From 446fecb96678d2c2c106e8c9e539cc5f7d9251ed Mon Sep 17 00:00:00 2001 From: Ralph Soika Date: Mon, 26 Aug 2019 21:45:09 +0200 Subject: [PATCH] refactoring Issue #554 --- .../engine/adminp/JobHandlerRenameUser.java | 6 +- .../workflow/engine/index/SchemaService.java | 180 ++++++++++++------ .../workflow/engine/index/SearchService.java | 29 +-- .../workflow/engine/index/UpdateService.java | 14 +- .../engine/lucene/LuceneIndexService.java | 90 +-------- .../engine/lucene/LuceneSearchService.java | 10 +- 6 files changed, 151 insertions(+), 178 deletions(-) diff --git a/imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/adminp/JobHandlerRenameUser.java b/imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/adminp/JobHandlerRenameUser.java index 464b45f13..b16e14ef6 100644 --- a/imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/adminp/JobHandlerRenameUser.java +++ b/imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/adminp/JobHandlerRenameUser.java @@ -10,7 +10,6 @@ import javax.annotation.Resource; import javax.annotation.security.DeclareRoles; import javax.annotation.security.RunAs; -import javax.ejb.EJB; import javax.ejb.LocalBean; import javax.ejb.SessionContext; import javax.ejb.Stateless; @@ -22,7 +21,6 @@ import org.imixs.workflow.WorkflowKernel; import org.imixs.workflow.engine.DocumentService; import org.imixs.workflow.engine.WorkflowService; -import org.imixs.workflow.engine.index.UpdateService; import org.imixs.workflow.engine.plugins.OwnerPlugin; import org.imixs.workflow.exceptions.AccessDeniedException; import org.imixs.workflow.exceptions.InvalidAccessException; @@ -74,9 +72,7 @@ public class JobHandlerRenameUser implements JobHandler { @Inject DocumentService documentService; - @Inject - UpdateService luceneService; - + private static final int DEFAULT_COUNT = 100; private static Logger logger = Logger.getLogger(JobHandlerRenameUser.class.getName()); diff --git a/imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/index/SchemaService.java b/imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/index/SchemaService.java index d3a359e08..f1f4d9963 100644 --- a/imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/index/SchemaService.java +++ b/imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/index/SchemaService.java @@ -39,44 +39,58 @@ import org.eclipse.microprofile.config.inject.ConfigProperty; import org.imixs.workflow.ItemCollection; +import org.imixs.workflow.engine.DocumentService; +import org.imixs.workflow.exceptions.QueryException; /** * The IndexSchemaService provides the index Schema. + *

+ * The schema is defined by the following properties: + * + *

