Commit 924b3c77 authored by doc@bgerp.org's avatar doc@bgerp.org

p12246 Split ProcessAction.

parent 5faf6bf5
C: Large refactoring, extracting two action classes from too overloaded ProcessAction.
......@@ -297,14 +297,14 @@
<item action="ru.bgcrm.struts.action.ParameterAction:entityLog" title="Просмотр лога изменений"/>
</item>
<item title="Процесс">
<item action="ru.bgcrm.struts.action.ProcessAction:queue" title="Очереди процессов"/>
<item action="ru.bgcrm.struts.action.ProcessAction:queueGet" title="Получение свойств очереди процессов"/>
<item action="ru.bgcrm.struts.action.ProcessAction:queueShow" title="Просмотр очереди процессов"/>
<item action="ru.bgcrm.struts.action.ProcessAction:queueSavedFilterSet" title="Сохранённые наборы фильтров" allowAll="1"/>
<item action="ru.bgcrm.struts.action.ProcessAction:queueSavedPanelSet" title="Сохранённые наборы кнопок очередей процессов" allowAll="1"/>
<item action="ru.bgcrm.struts.action.ProcessAction:queue;ru.bgcrm.struts.action.ProcessQueueAction:queue" title="Очереди процессов"/>
<item action="ru.bgcrm.struts.action.ProcessAction:queueGet;ru.bgcrm.struts.action.ProcessQueueAction:queueGet" title="Получение свойств очереди процессов"/>
<item action="ru.bgcrm.struts.action.ProcessAction:queueShow;ru.bgcrm.struts.action.ProcessQueueAction:queueShow" title="Просмотр очереди процессов"/>
<item action="ru.bgcrm.struts.action.ProcessAction:queueSavedFilterSet;ru.bgcrm.struts.action.ProcessQueueAction:queueSavedFilterSet" title="Сохранённые наборы фильтров" allowAll="1"/>
<item action="ru.bgcrm.struts.action.ProcessAction:queueSavedPanelSet;ru.bgcrm.struts.action.ProcessQueueAction:queueSavedPanelSet" title="Сохранённые наборы кнопок очередей процессов" allowAll="1"/>
<item action="ru.bgcrm.struts.action.ProcessAction:null" title="Просмотр карточки процесса"/>
<item action="ru.bgcrm.struts.action.ProcessAction:process" title="Просмотр карточки процесса"/>
<item action="ru.bgcrm.struts.action.ProcessAction:typeTree" title="Просмотр дерева типов процессов">
<item action="ru.bgcrm.struts.action.ProcessAction:typeTree;ru.bgcrm.struts.action.ProcessQueueAction:typeTree" title="Просмотр дерева типов процессов">
<b>onlyPermittedTypes</b> - 1-только типы процессов в разрешенные группы которого входит текущий пользователь, 0-без ограничений
</item>
<item action="ru.bgcrm.struts.action.ProcessAction:processCreate" title="Создание процесса"/>
......@@ -323,13 +323,13 @@
</item>
<item action="ru.bgcrm.struts.action.ProcessAction:processDelete" title="Удаление процесса"/>
<item action="ru.bgcrm.struts.action.ProcessAction:process" title="Просмотр карточки процесса"/>
<item action="ru.bgcrm.struts.action.ProcessAction:linkedProcessList" title="Просмотр процессов с привязкой">
<item action="ru.bgcrm.struts.action.ProcessAction:linkedProcessList;ru.bgcrm.struts.action.ProcessLinkAction:linkedProcessList" title="Просмотр процессов с привязкой">
<b>onlyPermittedTypes</b> - 1-только процессы в разрешенные группы котороых входит текущий пользователь , 0-без ограничений
</item>
<item action="ru.bgcrm.struts.action.ProcessAction:linkedProcessInfo" title="Просмотр информации о привязанном процессе"/>
<item action="ru.bgcrm.struts.action.ProcessAction:linkedProcessCreate" title="Создание процесса с привязкой"/>
<item action="ru.bgcrm.struts.action.ProcessAction:linkProcessList" title="Просмотр привязанных процессов"/>
<item action="ru.bgcrm.struts.action.ProcessAction:linkProcessCreate" title="Создание привязанного процесса"/>
<!-- <item action="ru.bgcrm.struts.action.ProcessLinkAction:linkedProcessInfo" title="Просмотр информации о привязанном процессе"/> -->
<item action="ru.bgcrm.struts.action.ProcessAction:linkedProcessCreate;ru.bgcrm.struts.action.ProcessLinkAction:linkedProcessCreate" title="Создание процесса с привязкой"/>
<item action="ru.bgcrm.struts.action.ProcessAction:linkProcessList;ru.bgcrm.struts.action.ProcessLinkAction:linkProcessList" title="Просмотр привязанных процессов"/>
<item action="ru.bgcrm.struts.action.ProcessAction:linkProcessCreate;ru.bgcrm.struts.action.ProcessLinkAction:linkProcessCreate" title="Создание привязанного процесса"/>
<item action="ru.bgcrm.struts.action.ProcessAction:processCustomClassInvoke" title="Выполнение произвольного динамического класса для процесса"/>
<item action="ru.bgcrm.struts.action.ProcessAction:processRequest" title="Запрос дополнительных параметров создания процесса" allowAll="1"/>
<item action="ru.bgcrm.struts.action.ProcessAction:processTypeEdit" title="Редактор изменения типа процесса"/>
......
This diff is collapsed.
......@@ -17,7 +17,6 @@ import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Tomcat;
import org.apache.commons.lang3.StringUtils;
......
......@@ -3,13 +3,10 @@ package ru.bgcrm.event.listener;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import ru.bgcrm.cache.ProcessQueueCache;
import ru.bgcrm.event.EventProcessor;
import ru.bgcrm.event.GetPoolTasksEvent;
import ru.bgcrm.event.client.FilterCounterEvent;
import ru.bgcrm.model.BGException;
import ru.bgcrm.model.process.Queue;
import ru.bgcrm.model.process.queue.config.SavedFiltersConfig;
import ru.bgcrm.model.process.queue.config.SavedFiltersConfig.SavedFilterSet;
......@@ -18,16 +15,14 @@ import ru.bgcrm.util.Preferences;
import ru.bgcrm.util.Utils;
import ru.bgcrm.util.sql.ConnectionSet;
import ru.bgcrm.worker.FilterEntryCounter;
import ru.bgerp.util.Log;
public class ProcessFilterCounterListener {
private static final Logger log = Logger.getLogger(ProcessFilterCounterListener.class);
private static final Log log = Log.getLog();
public ProcessFilterCounterListener() {
EventProcessor.subscribe(new EventListener<GetPoolTasksEvent>() {
@Override
public void notify(GetPoolTasksEvent e, ConnectionSet connectionSet) throws BGException {
processListener(e.getForm(), connectionSet);
}
EventProcessor.subscribe((e, conSet) -> {
processListener(e.getForm(), conSet);
}, GetPoolTasksEvent.class);
}
......@@ -58,7 +53,7 @@ public class ProcessFilterCounterListener {
try {
count = FilterEntryCounter.getInstance().parseUrlAndGetCount(queue, url, form.getUser());
} catch (Exception e) {
log.error(e.getMessage(), e);
log.error(e);
}
HashMap<Integer, Integer> btnIdAndEntryCount = valuesToReturn.get(queueId);
......
......@@ -167,7 +167,7 @@ public class BaseAction extends DispatchAction {
}
if (invoker == null)
throw new NoSuchMethodException();
throw new NoSuchMethodException(name);
invokerMap.putIfAbsent(name, invoker);
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -8,151 +8,142 @@ import java.util.Calendar;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.log4j.Logger;
import ru.bgcrm.dao.process.ProcessDAO;
import ru.bgcrm.model.BGException;
import ru.bgcrm.model.process.Queue;
import ru.bgcrm.model.user.User;
import ru.bgcrm.struts.form.DynActionForm;
import ru.bgcrm.util.Setup;
import ru.bgcrm.util.sql.SQLUtils;
import ru.bgerp.util.Log;
/**
* Caching counter of quantity of DB records.
* For pooling them without too often SQL queries.
*/
public class FilterEntryCounter extends Thread {
private Logger log = Logger.getLogger(FilterEntryCounter.class);
private static final long TIMEOUT = 60 * 1000L;
private static FilterEntryCounter instance;
private FilterEntryCounter() {
start();
}
private static Map<String, CountAndTime> queries = new ConcurrentHashMap<>();
public static FilterEntryCounter getInstance() {
if (instance == null) {
synchronized (FilterEntryCounter.class) {
if (instance == null) {
instance = new FilterEntryCounter();
}
}
}
return instance;
}
private static class CountAndTime {
public volatile int count;
public volatile long time;
public CountAndTime(int count, long time) {
this.count = count;
this.time = time;
}
}
@Override
public void run() {
while (true) {
try {
removeOldQueries();
updateQueries();
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
try {
Thread.sleep(TIMEOUT);
} catch (Exception ex) {
}
}
}
}
private void updateQueries() {
Connection con = Setup.getSetup().getConnectionPool().getDBSlaveConnectionFromPool();
try {
for (String query : queries.keySet()) {
countQuery(con, query);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
SQLUtils.closeConnection(con);
}
}
private int countQuery(Connection con, String query) throws SQLException {
int result = 0;
PreparedStatement ps = con.prepareStatement(query);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
queries.put(query, new CountAndTime(result = rs.getInt(1), System.currentTimeMillis()));
}
ps.close();
return result;
}
/*private void addQuery( String query )
{
HashMap<String, Object> countAndDate = new HashMap<String, Object>();
countAndDate.put( "count", -1 );
countAndDate.put( "time", Calendar.getInstance().getTimeInMillis() );
queries.put( query, countAndDate );
}
*/
private void removeOldQueries() {
long interval = Setup.getSetup().getLong("filterEntryStorageInterval", TIMEOUT * 2);
Long currentTime = Calendar.getInstance().getTimeInMillis();
for (Map.Entry<String, CountAndTime> me : queries.entrySet()) {
String query = me.getKey();
CountAndTime value = me.getValue();
if ((currentTime - value.time) > interval) {
queries.remove(query);
}
}
}
private int getCount(String query) {
CountAndTime result = queries.get(query);
// "заявка" на подсчёт количества
if (result == null) {
queries.put(query, result = new CountAndTime(-1, System.currentTimeMillis()));
}
return result.count;
}
public int parseUrlAndGetCount(Queue queue, String url, User user) throws Exception {
DynActionForm filterForm = new DynActionForm(url);
filterForm.setUser(user);
String query = new ProcessDAO(null, user).getCountQuery(queue, filterForm);
return getCount(query);
}
public int parseUrlAndGetCountSync(Queue queue, String url, User user) throws BGException {
DynActionForm filterForm = new DynActionForm(url);
filterForm.setUser(user);
String query = new ProcessDAO(null).getCountQuery(queue, filterForm);
if (queries.containsKey(query)) {
return getCount(query);
} else {
int result = 0;
Connection con = Setup.getSetup().getConnectionPool().getDBSlaveConnectionFromPool();
try {
result = countQuery(con, query);
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
SQLUtils.closeConnection(con);
}
return result;
}
}
private Log log = Log.getLog();
private static final long TIMEOUT = 60 * 1000L;
private static FilterEntryCounter instance;
private FilterEntryCounter() {
start();
}
private static Map<String, CountAndTime> queries = new ConcurrentHashMap<>();
public static FilterEntryCounter getInstance() {
if (instance == null) {
synchronized (FilterEntryCounter.class) {
if (instance == null) {
instance = new FilterEntryCounter();
}
}
}
return instance;
}
private static class CountAndTime {
public volatile int count;
public volatile long time;
public CountAndTime(int count, long time) {
this.count = count;
this.time = time;
}
}
@Override
public void run() {
while (true) {
try {
updateQueries();
removeOldQueries();
} catch (Exception e) {
log.error(e);
} finally {
try {
Thread.sleep(TIMEOUT);
} catch (Exception ex) {}
}
}
}
private void updateQueries() {
try (var con = Setup.getSetup().getConnectionPool().getDBSlaveConnectionFromPool()) {
for (String query : queries.keySet()) {
countQuery(con, query);
}
} catch (Exception e) {
log.error(e);
}
}
private int countQuery(Connection con, String query) throws SQLException {
int result = 0;
PreparedStatement ps = con.prepareStatement(query);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
var cnt = new CountAndTime(result = rs.getInt(1), System.currentTimeMillis());
queries.put(query, cnt);
log.debug("Put query size after: %s, count: %s, query: %s", queries.size(), cnt.count, query);
}
ps.close();
return result;
}
private void removeOldQueries() {
long interval = Setup.getSetup().getLong("filterEntryStorageInterval", TIMEOUT * 2);
Long currentTime = Calendar.getInstance().getTimeInMillis();
for (Map.Entry<String, CountAndTime> me : queries.entrySet()) {
String query = me.getKey();
CountAndTime value = me.getValue();
if ((currentTime - value.time) > interval) {
queries.remove(query);
log.debug("Remove query, size after: %s, currentTime: %s, cnt.time: %s, query: %s",
queries.size(), currentTime, value.time, query);
}
}
}
private int getCount(String query) {
CountAndTime result = queries.get(query);
// "заявка" на подсчёт количества
if (result == null) {
queries.put(query, result = new CountAndTime(-1, System.currentTimeMillis()));
}
return result.count;
}
public int parseUrlAndGetCount(Queue queue, String url, User user) throws Exception {
DynActionForm filterForm = new DynActionForm(url);
filterForm.setUser(user);
String query = new ProcessDAO(null, user).getCountQuery(queue, filterForm);
return getCount(query);
}
public int parseUrlAndGetCountSync(Queue queue, String url, User user) throws BGException {
DynActionForm filterForm = new DynActionForm(url);
filterForm.setUser(user);
String query = new ProcessDAO(null).getCountQuery(queue, filterForm);
if (queries.containsKey(query)) {
return getCount(query);
} else {
int result = 0;
try (var con = Setup.getSetup().getConnectionPool().getDBSlaveConnectionFromPool()) {
result = countQuery(con, query);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return result;
}
}
}
\ No newline at end of file
package ru.bgcrm.worker;
/*package ru.bgcrm.worker;
import java.sql.Connection;
......@@ -39,4 +39,4 @@ public class InsertUnaccountedCustomers
{
new InsertUnaccountedCustomers().run();
}
}
}*/
\ No newline at end of file
......@@ -14,64 +14,64 @@ import ru.bgcrm.util.Utils;
import ru.bgerp.util.Log;
public class MessageExchange extends ConfigurableTask {
private static final AtomicBoolean run = new AtomicBoolean(false);
private static final AtomicBoolean run = new AtomicBoolean(false);
private static final Log log = Log.getLog();
private final Set<Integer> types;
// пустой конструктор для запуска извне без конфигурации
public MessageExchange() {
super(null);
types = Collections.emptySet();
}
private static final Log log = Log.getLog();
private final Set<Integer> types;
// пустой конструктор для запуска извне без конфигурации
public MessageExchange() {
super(null);
types = Collections.emptySet();
}
public MessageExchange(ParameterMap config) {
super(config);
types = Utils.toIntegerSet(config.get("messageTypeIds"));
}
private MessageExchange(Set<Integer> types) {
public MessageExchange(ParameterMap config) {
super(config);
types = Utils.toIntegerSet(config.get("messageTypeIds"));
}
private MessageExchange(Set<Integer> types) {
super(null);
this.types = types;
}
@Override
public void run() {
if (run.get()) {
log.info("Task already working..");
return;
}
long time = System.currentTimeMillis();
@Override
public void run() {
if (run.get()) {
log.info("Task already working..");
return;
}
long time = System.currentTimeMillis();
synchronized (run) {
run.set(true);
if (!types.isEmpty())
log.info("Message types: " + types);
synchronized (run) {
run.set(true);
if (!types.isEmpty())
log.info("Message types: " + types);
try {
MessageTypeConfig config = Setup.getSetup().getConfig(MessageTypeConfig.class);
for (MessageType type : config.getTypeMap().values()) {
if (!types.isEmpty() && !types.contains(type.getId()))
continue;
try {
type.process();
} catch (Exception e) {
log.error(e);
}
}
} finally {
run.set(false);
Scheduler.logExecutingTime( this, time );
}
}
}
public static void main(String[] args) {
try {
MessageTypeConfig config = Setup.getSetup().getConfig(MessageTypeConfig.class);
for (MessageType type : config.getTypeMap().values()) {
if (!types.isEmpty() && !types.contains(type.getId()))
continue;
try {
type.process();
} catch (Exception e) {
log.error(e);
}
}
} finally {
run.set(false);
Scheduler.logExecutingTime( this, time );
}
}
}
public static void main(String[] args) {
new MessageExchange(Utils.toIntegerSet(args[0])).run();
}
}
......@@ -13,61 +13,50 @@ import ru.bgcrm.dao.Tables;
import ru.bgcrm.util.Setup;
import ru.bgcrm.util.sql.SQLUtils;
public class NewsManager
implements Runnable
{
private static final Logger log = Logger.getLogger( NewsManager.class );
@Override
public void run()
{
Connection con = Setup.getSetup().getDBConnectionFromPool();
try
{
//Обновление новостей: пометка прочитанными
String query = " UPDATE " + Tables.TABLE_NEWS_USER + " u " +
" INNER JOIN " + Tables.TABLE_NEWS + " n ON u.news_id=n.id SET u.is_read=1 " +
" WHERE DATE_ADD(n.create_dt, INTERVAL n.read_time HOUR) < NOW() AND u.is_read=0 ";
PreparedStatement ps = con.prepareStatement( query );
ps.executeUpdate();
ps.close();
con.commit();
//Обновление новостей: удаление отживших свое
query = " DELETE FROM " + Tables.TABLE_NEWS + " WHERE DATE_ADD(create_dt, INTERVAL life_time DAY) < NOW() ";
ps = con.prepareStatement( query );
ps.executeUpdate();
ps.close();
con.commit();
//Обновление новостей: удаление связок новость-пользователь, где новость указывает на несуществующую
query = " DELETE u.* FROM " + Tables.TABLE_NEWS_USER + " u " +
" LEFT JOIN " + Tables.TABLE_NEWS + " n ON u.news_id=n.id " +
" WHERE n.id IS NULL ";
ps = con.prepareStatement( query );
ps.executeUpdate();
ps.close();
con.commit();
//Обновление новостей: удаление связок новость-пользователь, где пользователь указывает на несуществующего или удаленного
query = " DELETE nu.* FROM " + Tables.TABLE_NEWS_USER + " nu " +
" LEFT JOIN " + TABLE_USER + " u ON nu.user_id=u.id " +
" WHERE u.id IS NULL OR u.deleted=1 ";
ps = con.prepareStatement( query );
ps.executeUpdate();
ps.close();
con.commit();
}
catch( SQLException e )
{
log.error( e.getMessage(), e );
}
finally
{
UserNewsCache.flush( con );
SQLUtils.closeConnection( con );
}
}
public class NewsManager implements Runnable {
private static final Logger log = Logger.getLogger(NewsManager.class);
@Override
public void run() {
Connection con = Setup.getSetup().getDBConnectionFromPool();
try {
//Обновление новостей: пометка прочитанными
String query = " UPDATE " + Tables.TABLE_NEWS_USER + " u " + " INNER JOIN " + Tables.TABLE_NEWS + " n ON u.news_id=n.id SET u.is_read=1 "
+ " WHERE DATE_ADD(n.create_dt, INTERVAL n.read_time HOUR) < NOW() AND u.is_read=0 ";
PreparedStatement ps = con.prepareStatement(query);
ps.executeUpdate();
ps.close();
con.commit();
//Обновление новостей: удаление отживших свое
query = " DELETE FROM " + Tables.TABLE_NEWS + " WHERE DATE_ADD(create_dt, INTERVAL life_time DAY) < NOW() ";
ps = con.prepareStatement(query);
ps.executeUpdate();
ps.close();
con.commit();
//Обновление новостей: удаление связок новость-пользователь, где новость указывает на несуществующую
query = " DELETE u.* FROM " + Tables.TABLE_NEWS_USER + " u " + " LEFT JOIN " + Tables.TABLE_NEWS + " n ON u.news_id=n.id "
+ " WHERE n.id IS NULL ";
ps = con.prepareStatement(query);
ps.executeUpdate();
ps.close();
con.commit();
//Обновление новостей: удаление связок новость-пользователь, где пользователь указывает на несуществующего или удаленного
query = " DELETE nu.* FROM " + Tables.TABLE_NEWS_USER + " nu " + " LEFT JOIN " + TABLE_USER + " u ON nu.user_id=u.id "
+ " WHERE u.id IS NULL OR u.deleted=1 ";
ps = con.prepareStatement(query);
ps.executeUpdate();
ps.close();
con.commit();
} catch (SQLException e) {
log.error(e.getMessage(), e);
} finally {
UserNewsCache.flush(con);
SQLUtils.closeConnection(con);
}
}
}
package ru.bgcrm.worker;
/*package ru.bgcrm.worker;
import java.sql.Connection;
......@@ -34,4 +34,4 @@ public class SphinxCache
SQLUtils.closeConnection( con );
}
}
}
}*/
......@@ -758,7 +758,7 @@ link:../../src/ru/bgcrm/struts/action/MessageAction.java#L241-L253[ru.bgcrm.stru
Сохранение плюс восстановление сразу:
[snippet, from="//", to=");", remove-leading=" "]
link:../../src/ru/bgcrm/struts/action/ProcessAction.java#L1086-L1090[ru.bgcrm.struts.action.ProcessAction]
link:../../src/ru/bgcrm/struts/action/ProcessLinkAction.java#L57-L61[ru.bgcrm.struts.action.ProcessLinkAction]
=== Отображение на вкладке количества элементов
Например, количества связанных процессов. Сохраняется при первом вызове.
......@@ -766,7 +766,7 @@ link:../../src/ru/bgcrm/struts/action/ProcessAction.java#L1086-L1090[ru.bgcrm.st
Обновление значения:
[snippet, from="// п", to="}", remove-leading=" "]
link:../../src/ru/bgcrm/struts/action/ProcessAction.java#L1270-L1277[ru.bgcrm.struts.action.ProcessAction]
link:../../src/ru/bgcrm/struts/action/ProcessLinkAction.java#L242-L249[ru.bgcrm.struts.action.ProcessLinkAction]
Отображение в JSP:
[snippet, from="<c:if", to="if>", remove-leading=" "]
......@@ -830,7 +830,7 @@ link:../../webapps/WEB-INF/jspf/user/process/process/link_process_list.jsp#L56-L
Java action:
[snippet, from="//", to="id);", remove-leading=" "]
link:../../src/ru/bgcrm/struts/action/ProcessAction.java#L1261-L1263[ru.bgcrm.struts.action.ProcessAction]
link:../../src/ru/bgcrm/struts/action/ProcessLinkAction.java#L233-L235[ru.bgcrm.struts.action.ProcessLinkAction]
[[sample-jsp-ui]]
=== JSP UI
......
......@@ -31,7 +31,7 @@
$tabs.tabs("add", "${url}", "Параметры");
<c:url var="url" value="process.do">
<c:url var="url" value="/user/process/link.do">
<c:param name="action" value="linkedProcessList"/>
<c:param name="objectType" value="customer"/>
<c:param name="objectTitle" value="${customer.title}"/>
......
......@@ -34,7 +34,7 @@
<ui:menu-item title="Процессы" href="process/queue"
action="ru.bgcrm.struts.action.ProcessAction:queue"
command="/user/process.do?action=queue" />