+ * * * @version 1.0 * @author rsoika */ @Singleton -public class SchemaService { - - +public class SchemaService { + /* - * index.fields - * index.fields.analyse - * index.fields.noanalyse - * index.fields.store + * index.fields index.fields.analyse index.fields.noanalyse index.fields.store * - * index.operator - * index.splitwhitespace + * index.operator index.splitwhitespace * * */ + public static final String ANONYMOUS = "ANONYMOUS"; + @Inject - @ConfigProperty(name = "lucence.fulltextFieldList", defaultValue = "") - private String luceneFulltextFieldList; + @ConfigProperty(name = "index.fields", defaultValue = "") + private String indexFields; @Inject - @ConfigProperty(name = "lucence.indexFieldListAnalyze", defaultValue = "") - private String luceneIndexFieldListAnalyse; + @ConfigProperty(name = "index.fields.analyze", defaultValue = "") + private String indexFieldsAnalyse; @Inject - @ConfigProperty(name = "lucence.indexFieldListNoAnalyze", defaultValue = "") - private String luceneIndexFieldListNoAnalyse; + @ConfigProperty(name = "index.fields.noanalyze", defaultValue = "") + private String indexFieldsNoAnalyse; @Inject - @ConfigProperty(name = "lucence.indexFieldListStore", defaultValue = "") - private String luceneIndexFieldListStore; + @ConfigProperty(name = "index.fields.store", defaultValue = "") + private String indexFieldsStore; + + @Inject + private DocumentService documentService; private List fieldList = null; private List fieldListAnalyse = null; @@ -94,8 +108,6 @@ public class SchemaService { "$workflowsummary", "$workflowabstract", "$workflowgroup", "$workflowstatus", "$modified", "$created", "$lasteventdate", "$creator", "$editor", "$lasteditor", "$owner", "namowner"); - - private static Logger logger = Logger.getLogger(SchemaService.class.getName()); /** @@ -106,17 +118,17 @@ public class SchemaService { */ @PostConstruct void init() { - - logger.finest("......lucene FulltextFieldList=" + luceneFulltextFieldList); - logger.finest("......lucene IndexFieldListAnalyse=" + luceneIndexFieldListAnalyse); - logger.finest("......lucene IndexFieldListNoAnalyse=" + luceneIndexFieldListNoAnalyse); + + logger.finest("......lucene FulltextFieldList=" + indexFields); + logger.finest("......lucene IndexFieldListAnalyse=" + indexFieldsAnalyse); + logger.finest("......lucene IndexFieldListNoAnalyse=" + indexFieldsNoAnalyse); // compute search field list fieldList = new ArrayList(); // add all static default field list fieldList.addAll(DEFAULT_SEARCH_FIELD_LIST); - if (luceneFulltextFieldList != null && !luceneFulltextFieldList.isEmpty()) { - StringTokenizer st = new StringTokenizer(luceneFulltextFieldList, ","); + if (indexFields != null && !indexFields.isEmpty()) { + StringTokenizer st = new StringTokenizer(indexFields, ","); while (st.hasMoreElements()) { String sName = st.nextToken().toLowerCase().trim(); // do not add internal fields @@ -127,8 +139,8 @@ void init() { // compute Index field list (Analyze) fieldListAnalyse = new ArrayList(); - if (luceneIndexFieldListAnalyse != null && !luceneIndexFieldListAnalyse.isEmpty()) { - StringTokenizer st = new StringTokenizer(luceneIndexFieldListAnalyse, ","); + if (indexFieldsAnalyse != null && !indexFieldsAnalyse.isEmpty()) { + StringTokenizer st = new StringTokenizer(indexFieldsAnalyse, ","); while (st.hasMoreElements()) { String sName = st.nextToken().toLowerCase().trim(); // do not add internal fields @@ -141,9 +153,9 @@ void init() { fieldListNoAnalyse = new ArrayList(); // add all static default field list fieldListNoAnalyse.addAll(DEFAULT_NOANALYSE_FIELD_LIST); - if (luceneIndexFieldListNoAnalyse != null && !luceneIndexFieldListNoAnalyse.isEmpty()) { + if (indexFieldsNoAnalyse != null && !indexFieldsNoAnalyse.isEmpty()) { // add additional field list from imixs.properties - StringTokenizer st = new StringTokenizer(luceneIndexFieldListNoAnalyse, ","); + StringTokenizer st = new StringTokenizer(indexFieldsNoAnalyse, ","); while (st.hasMoreElements()) { String sName = st.nextToken().toLowerCase().trim(); if (!fieldListNoAnalyse.contains(sName)) @@ -155,9 +167,9 @@ void init() { fieldListStore = new ArrayList(); // add all static default field list fieldListStore.addAll(DEFAULT_STORE_FIELD_LIST); - if (luceneIndexFieldListStore != null && !luceneIndexFieldListStore.isEmpty()) { + if (indexFieldsStore != null && !indexFieldsStore.isEmpty()) { // add additional field list from imixs.properties - StringTokenizer st = new StringTokenizer(luceneIndexFieldListStore, ","); + StringTokenizer st = new StringTokenizer(indexFieldsStore, ","); while (st.hasMoreElements()) { String sName = st.nextToken().toLowerCase().trim(); if (!fieldListStore.contains(sName)) @@ -177,45 +189,23 @@ void init() { } } - - - - public List getFieldList() { return fieldList; } - - - - - - public List getFieldListAnalyse() { return fieldListAnalyse; } - - - - public List getFieldListNoAnalyse() { return fieldListNoAnalyse; } - - - - public List getFieldListStore() { return fieldListStore; } - - - - /** * Returns the Lucene schema configuration * @@ -234,4 +224,88 @@ public ItemCollection getConfiguration() { + /** + * Returns the extended search term for a given query. The search term will be + * extended with a users roles to test the read access level of each workitem + * matching the search term. + * + * @param sSearchTerm + * @return extended search term + * @throws QueryException + * in case the searchtem is not understandable. + */ + public String getExtendedSearchTerm(String sSearchTerm) throws QueryException { + // test if searchtem is provided + if (sSearchTerm == null || "".equals(sSearchTerm)) { + logger.warning("No search term provided!"); + return ""; + } + // extend the Search Term if user is not ACCESSLEVEL_MANAGERACCESS + if (!documentService.isUserInRole(DocumentService.ACCESSLEVEL_MANAGERACCESS)) { + // get user names list + List userNameList = documentService.getUserNameList(); + // create search term (always add ANONYMOUS) + String sAccessTerm = "($readaccess:" + ANONYMOUS; + for (String aRole : userNameList) { + if (!"".equals(aRole)) + sAccessTerm += " OR $readaccess:\"" + aRole + "\""; + } + sAccessTerm += ") AND "; + sSearchTerm = sAccessTerm + sSearchTerm; + } + logger.finest("......lucene final searchTerm=" + sSearchTerm); + + return sSearchTerm; + } + + + /** + * This helper method escapes wildcard tokens found in a lucene search term. The + * method can be used by clients to prepare a search phrase. + * + * The method rewrites the lucene QueryParser.escape method and did + * not! escape '*' char. + * + * Clients should use the method normalizeSearchTerm() instead of + * escapeSearchTerm() to prepare a user input for a lucene search. + * + * + * @see normalizeSearchTerm + * @param searchTerm + * @param ignoreBracket + * - if true brackes will not be escaped. + * @return escaped search term + */ + public String escapeSearchTerm(String searchTerm, boolean ignoreBracket) { + if (searchTerm == null || searchTerm.isEmpty()) { + return searchTerm; + } + + // this is the code from the QueryParser.escape() method without the '*' + // char! + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < searchTerm.length(); i++) { + char c = searchTerm.charAt(i); + // These characters are part of the query syntax and must be escaped + // (ignore brackets!) + if (c == '\\' || c == '+' || c == '-' || c == '!' || c == ':' || c == '^' || c == '[' || c == ']' + || c == '\"' || c == '{' || c == '}' || c == '~' || c == '?' || c == '|' || c == '&' || c == '/') { + sb.append('\\'); + } + + // escape bracket? + if (!ignoreBracket && (c == '(' || c == ')')) { + sb.append('\\'); + } + + sb.append(c); + } + return sb.toString(); + + } + + public String escapeSearchTerm(String searchTerm) { + return escapeSearchTerm(searchTerm, false); + } + } diff --git a/imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/index/SearchService.java b/imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/index/SearchService.java index ad747b32a..37ec48e07 100644 --- a/imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/index/SearchService.java +++ b/imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/index/SearchService.java @@ -35,19 +35,10 @@ import org.imixs.workflow.exceptions.QueryException; /** - * This session ejb provides a service to search the lucene index. The EJB uses - * the IndexSearcher to query the current index. As the index can change across - * multiple searches we can not share a single IndexSearcher instance. For that - * reason the EJB is creating a new IndexSearch per-search. + * This SearchService defines methods to search workitems or collections of + * workitems. * - * The service provides a set of public methods which can be used to query - * workitems or collections of workitems. A search term can be escaped by - * calling the method escpeSearchTerm. This method prepends a - * \ for those characters that QueryParser expects to be escaped. - * - * @see http://stackoverflow.com/questions/34880347/why-did-lucene-indexwriter- - * did-not-update-the-index-when-called-from-a-web-modul - * @version 2.0 + * @version 1.0 * @author rsoika */ @Local @@ -58,7 +49,6 @@ public interface SearchService { // number of hits public static final int DEFAULT_PAGE_SIZE = 100; // default docs in one page - /** * Returns a collection of documents matching the provided search term. The * provided search team will we extended with a users roles to test the read @@ -84,18 +74,19 @@ public interface SearchService { * @throws QueryException */ public List search(String sSearchTerm, int pageSize, int pageIndex) throws QueryException; - + /** * Returns a collection of documents matching the provided search term. The term * will be extended with the current users roles to test the read access level * of each workitem matching the search term. *

- * The method returns the full loaded documents. If you only want to search for document stubs use instead the method + * The method returns the full loaded documents. If you only want to search for + * document stubs use instead the method *

* search(String searchTerm, int pageSize, int pageIndex, Sort sortOrder, Operator defaultOperator, boolean loadStubs) -

- + *

+ * */ public List search(String sSearchTerm, int pageSize, int pageIndex, SortOrder sortOrder, DefaultOperator defaultOperator) throws QueryException; @@ -133,7 +124,6 @@ public List search(String sSearchTerm, int pageSize, int pageInd */ public List search(String searchTerm, int pageSize, int pageIndex, SortOrder sortOrder, DefaultOperator defaultOperator, boolean loadStubs) throws QueryException; - /** * Returns the total hits for a given search term from the lucene index. The @@ -153,5 +143,6 @@ public List search(String searchTerm, int pageSize, int pageInde * @throws QueryException * in case the searchterm is not understandable. */ - public int getTotalHits(final String _searchTerm, final int _maxResult, final DefaultOperator defaultOperator) throws QueryException; + public int getTotalHits(final String _searchTerm, final int _maxResult, final DefaultOperator defaultOperator) + throws QueryException; } diff --git a/imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/index/UpdateService.java b/imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/index/UpdateService.java index 7bd16115e..c5da2d7e2 100644 --- a/imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/index/UpdateService.java +++ b/imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/index/UpdateService.java @@ -38,21 +38,17 @@ import org.imixs.workflow.exceptions.PluginException; /** - * The IndexUpdateService provides methods to write Imixs Workitems into a - * search index. With the method addWorkitem() a ItemCollection can - * be added to a lucene search index. The service init method reads the property - * file 'imixs.properties' from the current classpath to determine the - * configuration. - * + * The UpdateService provides methods to write Imixs Workitems into a search + * index. An ItemCollection can be added into the index by calling themethod + * updateDocument() * + * @see SchemaService * @version 1.0 * @author rsoika */ @Local public interface UpdateService { - - // default field lists public static List DEFAULT_SEARCH_FIELD_LIST = Arrays.asList("$workflowsummary", "$workflowabstract"); public static List DEFAULT_NOANALYSE_FIELD_LIST = Arrays.asList("$modelversion", "$taskid", "$processid", @@ -64,8 +60,6 @@ public interface UpdateService { "$workflowsummary", "$workflowabstract", "$workflowgroup", "$workflowstatus", "$modified", "$created", "$lasteventdate", "$creator", "$editor", "$lasteditor", "$owner", "namowner"); - - /** * This method adds a single document into the to the Lucene index. Before the * document is added to the index, a new eventLog is created. The document will diff --git a/imixs-workflow-lucene/src/main/java/org/imixs/workflow/engine/lucene/LuceneIndexService.java b/imixs-workflow-lucene/src/main/java/org/imixs/workflow/engine/lucene/LuceneIndexService.java index 30680e765..60bf519ba 100644 --- a/imixs-workflow-lucene/src/main/java/org/imixs/workflow/engine/lucene/LuceneIndexService.java +++ b/imixs-workflow-lucene/src/main/java/org/imixs/workflow/engine/lucene/LuceneIndexService.java @@ -117,10 +117,6 @@ public class LuceneIndexService { @Inject private AdminPService adminPService; - - @Inject - private DocumentService documentService; - @Inject private EventLogService eventLogService; @@ -601,98 +597,18 @@ public String normalizeSearchTerm(String searchTerm) throws QueryException { // issue #331 parser.setAllowLeadingWildcard(true); try { - Query result = parser.parse(escapeSearchTerm(searchTerm, false)); + Query result = parser.parse(schemaService.escapeSearchTerm(searchTerm, false)); searchTerm = result.toString("content"); } catch (ParseException e) { logger.warning("Unable to normalze serchTerm '" + searchTerm + "' -> " + e.getMessage()); throw new QueryException(QueryException.QUERY_NOT_UNDERSTANDABLE, e.getMessage(), e); } - return escapeSearchTerm(searchTerm, true); + return schemaService.escapeSearchTerm(searchTerm, true); } - /** - * Returns the extended search term for a given query. The search term will be - * extended with a users roles to test the read access level of each workitem - * matching the search term. - * - * @param sSearchTerm - * @return extended search term - * @throws QueryException - * in case the searchtem is not understandable. - */ - public String getExtendedSearchTerm(String sSearchTerm) throws QueryException { - // test if searchtem is provided - if (sSearchTerm == null || "".equals(sSearchTerm)) { - logger.warning("No search term provided!"); - return ""; - } - // extend the Search Term if user is not ACCESSLEVEL_MANAGERACCESS - if (!documentService.isUserInRole(DocumentService.ACCESSLEVEL_MANAGERACCESS)) { - // get user names list - List userNameList = documentService.getUserNameList(); - // create search term (always add ANONYMOUS) - String sAccessTerm = "($readaccess:" + ANONYMOUS; - for (String aRole : userNameList) { - if (!"".equals(aRole)) - sAccessTerm += " OR $readaccess:\"" + aRole + "\""; - } - sAccessTerm += ") AND "; - sSearchTerm = sAccessTerm + sSearchTerm; - } - logger.finest("......lucene final searchTerm=" + sSearchTerm); - return sSearchTerm; - } - - /** - * This helper method escapes wildcard tokens found in a lucene search term. The - * method can be used by clients to prepare a search phrase. - * - * The method rewrites the lucene QueryParser.escape method and did - * not! escape '*' char. - * - * Clients should use the method normalizeSearchTerm() instead of - * escapeSearchTerm() to prepare a user input for a lucene search. - * - * - * @see normalizeSearchTerm - * @param searchTerm - * @param ignoreBracket - * - if true brackes will not be escaped. - * @return escaped search term - */ - public String escapeSearchTerm(String searchTerm, boolean ignoreBracket) { - if (searchTerm == null || searchTerm.isEmpty()) { - return searchTerm; - } - - // this is the code from the QueryParser.escape() method without the '*' - // char! - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < searchTerm.length(); i++) { - char c = searchTerm.charAt(i); - // These characters are part of the query syntax and must be escaped - // (ignore brackets!) - if (c == '\\' || c == '+' || c == '-' || c == '!' || c == ':' || c == '^' || c == '[' || c == ']' - || c == '\"' || c == '{' || c == '}' || c == '~' || c == '?' || c == '|' || c == '&' || c == '/') { - sb.append('\\'); - } - - // escape bracket? - if (!ignoreBracket && (c == '(' || c == ')')) { - sb.append('\\'); - } - - sb.append(c); - } - return sb.toString(); - - } - - public String escapeSearchTerm(String searchTerm) { - return escapeSearchTerm(searchTerm, false); - } + } diff --git a/imixs-workflow-lucene/src/main/java/org/imixs/workflow/engine/lucene/LuceneSearchService.java b/imixs-workflow-lucene/src/main/java/org/imixs/workflow/engine/lucene/LuceneSearchService.java index d2d6220bf..3b10fe933 100644 --- a/imixs-workflow-lucene/src/main/java/org/imixs/workflow/engine/lucene/LuceneSearchService.java +++ b/imixs-workflow-lucene/src/main/java/org/imixs/workflow/engine/lucene/LuceneSearchService.java @@ -64,6 +64,7 @@ import org.imixs.workflow.WorkflowKernel; import org.imixs.workflow.engine.DocumentService; import org.imixs.workflow.engine.index.DefaultOperator; +import org.imixs.workflow.engine.index.SchemaService; import org.imixs.workflow.engine.index.SearchService; import org.imixs.workflow.exceptions.InvalidAccessException; import org.imixs.workflow.exceptions.QueryException; @@ -108,13 +109,14 @@ public class LuceneSearchService implements SearchService { private boolean luceneSplitOnWhitespace; @Inject - //@EJB private LuceneIndexService luceneIndexService; - @Inject private DocumentService documentService; + @Inject + private SchemaService schemaService; + private static Logger logger = Logger.getLogger(LuceneSearchService.class.getName()); /** @@ -231,7 +233,7 @@ public List search(String searchTerm, int pageSize, int pageInde ArrayList workitems = new ArrayList(); - searchTerm = luceneIndexService.getExtendedSearchTerm(searchTerm); + searchTerm = schemaService.getExtendedSearchTerm(searchTerm); // test if searchtem is provided if (searchTerm == null || "".equals(searchTerm)) { return workitems; @@ -401,7 +403,7 @@ public int getTotalHits(final String _searchTerm, final int _maxResult, final De maxResult = DEFAULT_MAX_SEARCH_RESULT; } - String sSearchTerm =luceneIndexService.getExtendedSearchTerm(_searchTerm); + String sSearchTerm =schemaService.getExtendedSearchTerm(_searchTerm); // test if searchtem is provided if (sSearchTerm == null || "".equals(sSearchTerm)) { return 0;