diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/SystemTestCase.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/SystemTestCase.java index ea47fa54030d4e100aab2f1d7e7c0193723d0446..298b3e7c754879773a14093294293d4b38b795ef 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/SystemTestCase.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/SystemTestCase.java @@ -400,7 +400,6 @@ public abstract class SystemTestCase extends AssertJUnit protected void waitUntilIndexUpdaterIsIdle() { - UpdateUtils.waitUntilIndexUpdaterIsIdle(applicationContext, operationLog); } @SuppressWarnings("unchecked") diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/HibernateSearchDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/HibernateSearchDAO.java deleted file mode 100644 index e84de4016b25bae3c41d5c2cc05ff5c269c98cee..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/HibernateSearchDAO.java +++ /dev/null @@ -1,945 +0,0 @@ -/* - * Copyright 2008 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db; - -import java.io.StringReader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamConstants; -import javax.xml.stream.XMLStreamReader; - -import org.apache.commons.lang3.StringUtils; -import org.apache.log4j.Logger; -import org.apache.lucene.analysis.Analyzer; -import org.apache.lucene.document.Document; -import org.apache.lucene.index.DocValuesType; -import org.apache.lucene.index.FieldInfo; -import org.apache.lucene.index.FieldInfos; -import org.apache.lucene.index.IndexReader; -import org.apache.lucene.index.IndexableField; -import org.apache.lucene.index.LeafReader; -import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; -import org.apache.lucene.queryparser.classic.QueryParser; -import org.apache.lucene.search.BooleanClause.Occur; -import org.apache.lucene.search.BooleanQuery; -import org.apache.lucene.search.Query; -import org.apache.lucene.search.WildcardQuery; -import org.apache.lucene.search.highlight.Formatter; -import org.apache.lucene.search.highlight.Highlighter; -import org.apache.lucene.search.highlight.QueryScorer; -import org.apache.lucene.search.highlight.TokenGroup; -import org.apache.lucene.search.spans.SpanMultiTermQueryWrapper; -import org.apache.lucene.search.spans.SpanNearQuery; -import org.apache.lucene.search.spans.SpanQuery; -import org.hibernate.HibernateException; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.search.FullTextQuery; -import org.hibernate.search.FullTextSession; -import org.hibernate.search.Search; -import org.hibernate.search.SearchFactory; -import org.hibernate.search.engine.ProjectionConstants; -import org.hibernate.search.indexes.spi.DirectoryBasedIndexManager; -import org.hibernate.search.indexes.spi.ReaderProvider; -import org.hibernate.search.spi.SearchIntegrator; -import org.hibernate.transform.BasicTransformerAdapter; -import org.hibernate.transform.ResultTransformer; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.support.JdbcAccessor; -import org.springframework.orm.hibernate5.HibernateCallback; -import org.springframework.orm.hibernate5.support.HibernateDaoSupport; - -import ch.systemsx.cisd.common.collection.CollectionUtils; -import ch.systemsx.cisd.common.collection.CollectionUtils.ICollectionFilter; -import ch.systemsx.cisd.common.exceptions.UserFailureException; -import ch.systemsx.cisd.common.logging.LogCategory; -import ch.systemsx.cisd.common.logging.LogFactory; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.IHibernateSearchDAO; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.HibernateSearchContext; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.LuceneQueryBuilder; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.detailed.DetailedQueryBuilder; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BasicEntityType; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriteria; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriterion; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchField; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchFieldKind; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchSubCriteria; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IAssociationCriteria; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MatchingEntity; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Person; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyMatch; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Space; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Span; -import ch.systemsx.cisd.openbis.generic.shared.dto.AbstractIdAndCodeHolder; -import ch.systemsx.cisd.openbis.generic.shared.dto.SearchableEntity; -import ch.systemsx.cisd.openbis.generic.shared.dto.hibernate.SearchFieldConstants; -import ch.systemsx.cisd.openbis.generic.shared.dto.properties.EntityKind; -import ch.systemsx.cisd.openbis.generic.shared.translator.DtoConverters; - -/** - * Implementation of {@link IHibernateSearchDAO} for databases. - * - * @author Christian Ribeaud - */ - -final class HibernateSearchDAO extends HibernateDaoSupport implements IHibernateSearchDAO -{ - private static final Pattern VALID_CODE_PATTERN = Pattern.compile("^[^\\s/&]+$", Pattern.CASE_INSENSITIVE); - - /** - * The <code>Logger</code> of this class. - * <p> - * This logger does not output any SQL statement. If you want to do so, you had better set an appropriate debugging level for class - * {@link JdbcAccessor}. - * </p> - */ - private final static Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, - HibernateSearchDAO.class); - - private final HibernateSearchContext hibernateSearchContext; - - private Map<String, DocValuesType> fieldTypesCache; - - private final XMLInputFactory xif = XMLInputFactory.newFactory(); - - private Properties serviceProperties; - - HibernateSearchDAO(final SessionFactory sessionFactory, - HibernateSearchContext hibernateSearchContext) - { - assert sessionFactory != null : "Unspecified session factory"; - this.hibernateSearchContext = hibernateSearchContext; - setSessionFactory(sessionFactory); - } - - private boolean containsKeys(Map<String, DocValuesType> map, List<String> keys) - { - for (String key : keys) - { - if (map == null || map.containsKey(key) == false) - { - return false; - } - } - return true; - } - - private Map<String, DocValuesType> getFieldTypes(List<String> fields) - { - // Initialize field types - if (fieldTypesCache == null || containsKeys(fieldTypesCache, fields) == false) - { - synchronized (this) - { - fieldTypesCache = Collections.synchronizedMap(new HashMap<String, DocValuesType>()); - for (SearchableEntity searchableEntity : SearchableEntity.values()) - { - MyIndexReaderProvider indexProvider = null; - try - { - final FullTextSession fullTextSession = Search.getFullTextSession(this.currentSession()); - indexProvider = new MyIndexReaderProvider(fullTextSession, searchableEntity); - IndexReader indexReader = indexProvider.getReader(); - for (LeafReaderContext rc : indexReader.leaves()) - { - LeafReader ar = rc.reader(); - FieldInfos fis = ar.getFieldInfos(); - for (Iterator<FieldInfo> iter = fis.iterator(); iter.hasNext();) - { - FieldInfo fi = iter.next(); - fieldTypesCache.put(fi.name, fi.getDocValuesType()); - } - } - } finally - { - indexProvider.close(); - } - } - } - } - return fieldTypesCache; - } - - // - // IHibernateSearchDAO - // - - @Override - public int getResultSetSizeLimit() - { - return hibernateSearchContext.getMaxResults(); - } - - // simple search for MatchingEntities - - @Override - public List<MatchingEntity> searchEntitiesByTerm(final String userId, - final SearchableEntity searchableEntity, final String searchTerm, - final HibernateSearchDataProvider dataProvider, final boolean useWildcardSearchMode, - final int alreadyFoundEntities, final int maxSize) throws DataAccessException - { - assert searchableEntity != null : "Unspecified searchable entity"; - assert StringUtils.isBlank(searchTerm) == false : "Unspecified search term."; - assert dataProvider != null : "Unspecified data provider"; - - @SuppressWarnings({ "unchecked", "rawtypes" }) - final List<MatchingEntity> list = - AbstractDAO.cast((List<?>) getHibernateTemplate().executeWithNativeSession(new HibernateCallback() - { - @Override - public final List<MatchingEntity> doInHibernate(final Session session) - throws HibernateException - { - return doSearchEntitiesByTerm(userId, session, searchableEntity, - searchTerm, dataProvider, useWildcardSearchMode, - alreadyFoundEntities, maxSize); - } - })); - if (operationLog.isDebugEnabled()) - { - operationLog.debug(String.format( - "%d matching entities of type '%s' have been found for search term '%s'.", - list.size(), searchableEntity.getMatchingEntityClass(), searchTerm)); - } - return list; - } - - private final List<MatchingEntity> doSearchEntitiesByTerm(final String userId, - final Session session, final SearchableEntity searchableEntity, final String userQuery, - final HibernateSearchDataProvider dataProvider, final boolean useWildcardSearchMode, - int alreadyFoundEntities, int maxSize) throws DataAccessException, UserFailureException - { - final FullTextSession fullTextSession = Search.getFullTextSession(session); - Analyzer analyzer = LuceneQueryBuilder.createSearchAnalyzer(); - - MyIndexReaderProvider indexProvider = - new MyIndexReaderProvider(fullTextSession, searchableEntity); - - try - { - List<MatchingEntity> result = searchTermInField(userId, fullTextSession, "global_search", userQuery, - searchableEntity, analyzer, indexProvider.getReader(), - dataProvider, useWildcardSearchMode, alreadyFoundEntities, - maxSize); - return result; - } finally - { - indexProvider.close(); - } - } - - private static List<String> subqueries(String input) - { - List<String> result = new ArrayList<>(); - String q = input.trim(); - if (q.length() == 0) - { - return result; - } - - Pattern pattern; - if (q.startsWith("\"")) - { - pattern = Pattern.compile("^\"(.*?)\"[$|\\s](.*$)"); - } else - { - pattern = Pattern.compile("^(.*?)\\s(.*)$"); - } - - Matcher matcher = pattern.matcher(q); - if (matcher.find()) - { - result.add(matcher.group(1)); - result.addAll(subqueries(matcher.group(2))); - } else - { - if (q.startsWith("\"") && q.endsWith("\"") && q.length() > 1) - { - q = q.substring(1, q.length() - 1); - } - result.add(q); - } - - return result; - } - - private final List<MatchingEntity> searchTermInField(final String userId, - final FullTextSession fullTextSession, final String fieldName, final String userQuery, - final SearchableEntity searchableEntity, Analyzer analyzer, IndexReader indexReader, - final HibernateSearchDataProvider dataProvider, final boolean useWildcardSearchMode, - int alreadyFoundResults, int maxSize) throws DataAccessException, UserFailureException - { - int maxResults = - Math.max(0, Math.min(maxSize, hibernateSearchContext.getMaxResults()) - - alreadyFoundResults); - if (maxResults == 0) - { - return new ArrayList<MatchingEntity>(); - } - - Query query = null; - - if (useWildcardSearchMode) - { - - List<String> subqueries = subqueries(userQuery.toLowerCase()); - - BooleanQuery.Builder bq = new BooleanQuery.Builder(); - - for (String q : subqueries) - { - String subquery = QueryParser.escape(q); - subquery = subquery.replace("\\*", "*"); - subquery = subquery.replace("\\?", "?"); - - String[] parts = subquery.split("\\s+"); - - SpanQuery[] queryParts = new SpanQuery[parts.length]; - String term = ""; - for (int i = 0; i < parts.length; i++) - { - term = parts[i]; - queryParts[i] = new SpanMultiTermQueryWrapper<WildcardQuery>( - new WildcardQuery(new Term("global_search", term))); - } - - if (queryParts.length == 1) - { - bq.add(queryParts[0], Occur.SHOULD); - } else - { - bq.add(new SpanNearQuery(queryParts, 0, true), Occur.SHOULD); - } - - if (parts.length == 1) - { - bq.add(new WildcardQuery(new Term("global_search_metaprojects", "/" + userId + "/" + parts[0])), - Occur.SHOULD); - } - } - query = bq.build(); - - } else - { - List<String> subqueries = subqueries(userQuery.toLowerCase()); - - BooleanQuery.Builder bq = new BooleanQuery.Builder(); - - for (String subquery : subqueries) - { - String[] parts = subquery.split("\\s+"); - - SpanQuery[] queryParts = new SpanQuery[parts.length]; - String term = ""; - for (int i = 0; i < parts.length; i++) - { - term = QueryParser.escape(parts[i]); - if (i == 0) - { - term = "*" + term; - } - if (i == parts.length - 1) - { - term = term + "*"; - } - queryParts[i] = new SpanMultiTermQueryWrapper<WildcardQuery>( - new WildcardQuery(new Term("global_search", term))); - } - - if (queryParts.length == 1) - { - bq.add(queryParts[0], Occur.SHOULD); - } else - { - bq.add(new SpanNearQuery(queryParts, 0, true), Occur.SHOULD); - } - bq.add(new WildcardQuery(new Term("global_search_metaprojects", "/" + userId + "/*" + QueryParser.escape(parts[0]) + "*")), - Occur.SHOULD); - - } - query = bq.build(); - } - - final FullTextQuery hibernateQuery = - fullTextSession.createFullTextQuery(query, - searchableEntity.getMatchingEntityClass()); - - // takes data only from Lucene index without hitting DB - hibernateQuery.setProjection(ProjectionConstants.DOCUMENT_ID, ProjectionConstants.DOCUMENT); - hibernateQuery.setReadOnly(true); - hibernateQuery.setFirstResult(0); - hibernateQuery.setMaxResults(maxResults); - - setTimeout(hibernateQuery); - - hibernateQuery.setResultTransformer(new ResultTransformer() - { - private static final long serialVersionUID = 1L; - - @Override - public Object transformTuple(Object[] tuple, String[] aliases) - { - // This is a hack. The real problem is that after upgrading to Hibernate Search 5.8.2 - // the result transformer is called at least two times for each entry. When the second call - // happens, the tuple already contains the transformed data. So we just return it. - if (tuple.length < 2) - { - return tuple[0]; - } - - IndexableField dataField = ((Document) tuple[1]).getField("global_search"); - IndexableField headerField = ((Document) tuple[1]).getField("global_search_fields"); - IndexableField metaprojectField = ((Document) tuple[1]).getField("global_search_metaprojects"); - - String splitString = "\\ \\|\\|\\|\\ "; - - String[] fields = headerField.stringValue().split(splitString); - String[] content = dataField.stringValue().split(splitString); - String[] metaprojects = new String[0]; - - String mpfs = metaprojectField.stringValue(); - if (mpfs.trim().length() > 0) - { - metaprojects = metaprojectField.stringValue().split(" "); - } - - List<String> query = subqueries(userQuery.toLowerCase()); - - Map<String, PropertyMatch> matchingFields = new HashMap<>(); - double score = 0.0; - - for (int i = 0; i < content.length; i++) - { - String field = fields[i]; - String data = content[i]; - List<Span> spans = new ArrayList<Span>(); - - double scoreNow = score; - for (String q : query) - { - if (useWildcardSearchMode) - { - Pattern pattern = Pattern.compile("(?s)(^|\\s)(" + q.replace("*", "[^\\s]*").replace("?", "[^\\s]?") + ")($|\\s)"); - - String cont = stripXml(content[i].toLowerCase()); - Matcher matcher = pattern.matcher(cont); - while (matcher.find()) - { - int start = matcher.start(); - int end = matcher.end(); - score += getScore(cont, start, end, fields[i], useWildcardSearchMode); - } - - cont = content[i].toLowerCase(); - matcher = pattern.matcher(cont); - while (matcher.find()) - { - Span span = new Span(); - span.setStart(matcher.start(2)); - span.setEnd(matcher.end(2)); - spans.add(span); - } - } else - { - String rest = stripXml(content[i].toLowerCase()); - while (rest.length() > 0) - { - int start = rest.indexOf(q); - if (start == -1) - { - rest = ""; - } else - { - int end = start + q.length(); - rest = rest.substring(end); - score += getScore(content[i].toLowerCase(), start, end, fields[i], useWildcardSearchMode); - } - } - - rest = content[i].toLowerCase(); - int idx = 0; - while (rest.length() > 0) - { - int start = rest.indexOf(q); - if (start == -1) - { - rest = ""; - } else - { - int end = start + q.length(); - rest = rest.substring(end); - Span span = new Span(); - span.setStart(start + idx); - span.setEnd(end + idx); - idx = idx + end; - spans.add(span); - } - } - } - } - - if (score > scoreNow) - { - PropertyMatch match = new PropertyMatch(); - match.setCode(field); - match.setValue(data); - match.setSpans(spans); - matchingFields.put(field, match); - } - } - - Set<String> matchingMetaprojects = new HashSet<>(); - for (int i = 0; i < metaprojects.length; i++) - { - String mp = metaprojects[i].substring(1); - String user = mp.substring(0, mp.indexOf("/")); - if (!user.equals(userId)) - { - continue; - } - - String value = metaprojects[i].substring(metaprojects[i].lastIndexOf("/") + 1); - for (String q : query) - { - if (useWildcardSearchMode) - { - Pattern pattern = Pattern.compile(q.toLowerCase().replace("*", ".*").replace("?", ".?")); - Matcher matcher = pattern.matcher(value.toLowerCase()); - - while (matcher.find()) - { - matchingMetaprojects.add(value); - int start = matcher.start(); - int end = matcher.end(); - score += getScore(value, start, end, "Tag", useWildcardSearchMode) * 5; - } - } else - { - String rest = value.toLowerCase(); - while (rest.length() > 0) - { - int start = rest.indexOf(q.toLowerCase()); - if (start == -1) - { - rest = ""; - } else - { - matchingMetaprojects.add(value); - int end = start + q.length(); - rest = rest.substring(end); - score += getScore(value, start, end, "Tag", useWildcardSearchMode) * 5; - } - } - } - } - } - - if (matchingMetaprojects.size() > 0) - { - List<String> mps = new ArrayList<>(matchingMetaprojects); - Collections.sort(mps); - - PropertyMatch match = new PropertyMatch(); - match.setCode("Tags"); - match.setValue(StringUtils.join(mps, ", ")); - match.setSpans(new ArrayList<Span>()); - matchingFields.put("Tags", match); - } - - if (matchingFields.containsKey("Code") || - matchingFields.containsKey("Project code") || - matchingFields.containsKey("Space code")) - { - matchingFields.remove("Identifier"); - } - - return createMatchingEntity((Document) tuple[1], new ArrayList<>(matchingFields.values()), score); - } - - private String stripXml(String cont) - { - if (cont.startsWith("<") && cont.endsWith(">")) - { - - StringBuffer value = new StringBuffer(); - try - { - XMLStreamReader xsr = xif.createXMLStreamReader(new StringReader(cont)); - while (xsr.hasNext()) - { - int x = xsr.next(); - if (x == XMLStreamConstants.CHARACTERS) - { - value.append(xsr.getText() + " "); - } - } - } catch (Exception e) - { - value = new StringBuffer(cont); - } - return value.toString(); - } else - { - return cont; - } - } - - private double getScore(String text, int start, int end, String field, boolean wildcard) - { - boolean fullmatch = (start == 0 || !StringUtils.isAlphanumeric(text.substring(start - 1, start))) && - (end == text.length() || !StringUtils.isAlphanumeric(text.substring(end, end + 1))) && - !wildcard; // full/partial matching not relevant for wildcard mode - if (field.equals("Perm ID") || field.equals("Code")) - { - if (fullmatch) - { - return 200; - } else - { - return 100; - } - } else if (fullmatch) - { - return 10; - } else - { - return 1; - } - } - - @Override - public List transformList(List collection) - { - List result = new ArrayList(); - for (Object o : collection) - { - result.add(transformTuple(new Object[] { o }, new String[0])); - } - return result; - } - - private MatchingEntity createMatchingEntity(final Document doc, final List<PropertyMatch> matches, double score) - { - final MatchingEntity result = new MatchingEntity(); - - // search properties - result.setMatches(matches); - result.setScore(score); - - // IIdentifiable properties - // NOTE: for contained sample this code is full code with container code part - result.setCode(getFieldValue(doc, SearchFieldConstants.CODE)); - result.setId(Long.parseLong(getFieldValue(doc, SearchFieldConstants.ID))); - result.setIdentifier(getFieldValue(doc, SearchFieldConstants.IDENTIFIER)); - result.setPermId(tryGetFieldValue(doc, SearchFieldConstants.PERM_ID)); - - // entity kind - result.setEntityKind(DtoConverters.convertEntityKind(searchableEntity.getEntityKind())); - - // entity type - BasicEntityType entityType = new BasicEntityType(); - entityType.setCode(getFieldValue(doc, SearchFieldConstants.PREFIX_ENTITY_TYPE - + SearchFieldConstants.CODE)); - result.setEntityType(entityType); - - // group - Map<String, Space> spacesById = dataProvider.getGroupsById(); - IndexableField spaceFieldOrNull = doc.getField(getSpaceIdFieldName()); - if (spaceFieldOrNull != null) - { - Space space = spacesById.get(spaceFieldOrNull.stringValue()); - result.setSpace(space); - } - - // registrator - final String registratorIdOrNull = - tryGetFieldValue(doc, SearchFieldConstants.PREFIX_REGISTRATOR - + SearchFieldConstants.PERSON_USER_ID); - final String firstNameOrNull = - tryGetFieldValue(doc, SearchFieldConstants.PREFIX_REGISTRATOR - + SearchFieldConstants.PERSON_FIRST_NAME); - if (registratorIdOrNull != null || firstNameOrNull != null) - { - Person registrator = new Person(); - registrator.setUserId(registratorIdOrNull); - registrator.setFirstName(firstNameOrNull); - registrator.setLastName(tryGetFieldValue(doc, - SearchFieldConstants.PREFIX_REGISTRATOR - + SearchFieldConstants.PERSON_LAST_NAME)); - registrator.setEmail(tryGetFieldValue(doc, SearchFieldConstants.PREFIX_REGISTRATOR - + SearchFieldConstants.PERSON_EMAIL)); - result.setRegistrator(registrator); - } - - return result; - } - - private String getFieldValue(final Document document, final String searchFieldName) - { - return document.getField(searchFieldName).stringValue(); - } - - private String tryGetFieldValue(final Document document, final String searchFieldName) - { - IndexableField fieldOrNull = document.getField(searchFieldName); - return fieldOrNull == null ? null : fieldOrNull.stringValue(); - } - - private String getSpaceIdFieldName() - { - String groupId = SearchFieldConstants.PREFIX_SPACE + SearchFieldConstants.ID; - if (searchableEntity.equals(SearchableEntity.EXPERIMENT)) - { - return SearchFieldConstants.PREFIX_PROJECT + groupId; - } else - { - return groupId; - } - } - - }); - - List<?> list = hibernateQuery.list(); - List<MatchingEntity> result = AbstractDAO.cast(list); - return CollectionUtils.filter(result, new ICollectionFilter<MatchingEntity>() - { - @Override - public boolean isPresent(MatchingEntity element) - { - return element != null && element.getScore() > 0.0; - } - }); - - } - - private void setTimeout(FullTextQuery hibernateQuery) - { - int timeout = -1; - try - { - timeout = Integer.parseInt(serviceProperties.get("fulltext-timeout").toString()); - } catch (Exception e) - { - } - if (timeout > 0) - { - hibernateQuery.setTimeout(timeout, TimeUnit.SECONDS); - } - } - - // detailed search - - @Override - public List<Long> searchForEntityIds(final String userId, - final DetailedSearchCriteria criteria, final EntityKind entityKind, - final List<IAssociationCriteria> associations) - { - @SuppressWarnings({ "unchecked", "rawtypes" }) - final List<Long> list = - AbstractDAO.cast((List<?>) getHibernateTemplate().executeWithNativeSession(new HibernateCallback() - { - @Override - public final Object doInHibernate(final Session session) - throws HibernateException - { - return searchForEntityIds(userId, session, criteria, entityKind, - associations); - } - })); - if (operationLog.isDebugEnabled()) - { - operationLog.debug(String.format( - "%d matching samples have been found for search criteria '%s'.", list.size(), - criteria.toString())); - } - return list; - } - - /** - * Returns a list ids of entities of given kind that match given criteria.<br> - * <br> - * Takes data only from Lucene index without hitting DB. - */ - private List<Long> searchForEntityIds(String userId, Session session, - DetailedSearchCriteria searchCriteria, EntityKind entityKind, - List<IAssociationCriteria> associations) - { - if (hasInvalidCodes(searchCriteria)) - { - return Collections.emptyList(); - } - List<String> fieldNames = DetailedQueryBuilder.getIndexFieldNames(searchCriteria.getCriteria(), DtoConverters.convertEntityKind(entityKind)); - - Query query = LuceneQueryBuilder.createDetailedSearchQuery(userId, searchCriteria, associations, entityKind, getFieldTypes(fieldNames)); - final FullTextSession fullTextSession = Search.getFullTextSession(session); - final FullTextQuery hibernateQuery = - fullTextSession.createFullTextQuery(query, entityKind.getEntityClass()); - - hibernateQuery.setProjection(ProjectionConstants.ID); - hibernateQuery.setReadOnly(true); - hibernateQuery.setResultTransformer(new PassThroughOneObjectTupleResultTransformer()); - - setTimeout(hibernateQuery); - - List<Long> entityIds = AbstractDAO.cast(hibernateQuery.list()); - entityIds = filterNulls(entityIds); - return entityIds; - } - - private boolean hasInvalidCodes(DetailedSearchCriteria searchCriteria) - { - if (searchCriteria != null) - { - for (DetailedSearchCriterion criterion : searchCriteria.getCriteria()) - { - String value = criterion.getValue(); - DetailedSearchField field = criterion.getField(); - DetailedSearchFieldKind kind = field.getKind(); - if (DetailedSearchFieldKind.ATTRIBUTE.equals(kind) && field.getAttributeCode().equals("CODE") - && VALID_CODE_PATTERN.matcher(value).matches() == false) - { - return true; - } - } - for (DetailedSearchSubCriteria subCriteria : searchCriteria.getSubCriterias()) - { - if (hasInvalidCodes(subCriteria.getCriteria())) - { - return true; - } - } - } - return false; - } - - // - // Helpers - // - - private static class PassThroughOneObjectTupleResultTransformer extends BasicTransformerAdapter - { - private static final long serialVersionUID = 1L; - - @Override - public Object transformTuple(Object[] tuple, String[] aliases) - { - assert tuple.length == 1 : "tuple should consist of exactly one object"; - return tuple[0]; - } - - } - - private static <T> List<T> filterNulls(List<T> list) - { - List<T> result = new ArrayList<T>(); - for (T elem : list) - { - if (elem != null) - { - result.add(elem); - } - } - return result; - } - - private static void logSearchHighlightingError(Exception ex) - { - operationLog.error("error during search result highlighting: " + ex.getMessage()); - } - - private static final class MyHighlighter - { - - private final Highlighter highlighter; - - public MyHighlighter(Query query, IndexReader indexReader, Analyzer analyzer) - { - this.highlighter = createHighlighter(query); - } - - private static Highlighter createHighlighter(Query query) - { - Formatter htmlFormatter = createFormatter(); - return new Highlighter(htmlFormatter, new QueryScorer(query)); - } - - private static Formatter createFormatter() - { - // NOTE: we do not use SimpleHTMLFormatter because we want to escape html in the search - // results. - return new Formatter() - { - @Override - public String highlightTerm(String text, TokenGroup tokenGroup) - { - return text; // no highlight at all - } - }; - } - - } - - private static final class MyIndexReaderProvider - { - private final ReaderProvider readerProvider; - - private final IndexReader indexReader; - - /** opens the index reader. Closing the index after usage must be done with #close() method. */ - public MyIndexReaderProvider(final FullTextSession fullTextSession, - final SearchableEntity searchableEntity) - { - SearchFactory searchFactory = fullTextSession.getSearchFactory(); - - SearchIntegrator searchIntegrator = searchFactory.unwrap(SearchIntegrator.class); - DirectoryBasedIndexManager indexManager = - (DirectoryBasedIndexManager) searchIntegrator.getIndexManager(searchableEntity.getMatchingEntityClass().getSimpleName()); - this.readerProvider = indexManager.getReaderProvider(); - this.indexReader = readerProvider.openIndexReader(); - } - - public IndexReader getReader() - { - return indexReader; - } - - /** must be called to close the index reader when it is not needed anymore */ - public void close() - { - readerProvider.closeIndexReader(indexReader); - } - } - - @Override - public void setProperties(Properties serviceProperties) - { - this.serviceProperties = serviceProperties; - } -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/IndexCreationUtil.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/IndexCreationUtil.java index 84fc81397935bf80f6888a85fe6ecfdde0fff9a3..e7435d2ca7de48075e9ce01badd3ad363a9347d9 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/IndexCreationUtil.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/IndexCreationUtil.java @@ -21,10 +21,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.apache.commons.lang3.time.StopWatch; import org.apache.log4j.Logger; -import org.hibernate.SessionFactory; -import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; @@ -35,11 +32,6 @@ import ch.systemsx.cisd.common.logging.LogInitializer; import ch.systemsx.cisd.common.process.ProcessExecutionHelper; import ch.systemsx.cisd.common.string.Template; import ch.systemsx.cisd.dbmigration.postgresql.DumpPreparator; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.FullTextIndexerRunnable; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.HibernateSearchContext; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IFullTextIndexUpdater; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IndexMode; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IndexUpdateOperation; /** * Utility methods around database indexing with <i>Hibernate</i>. @@ -59,7 +51,6 @@ public final class IndexCreationUtil private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, IndexCreationUtil.class); - private static HibernateSearchContext hibernateSearchContext; private static AbstractApplicationContext applicationContext; @@ -79,56 +70,6 @@ public final class IndexCreationUtil return applicationContext; } - /** - * Performs a full text index because the test database has been migrated. - */ - private final static void createAndRunFullTextIndexer() throws Exception - { - final BeanFactory factory = getApplicationContext(); - final IFullTextIndexUpdater updater = createDummyUpdater(); - final FullTextIndexerRunnable fullTextIndexer = - new FullTextIndexerRunnable( - (SessionFactory) factory.getBean("hibernate-session-factory"), - hibernateSearchContext, updater); - fullTextIndexer.run(); - } - - /** - * Creates a dummy {@link IFullTextIndexUpdater} that does nothing. - */ - private final static IFullTextIndexUpdater createDummyUpdater() - { - return new IFullTextIndexUpdater() - { - - @Override - public void clear() - { - } - - @Override - public void start() - { - } - - @Override - public void scheduleUpdate(IndexUpdateOperation entities) - { - } - }; - } - - /** - * Creates a freshly new {@link HibernateSearchContext} overriding the one loaded by <i>Spring</i>. - */ - private final static HibernateSearchContext createHibernateSearchContext(String indexFolder) - { - final HibernateSearchContext context = new HibernateSearchContext(); - context.setIndexBase(indexFolder); - context.setIndexMode(IndexMode.INDEX_FROM_SCRATCH); - return context; - } - // // Main method // @@ -144,8 +85,6 @@ public final class IndexCreationUtil dumpDatabase(parameters); } - performIsolatedIndexing(parameters); - releaseResources(); } @@ -190,39 +129,6 @@ public final class IndexCreationUtil applicationContext.destroy(); } - /** - * Performs indexing and restored the environment to original state - */ - private static void performIsolatedIndexing(Parameters parameters) throws Exception - { - String databaseKind = parameters.getDatabaseKind(); - String indexFolder = parameters.getIndexFolder(); - - System.setProperty("database.kind", databaseKind); - // Deactivate the indexing in the application context loaded by Spring. - System.setProperty("hibernate.search.index-mode", "NO_INDEX"); - System.setProperty("hibernate.search.index-base", indexFolder); - System.setProperty("database.create-from-scratch", parameters.getFromScratch()); - - performAndTimeIndexing(databaseKind, indexFolder); - - } - - private static void performAndTimeIndexing(String databaseKind, String indexFolder) - throws Exception - { - hibernateSearchContext = createHibernateSearchContext(indexFolder); - hibernateSearchContext.afterPropertiesSet(); - operationLog.info("=========== Start indexing ==========="); - StopWatch stopWatch = new StopWatch(); - stopWatch.start(); - createAndRunFullTextIndexer(); - stopWatch.stop(); - operationLog.info("Index of database '" + DATABASE_NAME_PREFIX + databaseKind - + "' successfully built in '" + indexFolder + "' after " - + ((stopWatch.getTime() + 30000) / 60000) + " minutes."); - } - static boolean duplicateDatabase(String destinationDatabase, String sourceDatabase) { operationLog.info("Duplicate database '" + sourceDatabase + "' as '" + destinationDatabase diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/.gitignore b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/.gitignore deleted file mode 100644 index c696d2a4a94a98ce914ed943431d577077f40bb3..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/FullTextIndexUpdaterRunnable.java -/NewDefaultFullTextIndexer.java diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/CharacterHelper.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/CharacterHelper.java deleted file mode 100644 index 9a31f8d4619371207ab6ee0163c7e27887ed79e0..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/CharacterHelper.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2010 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -/** - * Gathers characters that need special treatment and methods useful during indexing. - * - * @author Izabela Adamczyk - */ -public class CharacterHelper -{ - private static final char ESCAPE_CHARACTER = '\\'; - - public final static Set<Character> SPECIAL_CHARACTERS = new HashSet<Character>(Arrays.asList( - // Special code characters - '.', ':', '-', '_', - - // Special word characters - '\'')); - - // (don't trim '-' or '_' because they may have special meaning in identifiers) - /** those of special chars that should be trimmed */ - private final static Set<Character> TRIMMED_CHARACTERS = new HashSet<Character>(Arrays.asList( - '.', ':', '\'')); - - public static boolean isTokenCharacter(char c) - { - return Character.isLetterOrDigit(c) || SPECIAL_CHARACTERS.contains(c); - } - - public static Collection<Character> getTokenSeparators() - { - Set<Character> separators = new HashSet<Character>(); - for (char ch = 32; ch < 256; ch++) - { - if (isTokenCharacter(ch) == false && ch != ESCAPE_CHARACTER) - { - separators.add(ch); - } - } - return separators; - } - - public static Set<Character> getTrimmedSpecialCharacters() - { - return TRIMMED_CHARACTERS; - } - -} \ No newline at end of file diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/DefaultFullTextIndexer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/DefaultFullTextIndexer.java deleted file mode 100644 index 3060eb00acdbc0899db194ff5b5d9627951c500f..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/DefaultFullTextIndexer.java +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright 2008 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -import java.util.List; - -import org.apache.log4j.Logger; -import org.hibernate.CacheMode; -import org.hibernate.Criteria; -import org.hibernate.FlushMode; -import org.hibernate.Session; -import org.hibernate.Transaction; -import org.hibernate.criterion.Order; -import org.hibernate.criterion.Projections; -import org.hibernate.criterion.Restrictions; -import org.hibernate.search.FullTextSession; -import org.hibernate.search.Search; -import org.springframework.dao.DataAccessException; - -import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel; -import ch.systemsx.cisd.common.logging.LogCategory; -import ch.systemsx.cisd.common.logging.LogFactory; -import ch.systemsx.cisd.openbis.generic.shared.util.EodSqlUtils; - -/** - * A default {@link IFullTextIndexer} which knows how to perform an efficient full text index. - * <p> - * Partly taken from <i>Hibernate Search</i> documentation page. - * </p> - * - * @author Christian Ribeaud - * @author Piotr Buczek - */ -final class DefaultFullTextIndexer implements IFullTextIndexer -{ - private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, - DefaultFullTextIndexer.class); - - private static String ID_PROPERTY_NAME = "id"; - - /** - * It is critical that <code>batchSize</code> matches <code>hibernate.search.worker.batch_size</code>. - * <p> - * Default value (meaning <i>unspecified</i>) is <code>0</code>. - * </p> - */ - private final int batchSize; - - DefaultFullTextIndexer(final int batchSize) - { - assert batchSize > -1 : "Batch size can not be negative."; - this.batchSize = batchSize; - } - - // - // IFullTextIndexer - // - - @Override - public final <T> void doFullTextIndex(final Session hibernateSession, final Class<T> clazz) - throws DataAccessException - { - operationLog.info(String.format("Indexing '%s'...", clazz.getSimpleName())); - final FullTextSession fullTextSession = getFullTextSession(hibernateSession); - - doFullTextIndex(fullTextSession, clazz); - } - - <T> void doFullTextIndex(final FullTextSession fullTextSession, final Class<T> clazz) - { - // we index entities in batches loading them in groups restricted by id: - // [ ids[index], ids[min(index+batchSize, maxIndex))] ) - Transaction transaction = null; - try - { - transaction = fullTextSession.beginTransaction(); - - EodSqlUtils.setManagedConnection(transaction); - - final List<Long> ids = getAllIds(fullTextSession, clazz); - final int idsSize = ids.size(); - operationLog.info(String.format("... got %d '%s' ids...", idsSize, - clazz.getSimpleName())); - for (int index = 0; index < idsSize; index += batchSize) - { - final int nextIndex = index + batchSize; - final long minId = ids.get(index); - final long maxId = nextIndex < idsSize ? ids.get(nextIndex) : Integer.MAX_VALUE; - final List<T> results = - listEntitiesWithRestrictedId(fullTextSession, clazz, minId, maxId); - indexEntities(fullTextSession, results); - operationLog.info(String.format("%d/%d %ss have been indexed...", - Math.min(nextIndex, idsSize), idsSize, clazz.getSimpleName())); - } - fullTextSession.getSearchFactory().optimize(clazz); - transaction.commit(); - operationLog.info(String.format("'%s' index complete. %d entities have been indexed.", - clazz.getSimpleName(), idsSize)); - } catch (Exception e) - { - operationLog.error(e.getMessage()); - if (transaction != null) - { - transaction.rollback(); - } - throw CheckedExceptionTunnel.wrapIfNecessary(e); - } finally - { - EodSqlUtils.clearManagedConnection(); - } - } - - @Override - public <T> void doFullTextIndexUpdate(final Session hibernateSession, final Class<T> clazz, - final List<Long> ids) throws DataAccessException - { - operationLog.info(String.format("Reindexing %s %ss...", ids.size(), clazz.getSimpleName())); - final FullTextSession fullTextSession = getFullTextSession(hibernateSession); - - // we index entities in batches loading them in groups by id - Transaction transaction = null; - try - { - transaction = fullTextSession.beginTransaction(); - - EodSqlUtils.setManagedConnection(transaction); - - final int maxIndex = ids.size(); - int index = 0; - - while (index < maxIndex) - { - final int nextIndex = getNextIndex(index, maxIndex); - List<Long> subList = ids.subList(index, nextIndex); - final List<T> results = - listEntitiesWithRestrictedId(fullTextSession, clazz, subList); - if (subList.size() != results.size()) { - operationLog.error(String.format("The system tried to index %d but only found %d on the database.", subList.size(), results.size())); - } - indexEntities(fullTextSession, results); - index = nextIndex; - operationLog.info(String.format("%d/%d %ss have been reindexed...", index, - maxIndex, clazz.getSimpleName())); - } - fullTextSession.getSearchFactory().optimize(clazz); - transaction.commit(); - operationLog.info(String.format( - "'%s' index is updated. %d entities have been reindexed.", - clazz.getSimpleName(), index)); - } catch (Exception e) - { - operationLog.error(e.getMessage()); - if (transaction != null) - { - transaction.rollback(); - } - } finally - { - EodSqlUtils.clearManagedConnection(); - } - } - - @Override - public <T> void removeFromIndex(final Session hibernateSession, final Class<T> clazz, - final List<Long> ids) throws DataAccessException - { - operationLog.info(String.format("Removing %s %ss...", ids.size(), clazz.getSimpleName())); - final FullTextSession fullTextSession = getFullTextSession(hibernateSession); - - // removing from index doesn't require a lot of resources - don't need to use batches - Transaction transaction = null; - try - { - transaction = fullTextSession.beginTransaction(); - - EodSqlUtils.setManagedConnection(transaction); - - for (Long id : ids) - { - fullTextSession.purge(clazz, id); - } - fullTextSession.getSearchFactory().optimize(clazz); - transaction.commit(); - operationLog.info(String.format( - "'%s' index is updated. %d entities have been removed.", clazz.getSimpleName(), - ids.size())); - } catch (Exception e) - { - operationLog.error(e.getMessage()); - if (transaction != null) - { - transaction.rollback(); - } - } finally - { - EodSqlUtils.clearManagedConnection(); - } - } - - private int getNextIndex(int index, int maxIndex) - { - return Math.min(index + batchSize, maxIndex); - } - - private static final FullTextSession getFullTextSession(final Session hibernateSession) - { - final FullTextSession fullTextSession = Search.getFullTextSession(hibernateSession); - fullTextSession.setFlushMode(FlushMode.MANUAL); - fullTextSession.setCacheMode(CacheMode.IGNORE); - return fullTextSession; - } - - private static final <T> void indexEntities(final FullTextSession fullTextSession, - final List<T> entities) - { - for (T entity : entities) - { - indexEntity(fullTextSession, entity); - } - fullTextSession.flushToIndexes(); - fullTextSession.clear(); - } - - private static final <T> List<Long> getAllIds(final FullTextSession fullTextSession, - final Class<T> clazz) - { - Criteria criteria = - createCriteria(fullTextSession, clazz).setProjection( - Projections.property(ID_PROPERTY_NAME)).addOrder( - Order.asc(ID_PROPERTY_NAME)); - return list(criteria); - } - - private static final <T> List<T> listEntitiesWithRestrictedId( - final FullTextSession fullTextSession, final Class<T> clazz, final long minId, - final long maxId) - { - Criteria criteria = - createCriteria(fullTextSession, clazz) - .add(Restrictions.ge(ID_PROPERTY_NAME, minId)).add( - Restrictions.lt(ID_PROPERTY_NAME, maxId)); - return list(criteria); - - } - - private static final <T> List<T> listEntitiesWithRestrictedId( - final FullTextSession fullTextSession, final Class<T> clazz, final List<Long> ids) - { - Criteria criteria = - createCriteria(fullTextSession, clazz).add(Restrictions.in(ID_PROPERTY_NAME, ids)); - return list(criteria); - - } - - private static final <T> Criteria createCriteria(final FullTextSession fullTextSession, - final Class<T> clazz) - { - return fullTextSession.createCriteria(clazz); - } - - @SuppressWarnings("unchecked") - private static final <T> List<T> list(final Criteria criteria) - { - return criteria.list(); - } - - private static final <T> void indexEntity(final FullTextSession fullTextSession, T entity) - { - if (operationLog.isDebugEnabled()) - { - operationLog.debug(String.format("Indexing entity '%s'.", entity)); - } - try - { - fullTextSession.index(entity); - } catch (Exception e) - { - operationLog.error("Error while indexing the entity " + entity + ": " + e.getMessage() - + ". Indexing will be continued."); - } - } - -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/EntitiesToUpdate.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/EntitiesToUpdate.java deleted file mode 100644 index 41b946397420bf1850303f0b313cc75c4e31a270..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/EntitiesToUpdate.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2010 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -import java.io.Serializable; -import java.util.List; - -import ch.systemsx.cisd.common.collection.CollectionUtils; - -/** - * Encapsulates operation kind and data for an update operation to be performed on an index. - * - * @author Piotr Buczek - */ -public class EntitiesToUpdate implements Serializable -{ - public enum IndexUpdateOperationKind - { - /** update indexed entity */ - REINDEX, - - /** remove from index */ - REMOVE - } - - private static final long serialVersionUID = 1L; - - private final Class<?> clazz; - - private final List<Long> ids; - - private final IndexUpdateOperationKind operationKind; - - public static EntitiesToUpdate remove(Class<?> clazz, List<Long> ids) - { - return new EntitiesToUpdate(IndexUpdateOperationKind.REMOVE, clazz, ids); - } - - public static EntitiesToUpdate reindex(Class<?> clazz, List<Long> ids) - { - return new EntitiesToUpdate(IndexUpdateOperationKind.REINDEX, clazz, ids); - } - - private EntitiesToUpdate(IndexUpdateOperationKind operationKind, Class<?> clazz, - List<Long> ids) - { - this.clazz = clazz; - this.ids = ids; - this.operationKind = operationKind; - } - - public Class<?> getClazz() - { - return clazz; - } - - public List<Long> getIds() - { - return ids; - } - - public IndexUpdateOperationKind getOperationKind() - { - return operationKind; - } - - @Override - public String toString() - { - return operationKind + " " + clazz.getName() + ": " + CollectionUtils.abbreviate(ids, 10); - } - -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/FullTextIndexUpdater.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/FullTextIndexUpdater.java deleted file mode 100644 index 7abfa922340c9b0beab14b8c282eefcf428e7880..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/FullTextIndexUpdater.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright 2008 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -import java.io.File; -import java.util.Queue; - -import org.apache.commons.lang3.time.StopWatch; -import org.apache.log4j.Logger; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.springframework.orm.hibernate5.support.HibernateDaoSupport; - -import ch.systemsx.cisd.common.collection.CollectionUtils; -import ch.systemsx.cisd.common.collection.ExtendedLinkedBlockingQueue; -import ch.systemsx.cisd.common.collection.IExtendedBlockingQueue; -import ch.systemsx.cisd.common.io.PersistentExtendedBlockingQueueFactory; -import ch.systemsx.cisd.common.logging.LogCategory; -import ch.systemsx.cisd.common.logging.LogFactory; - -/** - * A <i>full-text</i> index updater. - * - * @author Piotr Buczek - */ -public final class FullTextIndexUpdater extends HibernateDaoSupport implements - IFullTextIndexUpdater -{ - public final static String FULL_TEXT_INDEX_UPDATER_QUEUE_FILENAME = ".index_updater_queue"; - - private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, - FullTextIndexUpdater.class); - - private static final Logger notificationLog = LogFactory.getLogger(LogCategory.NOTIFY, - FullTextIndexUpdater.class); - - private final HibernateSearchContext context; - - private final IFullTextIndexer fullTextIndexer; - - private final IExtendedBlockingQueue<IndexUpdateOperation> updaterQueue; - - public FullTextIndexUpdater(final SessionFactory sessionFactory, - final HibernateSearchContext context) - { - assert context != null : "Unspecified hibernate search context."; - setSessionFactory(sessionFactory); - this.context = context; - operationLog.debug(String.format("Hibernate search context: %s.", context)); - fullTextIndexer = new DefaultFullTextIndexer(context.getBatchSize()); - - final IndexMode indexMode = context.getIndexMode(); - if (indexMode == IndexMode.NO_INDEX) - { - // don't use persistent queue e.g. in tests to avoid problems (see SE-286) - operationLog.info(String.format( - "'%s' mode was configured. Updater tasks will not be persisted", indexMode)); - updaterQueue = new ExtendedLinkedBlockingQueue<IndexUpdateOperation>(); - return; - } - - final File indexBase = new File(context.getIndexBase()); - final File queueFile = getUpdaterQueueFile(indexBase); - operationLog.debug(String.format("Updater queue file: %s.", queueFile)); - updaterQueue = createUpdaterQueue(indexBase, queueFile); - } - - public int getQueueSize() - { - return updaterQueue.size(); - } - - public Queue<IndexUpdateOperation> getQueue() - { - return updaterQueue; - } - - private static IExtendedBlockingQueue<IndexUpdateOperation> createUpdaterQueue( - final File indexBase, final File queueFile) - { - try - { - return PersistentExtendedBlockingQueueFactory - .<IndexUpdateOperation> createSmartPersist(queueFile); - } catch (RuntimeException e) - { - // don't fail if e.g. deserialization of the queue fails (see SE-286) - String newFileName = - FULL_TEXT_INDEX_UPDATER_QUEUE_FILENAME + "_" + System.currentTimeMillis(); - notificationLog.error(String.format("%s.\n " - + "Renaming '%s' to '%s' and using an empty queue file. " - + "Restart server with the queue that caused the problem " - + "or force reindex of all entities.", e.getMessage(), queueFile, newFileName)); - queueFile.renameTo(new File(indexBase, newFileName)); - return PersistentExtendedBlockingQueueFactory - .<IndexUpdateOperation> createSmartPersist(queueFile); - } - } - - private static File getUpdaterQueueFile(File indexBase) - { - return new File(indexBase, FULL_TEXT_INDEX_UPDATER_QUEUE_FILENAME); - } - - @Override - public void start() - { - if (operationLog.isInfoEnabled()) - { - operationLog.info("Starting updater thread with queue size: " + updaterQueue.size()); - } - Thread thread = new Thread(new FullTextIndexUpdaterRunnable(), "Full Text Index Updater"); - thread.setDaemon(true); - thread.setPriority(Thread.MIN_PRIORITY); - thread.start(); - } - - @Override - public void clear() - { - updaterQueue.clear(); - if (operationLog.isInfoEnabled()) - { - operationLog.info("Cleared updater queue."); - } - } - - @Override - public void scheduleUpdate(IndexUpdateOperation operation) - { - if (operationLog.isDebugEnabled()) - { - operationLog.debug("Scheduling update: " + operation); - } - updaterQueue.add(operation); - } - - /** - * {@link Runnable} performing updates in a loop. - * - * @author Piotr Buczek - */ - private class FullTextIndexUpdaterRunnable implements Runnable - { - @Override - public final void run() - { - final IndexMode indexMode = context.getIndexMode(); - if (indexMode == IndexMode.NO_INDEX) // sanity check - { - operationLog.info(String.format("Stopping index updater process as " - + " '%s' mode was configured.", indexMode)); - return; - } - try - { - while (true) - { - final IndexUpdateOperation operation = updaterQueue.peekWait(); - if (operationLog.isInfoEnabled()) - { - operationLog.info("Update: " + operation); - } - final StopWatch stopWatch = new StopWatch(); - stopWatch.start(); - Session session = null; - try - { - final Class<?> clazz = Class.forName(operation.getClassName()); - session = getSessionFactory().openSession(); - switch (operation.getOperationKind()) - { - case REINDEX: - fullTextIndexer.doFullTextIndexUpdate(session, clazz, - operation.getIds()); - break; - case REMOVE: - fullTextIndexer.removeFromIndex(session, clazz, operation.getIds()); - } - stopWatch.stop(); - } catch (RuntimeException e) - { - notificationLog.error("Error: " + operation + ".", e); - } finally - { - if (session != null) - { - session.close(); - } - if (operationLog.isInfoEnabled()) - { - operationLog.info(operation.getOperationKind() + " of " - + operation.getIds().size() + " " + operation.getClassName() - + "s " + CollectionUtils.abbreviate(operation.getIds(), 20) - + " took " + stopWatch); - } - } - updaterQueue.take(); - } - } catch (final InterruptedException e) - { - operationLog.warn(e); - } catch (final Throwable th) - { - notificationLog.error("A problem has occurred while updating index.", th); - } finally - { - operationLog.info("Updater closed"); - } - - } - } - -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/FullTextIndexerRunnable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/FullTextIndexerRunnable.java deleted file mode 100644 index 76399220b1877f8d6d379a210b73be0b060eac6d..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/FullTextIndexerRunnable.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2008 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -import java.io.File; -import java.io.IOException; -import java.util.Set; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang3.time.StopWatch; -import org.apache.log4j.Logger; -import org.apache.lucene.index.IndexWriter; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.search.FullTextSession; -import org.hibernate.search.Search; -import org.hibernate.search.SearchFactory; -import org.hibernate.search.annotations.Indexed; -import org.hibernate.search.indexes.spi.DirectoryBasedIndexManager; -import org.hibernate.search.spi.SearchIntegrator; -import org.hibernate.search.store.DirectoryProvider; -import org.springframework.orm.hibernate5.support.HibernateDaoSupport; - -import ch.systemsx.cisd.common.filesystem.FileConstants; -import ch.systemsx.cisd.common.logging.LogCategory; -import ch.systemsx.cisd.common.logging.LogFactory; - -/** - * A <i>full-text</i> indexer. - * - * @author Christian Ribeaud - */ -public final class FullTextIndexerRunnable extends HibernateDaoSupport implements Runnable -{ - public final static String FULL_TEXT_INDEX_MARKER_FILENAME = FileConstants.MARKER_PREFIX - + "full_index"; - - private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, - FullTextIndexerRunnable.class); - - private static final Logger notificationLog = LogFactory.getLogger(LogCategory.NOTIFY, - FullTextIndexerRunnable.class); - - private final HibernateSearchContext context; - - private final IFullTextIndexer fullTextIndexer; - - private final IFullTextIndexUpdater fullTextIndexUpdater; - - private final IIndexedEntityFinder indexedEntityFinder; - - public FullTextIndexerRunnable(final SessionFactory sessionFactory, - final HibernateSearchContext context, final IFullTextIndexUpdater fullTextIndexUpdater) - { - assert context != null : "Unspecified hibernate search context."; - setSessionFactory(sessionFactory); - this.context = context; - this.fullTextIndexUpdater = fullTextIndexUpdater; - this.fullTextIndexer = new DefaultFullTextIndexer(context.getBatchSize()); - // TODO 2008-11-25, Tomasz Pylak: maybe we could get rid of hardcoding package path by - // scanning Hibernate mapped entities? - this.indexedEntityFinder = - new PackageBasedIndexedEntityFinder("ch.systemsx.cisd.openbis.generic.shared.dto"); - operationLog.info(String.format("Hibernate search context: %s.", context)); - } - - // - // Runnable - // - - @Override - public final void run() - { - final IndexMode indexMode = context.getIndexMode(); - if (indexMode == IndexMode.NO_INDEX) - { - operationLog.debug(String.format("Skipping indexing process as " - + " '%s' mode was configured.", indexMode)); - return; - } - final Set<Class<?>> indexedEntities = indexedEntityFinder.getIndexedEntities(); - - // Use code below for debugging if not all entities need to be indexed. - // - // final Set<Class<?>> indexedEntities = new HashSet<Class<?>>(); - // indexedEntities.add(DataPE.class); - // indexedEntities.add(ExperimentPE.class); - - if (indexedEntities.size() == 0) - { - operationLog.info(String.format("No entity annotated with '%s' has been found.", - Indexed.class.getSimpleName())); - return; - } - Class<?> currentEntity = null; - try - { - // timeout exceptions were observed for the default timeout when database was bigger - // IndexWriterConfig.setDefaultWriteLockTimeout(3000); - final File indexBase = new File(context.getIndexBase()); - final File markerFile = new File(indexBase, FULL_TEXT_INDEX_MARKER_FILENAME); - final Session session = getSessionFactory().openSession(); - writeLockRecovery(session, indexedEntities); // recover even if marker is found - if (indexMode == IndexMode.SKIP_IF_MARKER_FOUND && markerFile.exists()) - { - operationLog.debug(String.format("Skipping indexing process as " - + "marker file '%s' already exists.", markerFile.getAbsolutePath())); - return; - } - // full text index will be performed so updater queue can be cleared - fullTextIndexUpdater.clear(); - // - final StopWatch stopWatch = new StopWatch(); - for (final Class<?> indexedEntity : indexedEntities) - { - currentEntity = indexedEntity; - stopWatch.reset(); - stopWatch.start(); - fullTextIndexer.doFullTextIndex(session, indexedEntity); - stopWatch.stop(); - operationLog.info(String.format("Indexing entity '%s' took %s.", - indexedEntity.getName(), stopWatch)); - } - FileUtils.touch(markerFile); - session.close(); - } catch (final Throwable th) - { - notificationLog.error(String.format( - "A problem has occurred while indexing entity '%s'.", currentEntity), th); - } finally - // when index creation is finished start index updater thread - { - fullTextIndexUpdater.start(); - } - } - - /** - * Recovery code that removes stale write locks on directories of specified entities (see LMS-2168). It should be run only at the server start - * when we are sure that no other thread could be writing to the index at the same time. In our case the updater thread shouldn't be started yet. - * - * @see IndexWriter#unlock(org.apache.lucene.store.Directory) - */ - private void writeLockRecovery(Session session, Set<Class<?>> indexedEntities) - throws IOException - { - final FullTextSession fullTextSession = Search.getFullTextSession(session); - SearchFactory searchFactory = fullTextSession.getSearchFactory(); - SearchIntegrator searchIntegrator = searchFactory.unwrap(SearchIntegrator.class); - - for (Class<?> indexedEntity : indexedEntities) - { - DirectoryBasedIndexManager indexManager = - (DirectoryBasedIndexManager) searchIntegrator.getIndexManager(indexedEntity.getSimpleName()); - DirectoryProvider<?> provider = indexManager.getDirectoryProvider(); - // IndexWriter.unlock(provider.getDirectory()); - } - } -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/HibernateSearchContext.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/HibernateSearchContext.java deleted file mode 100644 index dcbac27074a32cfe200b03213aa5a486635a8bcf..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/HibernateSearchContext.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2008 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -import java.io.File; - -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; -import org.springframework.beans.factory.InitializingBean; - -import ch.systemsx.cisd.common.filesystem.FileUtilities; -import ch.systemsx.cisd.common.logging.Log4jSimpleLogger; -import ch.systemsx.cisd.common.logging.LogCategory; -import ch.systemsx.cisd.common.logging.LogFactory; -import ch.systemsx.cisd.common.reflection.ModifiedShortPrefixToStringStyle; - -/** - * A bean class that contains properties related to <i>Hibernate Search</i>. - * <p> - * This bean must be initialized before <code>hibernate-session-factory</code> bean as it will remove the <code>indexBase</code> directory. - * </p> - * - * @author Christian Ribeaud - */ -public final class HibernateSearchContext implements InitializingBean -{ - private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, - HibernateSearchContext.class); - - private IndexMode indexMode = IndexMode.SKIP_IF_MARKER_FOUND; - - private String indexBase = System.getProperty("java.io.tmpdir"); - - /** - * 0 means no limit. - */ - private int batchSize = 1000; - - private int maxResults = 100000; - - public int getMaxResults() - { - return maxResults; - } - - public void setMaxResults(int maxResults) - { - if (maxResults > 0) - { - this.maxResults = maxResults; - } - } - - public final String getIndexBase() - { - return indexBase; - } - - public final void setIndexBase(final String indexBase) - { - if (StringUtils.isNotBlank(indexBase)) - { - this.indexBase = indexBase; - } - } - - public final int getBatchSize() - { - return batchSize; - } - - public final void setBatchSize(final int batchSize) - { - this.batchSize = Math.max(0, batchSize); - } - - public final IndexMode getIndexMode() - { - return indexMode; - } - - public final void setIndexMode(final IndexMode indexMode) - { - assert indexMode != null : "Unspecified index mode."; - this.indexMode = indexMode; - } - - // - // Object - // - - @Override - public final String toString() - { - return ToStringBuilder.reflectionToString(this, - ModifiedShortPrefixToStringStyle.MODIFIED_SHORT_PREFIX_STYLE); - } - - // - // InitializingBean - // - - @Override - public final void afterPropertiesSet() throws Exception - { - if (getIndexMode() == IndexMode.INDEX_FROM_SCRATCH) - { - final File searchIndexBase = new File(getIndexBase()); - if (searchIndexBase.exists()) - { - final boolean deleted = - FileUtilities.deleteRecursively(searchIndexBase, new Log4jSimpleLogger( - operationLog, Level.DEBUG)); - operationLog.info(String.format("Index base '%s' %s.", searchIndexBase - .getAbsolutePath(), deleted ? "has been successfully deleted" - : "has NOT been deleted")); - } - } - } -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexUpdateScheduler.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexUpdateScheduler.java deleted file mode 100644 index fbd5de16b694c6ffa75037135e0b9e503c4235c6..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexUpdateScheduler.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2008 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -/** - * Each implementation is able to schedule a <i>full-text</i> index update. Updates are expected to be executed asynchronously in the order they had - * been scheduled. The thread executing updates will run with low priority. - * - * @author Piotr Buczek - */ -public interface IFullTextIndexUpdateScheduler -{ - /** - * Schedules specified operation. - */ - void scheduleUpdate(IndexUpdateOperation operation); -} \ No newline at end of file diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexUpdater.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexUpdater.java deleted file mode 100644 index ea7cc234cdab5b1e522b6aa387a3f477d622a248..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexUpdater.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2008 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -/** - * Each implementation is able to perform a <i>full-text</i> index update. Updates are expected to be executed asynchronously in the order they had - * been scheduled. The thread executing updates will run with low priority. - * - * @author Piotr Buczek - */ -public interface IFullTextIndexUpdater extends IFullTextIndexUpdateScheduler -{ - - /** - * Starts up updater. - */ - void start(); - - /** - * Clears the schedule. - */ - void clear(); - -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexer.java deleted file mode 100644 index c065a8a5dd8042cca5e2671ed58877c6689533f7..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IFullTextIndexer.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2008 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -import java.util.List; - -import org.hibernate.Session; -import org.springframework.dao.DataAccessException; - -/** - * Each implementation is able to perform a <i>full-text</i> index. - * - * @author Christian Ribeaud - * @author Piotr Buczek - */ -public interface IFullTextIndexer -{ - - /** - * Performs a <i>full-text</i> index on entities of given <var>clazz</var> using given <i>Hibernate</i> session. - */ - public <T> void doFullTextIndex(final Session hibernateSession, final Class<T> clazz) - throws DataAccessException; - - /** - * Performs a <i>full-text</i> index update on entities of given <var>clazz</var> with given <var>ids</var> using given <i>Hibernate</i> session. - */ - public <T> void doFullTextIndexUpdate(final Session hibernateSession, final Class<T> clazz, - final List<Long> ids) throws DataAccessException; - - /** - * Removes entities of given <var>clazz</var> with given <var>ids</var> from the <i>full-text</i> index using given <i>Hibernate</i> session. - */ - public <T> void removeFromIndex(final Session hibernateSession, final Class<T> clazz, - final List<Long> ids) throws DataAccessException; -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IIndexedEntityFinder.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IIndexedEntityFinder.java deleted file mode 100644 index ba3ef272cf6db02cf3a3d4aa1ceb6a69d9f7f3bb..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IIndexedEntityFinder.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2008 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -import java.util.Set; - -import org.hibernate.search.annotations.Indexed; - -/** - * An finder of entities annotated with {@link Indexed} annotation. - * - * @author Christian Ribeaud - */ -public interface IIndexedEntityFinder -{ - /** - * Returns the <i>Hibernate</i> entities that are annotated with {@link Indexed} annotation. - * - * @return never <code>null</code> but could return an empty set. - */ - public Set<Class<?>> getIndexedEntities(); -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IndexMode.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IndexMode.java deleted file mode 100644 index 872396de1fa38f009e6681630f458d9df1d73c65..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IndexMode.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2008 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -/** - * The mode in which the indexing is working: - * <ul> - * <li><b>NO_INDEX</b>: no manual index will be performed.</li> - * <li><b>SKIP_IF_MARKER_FOUND</b>: skips the indexing if {@link FullTextIndexerRunnable#FULL_TEXT_INDEX_MARKER_FILENAME} marker file is found - * (meaning that a manual index has already been performed).</li> - * <li><b>INDEX_FROM_SCRATCH</b>: performs a manual index from the scratch, deleting the whole <code>index-base</code> directory.</li> - * </ul> - * - * @author Christian Ribeaud - */ -public enum IndexMode -{ - NO_INDEX, SKIP_IF_MARKER_FOUND, INDEX_FROM_SCRATCH; -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IndexUpdateOperation.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IndexUpdateOperation.java deleted file mode 100644 index cc85d0f5a0ed75f823500613780401b40bd19ce7..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/IndexUpdateOperation.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2010 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -import java.io.Serializable; -import java.util.List; - -import ch.systemsx.cisd.common.collection.CollectionUtils; - -/** - * Encapsulates operation kind and data for an update operation to be performed on an index. - * - * @author Piotr Buczek - */ -public class IndexUpdateOperation implements Serializable -{ - public enum IndexUpdateOperationKind - { - /** update indexed entity */ - REINDEX, - - /** remove from index */ - REMOVE - } - - private static final long serialVersionUID = 2L; - - // we don't store Class<?> not to cause problems with deserialization - private final String className; - - private final List<Long> ids; - - private final IndexUpdateOperationKind operationKind; - - public static IndexUpdateOperation remove(Class<?> clazz, List<Long> ids) - { - return new IndexUpdateOperation(IndexUpdateOperationKind.REMOVE, clazz, ids); - } - - public static IndexUpdateOperation reindex(Class<?> clazz, List<Long> ids) - { - return new IndexUpdateOperation(IndexUpdateOperationKind.REINDEX, clazz, ids); - } - - private IndexUpdateOperation(IndexUpdateOperationKind operationKind, Class<?> clazz, - List<Long> ids) - { - this.className = clazz.getName(); - this.ids = ids; - this.operationKind = operationKind; - } - - public String getClassName() - { - return className; - } - - public List<Long> getIds() - { - return ids; - } - - public IndexUpdateOperationKind getOperationKind() - { - return operationKind; - } - - @Override - public String toString() - { - return operationKind + " " + className + ": " + CollectionUtils.abbreviate(ids, 10); - } -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/LuceneQueryBuilder.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/LuceneQueryBuilder.java deleted file mode 100644 index 6a74411b1a60fb527fe7c4add3db3cecc17b4f65..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/LuceneQueryBuilder.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright 2009 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import org.apache.commons.lang3.StringUtils; -import org.apache.lucene.analysis.Analyzer; -import org.apache.lucene.index.DocValuesType; -import org.apache.lucene.queryparser.classic.ParseException; -import org.apache.lucene.queryparser.classic.QueryParser; -import org.apache.lucene.search.BooleanClause; -import org.apache.lucene.search.BooleanClause.Occur; -import org.apache.lucene.search.BooleanQuery; -import org.apache.lucene.search.MatchAllDocsQuery; -import org.apache.lucene.search.MultiTermQuery; -import org.apache.lucene.search.Query; - -import ch.systemsx.cisd.common.exceptions.UserFailureException; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.detailed.DetailedQueryBuilder; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CompareType; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriteria; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IAssociationCriteria; -import ch.systemsx.cisd.openbis.generic.shared.dto.properties.EntityKind; -import ch.systemsx.cisd.openbis.generic.shared.translator.DtoConverters; - -/** - * @author Tomasz Pylak - */ -public class LuceneQueryBuilder -{ - private static final String NOT = "NOT"; - - private static final String OR = "OR"; - - private static final String AND = "AND"; - - private static final char STAR = '*'; - - private static final char SPACE = ' '; - - /** - * @throws UserFailureException when some search patterns are incorrect - */ - public static Query createDetailedSearchQuery(String userId, - DetailedSearchCriteria searchCriteria, - List<IAssociationCriteria> associations, EntityKind entityKind, Map<String, DocValuesType> fieldTypes) - { - return DetailedQueryBuilder.createQuery(userId, searchCriteria, - DtoConverters.convertEntityKind(entityKind), associations, fieldTypes); - } - - private static final char FIELD_SEPARATOR = ':'; - - // - // query adaptation - // - - private static final char[] CHARS_ESCAPED_IN_WILCARD_MODE = - { FIELD_SEPARATOR, '/' }; - - // For now both wildcard and basic modes escape the same characters. If we decide - // to escape wildcard characters in basic mode unescape the following code. - // private static final char[] CHARS_ESCAPED_IN_BASIC_MODE = - // { FIELD_SEPARATOR, '*', '?' }; - private static final char[] CHARS_ESCAPED_IN_BASIC_MODE = CHARS_ESCAPED_IN_WILCARD_MODE; - - public static String adaptQuery(String userQuery, boolean useWildcardSearchMode) - { - return adaptQuery(userQuery, useWildcardSearchMode, true); - } - - public static String adaptQuery(String userQuery, boolean useWildcardSearchMode, - boolean splitQuery) - { - char[] escapedChars = - (useWildcardSearchMode == true) ? CHARS_ESCAPED_IN_WILCARD_MODE - : CHARS_ESCAPED_IN_BASIC_MODE; - String result = escapeQuery(userQuery, escapedChars); - // add '*' wildcard at the beginning and at the end of the query if all conditions are met: - // 1. in basic search mode - // 2. query is not in quotes - // 3. query doesn't contain '*' - if (useWildcardSearchMode == false && isQuoted(result) == false - && result.contains("*") == false) - { - result = addWildcards(result, splitQuery); - } - return result; - } - - private static String addWildcards(String result, boolean split) - { - String[] queryTokens = StringUtils.split(result, SPACE); - List<String> transformedTokens = new ArrayList<String>(); - for (String qt : queryTokens) - { - if (qt.equals(AND) || qt.equals(OR) || qt.equals(NOT)) - { - transformedTokens.add(qt); - } else - { - transformedTokens.add(addWildcartdsToToken(qt, split)); - } - } - return StringUtils.join(transformedTokens, SPACE); - } - - private static String addWildcartdsToToken(String token, boolean split) - { - Collection<Character> tokenSeparators = CharacterHelper.getTokenSeparators(); - tokenSeparators.removeAll(new ArrayList<String>()); - String[] miniTokens = null; - - if (split) - { - miniTokens = StringUtils.split(token, StringUtils.join(tokenSeparators, "")); - } else - { - miniTokens = new String[] { token }; - } - - List<String> transformedMiniTokens = new ArrayList<String>(); - for (String qt : miniTokens) - { - transformedMiniTokens.add(STAR + qt + STAR); - } - return '(' + StringUtils.join(transformedMiniTokens, SPACE + AND + SPACE) + ')'; - } - - private static boolean isQuoted(String result) - { - return result.startsWith("\"") && result.endsWith("\""); - } - - /** - * Escapes <var>escapedChars</var> characters in the query. - */ - private static String escapeQuery(String userQuery, char... escapedChars) - { - char escapeChar = '\\'; - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < userQuery.length(); i++) - { - char ch = userQuery.charAt(i); - for (char escapedChar : escapedChars) - { - if (ch == escapedChar && (i == 0 || userQuery.charAt(i - 1) != escapeChar)) - { - // add escape character if there is none - sb.append(escapeChar); - } - } - sb.append(ch); - } - return sb.toString(); - } - - // - - /** - * All the search query parsers should use this method to get the analyzer, because this is the one which is used to build the index. - */ - public static Analyzer createSearchAnalyzer() - { - return new SearchAnalyzer(); - } - - public static Query parseQuery(final String fieldName, final String searchPattern, - Analyzer analyzer) throws UserFailureException - { - final QueryParser parser = new QueryParser(fieldName, analyzer); - - parser.setMultiTermRewriteMethod(MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE); - return parseQuery(searchPattern, searchPattern, parser); - } - - // creates a query where any field matches the given pattern - public static Query parseQuery(final CompareType type, final List<String> fieldNames, - final List<String> searchPatterns, List<Analyzer> analyzers, List<Occur> occurs) - throws UserFailureException - { - BooleanQuery resultQuery = new BooleanQuery(); - - boolean mustNotOccured = false; - boolean shouldOccured = false; - for (int i = 0; i < fieldNames.size(); i++) - { - String fieldName = fieldNames.get(i); - String searchPattern = searchPatterns.get(i); - Analyzer analyzer = analyzers.get(i); - - Query query = parseQuery(fieldName, searchPattern, analyzer); - Occur occur = occurs.get(i); - if (Occur.MUST_NOT.equals(occur)) - { - mustNotOccured = true; - } else if (Occur.SHOULD.equals(occur)) - { - shouldOccured = true; - } - resultQuery.add(query, occur); - } - if (mustNotOccured && shouldOccured == false) - { - resultQuery.add(new BooleanClause(new MatchAllDocsQuery(), Occur.SHOULD)); - } - return resultQuery; - } - - // creates a query where given field matches any of the given patterns - public static Query parseQuery(final String fieldName, final List<String> searchPatterns, - Analyzer analyzer) throws UserFailureException - { - BooleanQuery resultQuery = new BooleanQuery(); - for (String searchPattern : searchPatterns) - { - Query query = parseQuery(fieldName, searchPattern, analyzer); - resultQuery.add(query, Occur.SHOULD); - } - return resultQuery; - } - - private static Query parseQuery(final String searchPattern, String wholeQuery, - final QueryParser parser) - { - parser.setAllowLeadingWildcard(true); - BooleanQuery.setMaxClauseCount(Integer.MAX_VALUE); - - try - { - return parser.parse(wholeQuery); - } catch (ParseException ex) - { - throw new UserFailureException(String.format("Search pattern '%s' is invalid.", - searchPattern), ex); - } - } -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/PackageBasedIndexedEntityFinder.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/PackageBasedIndexedEntityFinder.java deleted file mode 100644 index 369348686de976914edc348d80ab0bbfdea24b54..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/PackageBasedIndexedEntityFinder.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2008 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.hibernate.search.annotations.Indexed; - -import ch.systemsx.cisd.common.reflection.ClassUtils; -import ch.systemsx.cisd.common.reflection.IClassFilter; - -/** - * A {@link IIndexedEntityFinder} based on a package name specified in the constructor. Classes ending with <code>Test</code> will be ignored. - * <p> - * This does not work recursively and expects to find all the correctly annotated classes in the given package. - * </p> - * - * @author Christian Ribeaud - */ -public final class PackageBasedIndexedEntityFinder implements IIndexedEntityFinder -{ - private Set<Class<?>> indexedEntities; - - public PackageBasedIndexedEntityFinder(final String packageName) - { - assert packageName != null : "Unspecified package name."; - indexedEntities = createIndexedEntities(packageName); - } - - private HashSet<Class<?>> createIndexedEntities(final String packageName) - { - final List<Class<?>> classes = ClassUtils.listClasses(packageName, new IClassFilter() - { - - // - // IClassFilter - // - - @Override - public boolean accept(String fullyQualifiedClassName) - { - return fullyQualifiedClassName.endsWith("Test") == false; - } - - @Override - public final boolean accept(final Class<?> clazz) - { - if (clazz.isAnnotationPresent(Indexed.class)) - { - if (clazz.getSuperclass() != null && accept(clazz.getSuperclass())) - { - // don't index data sets twice (for DataPE and for ExternalDataPE) - return false; - } else - { - return true; - } - } else - { - return false; - } - } - }); - return new HashSet<Class<?>>(classes); - } - - // - // IIndexedEntityFinder - // - - @Override - public final Set<Class<?>> getIndexedEntities() - { - return indexedEntities; - } -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/SearchAnalyzer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/SearchAnalyzer.java deleted file mode 100644 index 6f26850474281477f00f356e2d8d4b25b22b56ff..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/SearchAnalyzer.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2008 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -import java.io.IOException; -import java.util.Set; - -import org.apache.lucene.analysis.Analyzer; -import org.apache.lucene.analysis.TokenFilter; -import org.apache.lucene.analysis.TokenStream; -import org.apache.lucene.analysis.Tokenizer; -import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; -import org.apache.lucene.analysis.util.CharTokenizer; - -/** - * Extends {@link Analyzer} splitting text on characters not allowed in codes or words. - * - * @author Piotr Buczek - */ -public final class SearchAnalyzer extends Analyzer -{ - - // - // Helper classes - // - - /** - * A tokenizer that divides text at chars different than letters, digits and special chars defined in {@link CharacterHelper}. - * <p> - * Additionally it normalizes token text to lower case (with a performance gain compared to using LowerCaseFilter after tokenization). - */ - private static class WordAndCodeTokenizer extends CharTokenizer - { - - @Override - protected boolean isTokenChar(int c) - { - return CharacterHelper.isTokenCharacter((char) c); - } - - @Override - protected int normalize(int c) - { - return Character.toLowerCase((char) c); - } - } - - /** - * Normalizes tokens extracted with {@link WordAndCodeTokenizer} trimming special chars. - */ - private static final class TrimSpecialCharsFilter extends TokenFilter - { - private CharTermAttribute termAttr; - - public TrimSpecialCharsFilter(TokenStream input) - { - super(input); - this.termAttr = addAttribute(CharTermAttribute.class); - } - - @Override - public final boolean incrementToken() throws IOException - { - while (input.incrementToken()) - { - char[] buffer = this.termAttr.buffer(); - final int bufferLength = this.termAttr.length(); - - int startCounter = 0; // counts chars to trim from the beginning - Set<Character> trimmedCharacters = CharacterHelper.getTrimmedSpecialCharacters(); - for (int i = 0; i < bufferLength; i++) - { - if (trimmedCharacters.contains(buffer[i])) - { - startCounter++; - } else - { - break; - } - } - - // if all chars are special leave the token untouched - if (startCounter == bufferLength) - { - return true; - } - - int endCounter = 0; // counts chars to trim from the end - for (int i = bufferLength - 1; i > 0; i--) - { - if (trimmedCharacters.contains(buffer[i])) - { - endCounter++; - } else - { - break; - } - } - - if (startCounter > 0) - { - // need to shift all characters (setting startPos to >0 breaks search equality) - // see: StandardFilter - for (int i = startCounter; i < bufferLength; i++) - { - buffer[i - startCounter] = buffer[i]; - } - } - - // change length - if (startCounter + endCounter > 0) - { - int trimmedLength = bufferLength - (startCounter + endCounter); - this.termAttr.setLength(trimmedLength); - } - - return true; - } - return false; - } - } - - @Override - protected TokenStreamComponents createComponents(String fieldName) - { - Tokenizer source = new WordAndCodeTokenizer(); - TokenStream filter = new TrimSpecialCharsFilter(source); - return new TokenStreamComponents(source, filter); - } - -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/DetailedQueryBuilder.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/DetailedQueryBuilder.java deleted file mode 100644 index 1af5fc3abefa2463a3cc461198c21d9095b3f6e7..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/DetailedQueryBuilder.java +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright 2009 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.detailed; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.EnumSet; -import java.util.List; -import java.util.Map; - -import org.apache.commons.lang3.StringUtils; -import org.apache.log4j.Logger; -import org.apache.lucene.analysis.Analyzer; -import org.apache.lucene.index.DocValuesType; -import org.apache.lucene.search.BooleanClause.Occur; -import org.apache.lucene.search.BooleanQuery; -import org.apache.lucene.search.Query; -import org.apache.lucene.search.TermRangeQuery; -import org.hibernate.search.annotations.Resolution; -import org.hibernate.search.bridge.builtin.StringEncodingDateBridge; -import org.hibernate.search.util.impl.PassThroughAnalyzer; - -import ch.systemsx.cisd.common.exceptions.InternalErr; -import ch.systemsx.cisd.common.exceptions.UserFailureException; -import ch.systemsx.cisd.common.logging.LogCategory; -import ch.systemsx.cisd.common.logging.LogFactory; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.MetaprojectSearch; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.LuceneQueryBuilder; -import ch.systemsx.cisd.openbis.generic.shared.basic.AttributeSearchFieldKindProvider; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CompareType; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriteria; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriterion; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchField; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchFieldKind; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IAssociationCriteria; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IAttributeSearchFieldKind; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SearchCriteriaConnection; -import ch.systemsx.cisd.openbis.generic.shared.dto.hibernate.SearchFieldConstants; -import ch.systemsx.cisd.openbis.generic.shared.dto.hibernate.SortableNumberBridgeUtils; -import ch.systemsx.cisd.openbis.generic.shared.search.IgnoreCaseAnalyzer; - -/** - * Builder for detailed lucene queries for different entity kinds. - * - * @author Piotr Buczek - */ -public class DetailedQueryBuilder -{ - - private final static Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, - DetailedQueryBuilder.class); - - /** - * @param associations // TODO move to DetailedSearchCriteria - * @throws UserFailureException when some search patterns are incorrect - */ - public static Query createQuery(String userId, DetailedSearchCriteria searchCriteria, - EntityKind entityKind, List<IAssociationCriteria> associations, Map<String, DocValuesType> fieldTypes) - throws UserFailureException - { - final DetailedQueryBuilder builder = new DetailedQueryBuilder(entityKind); - final Query resultQuery = builder.createQuery(userId, searchCriteria, associations, fieldTypes); - operationLog.debug("Lucene detailed query: " + resultQuery.toString()); - return resultQuery; - } - - // - // LuceneDetailedQueryBuilder - // - - private final EntityKind entityKind; - - private DetailedQueryBuilder(EntityKind entityKind) - { - this.entityKind = entityKind; - } - - private Query createQuery(String userId, DetailedSearchCriteria searchCriteria, - List<IAssociationCriteria> associations, Map<String, DocValuesType> fieldTypes) - { - boolean useWildcardSearchMode = searchCriteria.isUseWildcardSearchMode(); - List<DetailedSearchCriterion> criteria = searchCriteria.getCriteria(); - Occur occureCondition = createOccureCondition(searchCriteria.getConnection()); - - Analyzer searchAnalyzer = LuceneQueryBuilder.createSearchAnalyzer(); - BooleanQuery resultQuery = new BooleanQuery(); - for (DetailedSearchCriterion criterion : criteria) - { - List<String> fieldNames = getIndexFieldNames(criterion.getField(), entityKind); - Collection<String> values = criterion.getValues(); - - if (criterion.getTimeZone() == null) - { - List<String> fieldPatterns = new ArrayList<String>(); - List<Analyzer> fieldAnalyzers = new ArrayList<Analyzer>(); - List<Occur> fieldOccur = new ArrayList<Occur>(); - List<String> fieldValueNames = new ArrayList<String>(); - - if (values != null) - { - for (String value : values) - { - for (String fieldName : fieldNames) - { - String fieldPattern = null; - Analyzer fieldAnalyzer = null; - boolean isNumeric = fieldTypes.get(fieldName) == DocValuesType.SORTED_NUMERIC; - if (MetaprojectSearch.isMetaprojectField(fieldName)) - { - String fieldUserQuery = - MetaprojectSearch.getMetaprojectUserQuery(value, userId); - fieldPattern = LuceneQueryBuilder.adaptQuery(fieldUserQuery, - useWildcardSearchMode, false); - fieldAnalyzer = new IgnoreCaseAnalyzer(); - } else if (isNumeric && criterion.getType() != null && SortableNumberBridgeUtils.isValidNumber(value)) - { - fieldPattern = getRangeNumberQuery(criterion.getType(), value, fieldPattern); - fieldAnalyzer = PassThroughAnalyzer.INSTANCE; - } else - { - fieldPattern = LuceneQueryBuilder.adaptQuery(value, useWildcardSearchMode, getFieldSplit(entityKind, fieldName)); - fieldAnalyzer = getFieldAnalyzer(entityKind, fieldName, searchAnalyzer); - } - - fieldPatterns.add(fieldPattern); - fieldAnalyzers.add(fieldAnalyzer); - fieldOccur.add(criterion.isNegated() ? Occur.MUST_NOT : Occur.SHOULD); - fieldValueNames.add(fieldName); - } - } - } - - Query luceneQuery = LuceneQueryBuilder.parseQuery(criterion.getType(), fieldValueNames, - fieldPatterns, fieldAnalyzers, fieldOccur); - resultQuery.add(luceneQuery, occureCondition); - } else - { - if (false == StringUtils.isEmpty(criterion.getValue())) - { - DateRangeCalculator rangeCalculator = new DateRangeCalculator(criterion.getValue(), criterion.getTimeZone(), criterion.getType()); - String fieldName = fieldNames.get(0); - StringEncodingDateBridge bridge = new StringEncodingDateBridge(Resolution.SECOND); - TermRangeQuery q = - TermRangeQuery.newStringRange(fieldName, bridge.objectToString(rangeCalculator.getLowerDate()), - bridge.objectToString(rangeCalculator.getUpperDate()), true, true); - resultQuery.add(q, occureCondition); - } - } - } - - for (IAssociationCriteria association : associations) - { - String fieldName = getIndexFieldName(association); - Query luceneQuery = LuceneQueryBuilder.parseQuery(fieldName, association.getSearchPatterns(), searchAnalyzer); - resultQuery.add(luceneQuery, occureCondition); - } - - return resultQuery; - } - - private String getRangeNumberQuery(CompareType compareType, String value, String fieldPattern) - { - String parsedNumberValue = SortableNumberBridgeUtils.getNumberForLucene(value); - switch (compareType) - { - case LESS_THAN: - return "{* TO " + parsedNumberValue + "}"; - case LESS_THAN_OR_EQUAL: - return "[* TO " + parsedNumberValue + "]"; - case EQUALS: - return "[" + parsedNumberValue + " TO " + parsedNumberValue + "]"; - case MORE_THAN_OR_EQUAL: - return "[" + parsedNumberValue + " TO *]"; - case MORE_THAN: - return "{" + parsedNumberValue + " TO *}"; - } - return fieldPattern; - } - - private Occur createOccureCondition(SearchCriteriaConnection connection) - { - switch (connection) - { - case MATCH_ALL: - return Occur.MUST; - case MATCH_ANY: - return Occur.SHOULD; - default: - throw InternalErr.error("unknown enum " + connection); - } - } - - public static List<String> getIndexFieldNames(List<DetailedSearchCriterion> criteria, EntityKind entityKind) - { - List<String> fieldNames = new ArrayList<String>(); - for (DetailedSearchCriterion criterion : criteria) - { - fieldNames.addAll(getIndexFieldNames(criterion.getField(), entityKind)); - } - return fieldNames; - } - - private static List<String> getIndexFieldNames(DetailedSearchField searchField, EntityKind entityKind) - { - DetailedSearchFieldKind fieldKind = searchField.getKind(); - switch (fieldKind) - { - case ANY_PROPERTY: - return getPropertyIndexFields(searchField, entityKind); - case ANY_FIELD: - List<String> fields = new ArrayList<String>(); - fields.addAll(getPropertyIndexFields(searchField, entityKind)); - fields.addAll(getAllAttributeIndexFieldNames(entityKind)); - return fields; - case REGISTRATOR: - return Arrays.asList(SearchFieldConstants.PREFIX_REGISTRATOR - + SearchFieldConstants.PERSON_USER_ID); - default: - return Arrays.asList(getSimpleFieldIndexName(searchField, entityKind)); - } - } - - private String getIndexFieldName(IAssociationCriteria association) - { - return IndexFieldNameHelper.getAssociationIndexField(entityKind, - association.getEntityKind()); - } - - private final static EnumSet<DetailedSearchFieldKind> simpleFieldKinds = EnumSet.of( - DetailedSearchFieldKind.ATTRIBUTE, DetailedSearchFieldKind.PROPERTY); - - private static String getSimpleFieldIndexName(DetailedSearchField searchField, EntityKind entityKind) - { - assert simpleFieldKinds.contains(searchField.getKind()) : "simple field kind required"; - String indexFieldName = tryGetIndexFieldName(searchField, entityKind); - assert indexFieldName != null; - return indexFieldName; - } - - private static List<String> getAllAttributeIndexFieldNames(EntityKind entityKind) - { - List<String> indexFieldNames = new ArrayList<String>(); - IAttributeSearchFieldKind[] attributeFieldKinds = getAllAttributeFieldKinds(entityKind); - for (IAttributeSearchFieldKind attributeFieldKind : attributeFieldKinds) - { - DetailedSearchField attributeField = - DetailedSearchField.createAttributeField(attributeFieldKind); - indexFieldNames.add(getSimpleFieldIndexName(attributeField, entityKind)); - } - return indexFieldNames; - } - - private static IAttributeSearchFieldKind[] getAllAttributeFieldKinds(EntityKind entityKind) - { - return AttributeSearchFieldKindProvider.getAllAttributeFieldKinds(entityKind); - } - - private static List<String> getPropertyIndexFields(DetailedSearchField searchField, EntityKind entityKind) - { - assert searchField.getKind() != DetailedSearchFieldKind.ATTRIBUTE : "attribute field kind not allowed"; - return getPropertyIndexFieldNames(searchField.getAllEntityPropertyCodesOrNull(), entityKind); - } - - private static List<String> getPropertyIndexFieldNames(List<String> allPropertyCodes, EntityKind entityKind) - { - List<String> indexFieldNames = new ArrayList<String>(); - assert allPropertyCodes != null; - for (String propertyCode : allPropertyCodes) - { - final DetailedSearchField searchField = - DetailedSearchField.createPropertyField(propertyCode); - final String indexFieldName = tryGetIndexFieldName(searchField, entityKind); - assert indexFieldName != null; - indexFieldNames.add(indexFieldName); - } - return indexFieldNames; - } - - // returns the field name in the index for the specified query field - private static String tryGetIndexFieldName(DetailedSearchField searchField, EntityKind entityKind) - { - DetailedSearchFieldKind fieldKind = searchField.getKind(); - switch (fieldKind) - { - case ATTRIBUTE: - return IndexFieldNameHelper.getAttributeIndexField(entityKind, - searchField.getAttributeCode()); - case PROPERTY: - return IndexFieldNameHelper.getPropertyIndexField(searchField.getPropertyCode()); - case ANY_PROPERTY: - case ANY_FIELD: - return null; - default: - throw InternalErr.error("unknown enum " + fieldKind); - } - } - - private static boolean getFieldSplit(EntityKind entityKind, String fieldName) - { - return isSampleOrExperimentIdentifierField(entityKind, fieldName) == false; - } - - private static Analyzer getFieldAnalyzer(EntityKind entityKind, String fieldName, Analyzer defaultAnalyzer) - { - return isSampleOrExperimentIdentifierField(entityKind, fieldName) ? new IgnoreCaseAnalyzer() : defaultAnalyzer; - } - - private static boolean isSampleOrExperimentIdentifierField(EntityKind entityKind, String fieldName) - { - return (EntityKind.SAMPLE.equals(entityKind) || EntityKind.EXPERIMENT.equals(entityKind)) - && SearchFieldConstants.IDENTIFIER.equals(fieldName); - } - -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/IndexFieldNameHelper.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/IndexFieldNameHelper.java deleted file mode 100644 index 1d9665994a2cf1dd8fb2f4c5e8d1da1e5311c807..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/IndexFieldNameHelper.java +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright 2009 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.detailed; - -import static ch.systemsx.cisd.openbis.generic.shared.dto.hibernate.SearchFieldConstants.CODE; -import static ch.systemsx.cisd.openbis.generic.shared.dto.hibernate.SearchFieldConstants.ID; -import static ch.systemsx.cisd.openbis.generic.shared.dto.hibernate.SearchFieldConstants.PERM_ID; - -import ch.systemsx.cisd.common.exceptions.InternalErr; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AssociatedEntityKind; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetAttributeSearchFieldKind; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentAttributeSearchFieldKind; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialAttributeSearchFieldKind; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleAttributeSearchFieldKind; -import ch.systemsx.cisd.openbis.generic.shared.dto.hibernate.SearchFieldConstants; - -/** - * Helper for getting index field names of attributes and properties for detailed entity search.<br> - * - * @author Piotr Buczek - */ -class IndexFieldNameHelper -{ - // associations - - static String getAssociationIndexField(EntityKind entityKind, - AssociatedEntityKind associationKind) - { - switch (associationKind) - { - case EXPERIMENT: - if (entityKind == EntityKind.SAMPLE || entityKind == EntityKind.DATA_SET) - { - return SearchFieldConstants.EXPERIMENT_ID; - } - throw createAssociationNotHandledException(entityKind, associationKind); - - case SAMPLE: - if (entityKind == EntityKind.DATA_SET) - { - return SearchFieldConstants.SAMPLE_ID; - } - throw createAssociationNotHandledException(entityKind, associationKind); - - case DATA_SET: - throw createAssociationNotHandledException(entityKind, associationKind); - - case SAMPLE_CONTAINER: - if (entityKind == EntityKind.SAMPLE) - { - return SearchFieldConstants.CONTAINER_ID; - } - throw createAssociationNotHandledException(entityKind, associationKind); - - case DATA_SET_CONTAINER: - case DATA_SET_PARENT: - case DATA_SET_CHILD: - case SAMPLE_PARENT: - case SAMPLE_CHILD: - case MATERIAL: - // parent-child is a many-to-many connection - it is not handled by lucene index - throw createAssociationNotHandledException(entityKind, associationKind); - } - return null; // shouldn't happen - } - - private static RuntimeException createAssociationNotHandledException(EntityKind entityKind, - AssociatedEntityKind associationKind) - { - return InternalErr.error("Associations between " + entityKind + " and " + associationKind - + " are not supported"); - } - - // properties - - static String getPropertyIndexField(String propertyCode) - { - assert propertyCode != null : "property code is null"; - return SearchFieldConstants.PREFIX_PROPERTIES + propertyCode; - } - - // attributes - - static String getAttributeIndexField(EntityKind entityKind, String attributeCode) - { - switch (entityKind) - { - case DATA_SET: - return getDataSetAttributeIndexField(DataSetAttributeSearchFieldKind - .valueOf(attributeCode)); - case EXPERIMENT: - return getExperimentAttributeIndexField(ExperimentAttributeSearchFieldKind - .valueOf(attributeCode)); - case MATERIAL: - return getMaterialAttributeIndexField(MaterialAttributeSearchFieldKind - .valueOf(attributeCode)); - case SAMPLE: - for (SampleAttributeSearchFieldKind searchFieldKind : SampleAttributeSearchFieldKind.values()) - { - if (searchFieldKind.name().equals(attributeCode)) - { - return getSampleAttributeIndexField(searchFieldKind); - } - } - return attributeCode; - } - return null; // cannot happen - } - - private static String getDataSetAttributeIndexField( - DataSetAttributeSearchFieldKind attributeKind) - { - switch (attributeKind) - { - // common fields - - case CODE: - return CODE; - case DATA_SET_TYPE: - return SearchFieldConstants.PREFIX_ENTITY_TYPE + CODE; - case METAPROJECT: - return SearchFieldConstants.PREFIX_METAPROJECT + SearchFieldConstants.IDENTIFIER; - case REGISTRATION_DATE: - case REGISTRATION_DATE_FROM: - case REGISTRATION_DATE_UNTIL: - return SearchFieldConstants.REGISTRATION_DATE; - case MODIFICATION_DATE: - case MODIFICATION_DATE_FROM: - case MODIFICATION_DATE_UNTIL: - return SearchFieldConstants.MODIFICATION_DATE; - - // physical data set fields - - case LOCATOR_TYPE: - return SearchFieldConstants.PREFIX_LOCATOR_TYPE + CODE; - case LOCATION: - return SearchFieldConstants.LOCATION; - case SHARE_ID: - return SearchFieldConstants.SHARE_ID; - case SIZE: - return SearchFieldConstants.SIZE; - case STORAGE_FORMAT: - return SearchFieldConstants.PREFIX_STORAGE_FORMAT + CODE; - case FILE_TYPE: - return SearchFieldConstants.PREFIX_FILE_FORMAT_TYPE + CODE; - case COMPLETE: - return SearchFieldConstants.COMPLETE; - case STATUS: - return SearchFieldConstants.STATUS; - case ARCHIVING_REQUESTED: - return SearchFieldConstants.ARCHIVING_REQUESTED; - case PRESENT_IN_ARCHIVE: - return SearchFieldConstants.PRESENT_IN_ARCHIVE; - case STORAGE_CONFIRMATION: - return SearchFieldConstants.STORAGE_CONFIRMATION; - case SPEED_HINT: - return SearchFieldConstants.SPEED_HINT; - case EXTERNAL_DMS_CODE: - return SearchFieldConstants.PREFIX_CONTENT_COPY + SearchFieldConstants.PREFIX_EXTERNAL_DMS + CODE; - case EXTERNAL_DMS_LABEL: - return SearchFieldConstants.PREFIX_CONTENT_COPY + SearchFieldConstants.PREFIX_EXTERNAL_DMS + SearchFieldConstants.LABEL; - case EXTERNAL_DMS_ADDRESS: - return SearchFieldConstants.PREFIX_CONTENT_COPY + SearchFieldConstants.PREFIX_EXTERNAL_DMS + SearchFieldConstants.ADDRESS; - case EXTERNAL_DMS_TYPE: - return SearchFieldConstants.PREFIX_CONTENT_COPY + SearchFieldConstants.PREFIX_EXTERNAL_DMS + SearchFieldConstants.ADDRESS_TYPE; - case EXTERNAL_CODE: - return SearchFieldConstants.PREFIX_CONTENT_COPY + SearchFieldConstants.EXTERNAL_CODE; - case PATH: - return SearchFieldConstants.PREFIX_CONTENT_COPY + SearchFieldConstants.PATH; - case COMMIT_HASH: - return SearchFieldConstants.PREFIX_CONTENT_COPY + SearchFieldConstants.GIT_COMMIT_HASH; - case COMMIT_REPOSITORY_ID: - return SearchFieldConstants.PREFIX_CONTENT_COPY + SearchFieldConstants.GIT_REPOSITORY_ID; - case REGISTRATOR_USER_ID: - return SearchFieldConstants.PREFIX_REGISTRATOR + SearchFieldConstants.PERSON_USER_ID; - case REGISTRATOR_FIRST_NAME: - return SearchFieldConstants.PREFIX_REGISTRATOR + SearchFieldConstants.PERSON_FIRST_NAME; - case REGISTRATOR_LAST_NAME: - return SearchFieldConstants.PREFIX_REGISTRATOR + SearchFieldConstants.PERSON_LAST_NAME; - case REGISTRATOR_EMAIL: - return SearchFieldConstants.PREFIX_REGISTRATOR + SearchFieldConstants.PERSON_EMAIL; - case MODIFIER_USER_ID: - return SearchFieldConstants.PREFIX_MODIFIER + SearchFieldConstants.PERSON_USER_ID; - case MODIFIER_FIRST_NAME: - return SearchFieldConstants.PREFIX_MODIFIER + SearchFieldConstants.PERSON_FIRST_NAME; - case MODIFIER_LAST_NAME: - return SearchFieldConstants.PREFIX_MODIFIER + SearchFieldConstants.PERSON_LAST_NAME; - case MODIFIER_EMAIL: - return SearchFieldConstants.PREFIX_MODIFIER + SearchFieldConstants.PERSON_EMAIL; - } - throw new IllegalArgumentException(attributeKind.toString()); - } - - private static String getExperimentAttributeIndexField( - ExperimentAttributeSearchFieldKind attributeKind) - { - switch (attributeKind) - { - case CODE: - return CODE; - case EXPERIMENT_TYPE: - return SearchFieldConstants.PREFIX_ENTITY_TYPE + CODE; - case PERM_ID: - return SearchFieldConstants.PERM_ID; - case IDENTIFIER: - return SearchFieldConstants.IDENTIFIER; - case PROJECT: - return SearchFieldConstants.PREFIX_PROJECT + CODE; - case PROJECT_PERM_ID: - return SearchFieldConstants.PREFIX_PROJECT + PERM_ID; - case PROJECT_SPACE: - return SearchFieldConstants.PREFIX_PROJECT + SearchFieldConstants.PREFIX_SPACE - + CODE; - case METAPROJECT: - return SearchFieldConstants.PREFIX_METAPROJECT + SearchFieldConstants.IDENTIFIER; - case REGISTRATION_DATE: - case REGISTRATION_DATE_FROM: - case REGISTRATION_DATE_UNTIL: - return SearchFieldConstants.REGISTRATION_DATE; - case MODIFICATION_DATE: - case MODIFICATION_DATE_FROM: - case MODIFICATION_DATE_UNTIL: - return SearchFieldConstants.MODIFICATION_DATE; - case REGISTRATOR_USER_ID: - return SearchFieldConstants.PREFIX_REGISTRATOR + SearchFieldConstants.PERSON_USER_ID; - case REGISTRATOR_FIRST_NAME: - return SearchFieldConstants.PREFIX_REGISTRATOR + SearchFieldConstants.PERSON_FIRST_NAME; - case REGISTRATOR_LAST_NAME: - return SearchFieldConstants.PREFIX_REGISTRATOR + SearchFieldConstants.PERSON_LAST_NAME; - case REGISTRATOR_EMAIL: - return SearchFieldConstants.PREFIX_REGISTRATOR + SearchFieldConstants.PERSON_EMAIL; - case MODIFIER_USER_ID: - return SearchFieldConstants.PREFIX_MODIFIER + SearchFieldConstants.PERSON_USER_ID; - case MODIFIER_FIRST_NAME: - return SearchFieldConstants.PREFIX_MODIFIER + SearchFieldConstants.PERSON_FIRST_NAME; - case MODIFIER_LAST_NAME: - return SearchFieldConstants.PREFIX_MODIFIER + SearchFieldConstants.PERSON_LAST_NAME; - case MODIFIER_EMAIL: - return SearchFieldConstants.PREFIX_MODIFIER + SearchFieldConstants.PERSON_EMAIL; - } - return null; // cannot happen - } - - private static String getMaterialAttributeIndexField( - MaterialAttributeSearchFieldKind attributeKind) - { - switch (attributeKind) - { - case ID: - return ID; - case PERM_ID: - return PERM_ID; - case CODE: - return CODE; - case MATERIAL_TYPE: - return SearchFieldConstants.PREFIX_ENTITY_TYPE + CODE; - case METAPROJECT: - return SearchFieldConstants.PREFIX_METAPROJECT + SearchFieldConstants.IDENTIFIER; - case REGISTRATION_DATE: - case REGISTRATION_DATE_FROM: - case REGISTRATION_DATE_UNTIL: - return SearchFieldConstants.REGISTRATION_DATE; - case MODIFICATION_DATE: - case MODIFICATION_DATE_FROM: - case MODIFICATION_DATE_UNTIL: - return SearchFieldConstants.MODIFICATION_DATE; - case REGISTRATOR_USER_ID: - return SearchFieldConstants.PREFIX_REGISTRATOR + SearchFieldConstants.PERSON_USER_ID; - case REGISTRATOR_FIRST_NAME: - return SearchFieldConstants.PREFIX_REGISTRATOR + SearchFieldConstants.PERSON_FIRST_NAME; - case REGISTRATOR_LAST_NAME: - return SearchFieldConstants.PREFIX_REGISTRATOR + SearchFieldConstants.PERSON_LAST_NAME; - case REGISTRATOR_EMAIL: - return SearchFieldConstants.PREFIX_REGISTRATOR + SearchFieldConstants.PERSON_EMAIL; - case MODIFIER_USER_ID: - return SearchFieldConstants.PREFIX_MODIFIER + SearchFieldConstants.PERSON_USER_ID; - case MODIFIER_FIRST_NAME: - return SearchFieldConstants.PREFIX_MODIFIER + SearchFieldConstants.PERSON_FIRST_NAME; - case MODIFIER_LAST_NAME: - return SearchFieldConstants.PREFIX_MODIFIER + SearchFieldConstants.PERSON_LAST_NAME; - case MODIFIER_EMAIL: - return SearchFieldConstants.PREFIX_MODIFIER + SearchFieldConstants.PERSON_EMAIL; - } - return null; // cannot happen - } - - private static String getSampleAttributeIndexField(SampleAttributeSearchFieldKind attributeKind) - { - switch (attributeKind) - { - case CODE: - return CODE; - case SAMPLE_TYPE: - return SearchFieldConstants.PREFIX_ENTITY_TYPE + CODE; - case PERM_ID: - return SearchFieldConstants.PERM_ID; - case IDENTIFIER: - return SearchFieldConstants.IDENTIFIER; - case SPACE: - return SearchFieldConstants.PREFIX_SPACE + CODE; - case PROJECT: - return SearchFieldConstants.PREFIX_PROJECT + CODE; - case PROJECT_PERM_ID: - return SearchFieldConstants.PREFIX_PROJECT + PERM_ID; - case PROJECT_SPACE: - return SearchFieldConstants.PREFIX_PROJECT + SearchFieldConstants.PREFIX_SPACE + CODE; - case METAPROJECT: - return SearchFieldConstants.PREFIX_METAPROJECT + SearchFieldConstants.IDENTIFIER; - case REGISTRATION_DATE: - case REGISTRATION_DATE_FROM: - case REGISTRATION_DATE_UNTIL: - return SearchFieldConstants.REGISTRATION_DATE; - case MODIFICATION_DATE: - case MODIFICATION_DATE_FROM: - case MODIFICATION_DATE_UNTIL: - return SearchFieldConstants.MODIFICATION_DATE; - case REGISTRATOR_USER_ID: - return SearchFieldConstants.PREFIX_REGISTRATOR + SearchFieldConstants.PERSON_USER_ID; - case REGISTRATOR_FIRST_NAME: - return SearchFieldConstants.PREFIX_REGISTRATOR + SearchFieldConstants.PERSON_FIRST_NAME; - case REGISTRATOR_LAST_NAME: - return SearchFieldConstants.PREFIX_REGISTRATOR + SearchFieldConstants.PERSON_LAST_NAME; - case REGISTRATOR_EMAIL: - return SearchFieldConstants.PREFIX_REGISTRATOR + SearchFieldConstants.PERSON_EMAIL; - case MODIFIER_USER_ID: - return SearchFieldConstants.PREFIX_MODIFIER + SearchFieldConstants.PERSON_USER_ID; - case MODIFIER_FIRST_NAME: - return SearchFieldConstants.PREFIX_MODIFIER + SearchFieldConstants.PERSON_FIRST_NAME; - case MODIFIER_LAST_NAME: - return SearchFieldConstants.PREFIX_MODIFIER + SearchFieldConstants.PERSON_LAST_NAME; - case MODIFIER_EMAIL: - return SearchFieldConstants.PREFIX_MODIFIER + SearchFieldConstants.PERSON_EMAIL; - } - throw new IllegalArgumentException(attributeKind.toString()); - } -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/id/experiment/.gitignore b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/id/experiment/.gitignore deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/id/sample/.gitignore b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/id/sample/.gitignore deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/DummyDynamicPropertyEvaluationRunnable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/DummyDynamicPropertyEvaluationRunnable.java deleted file mode 100644 index aca10e1dcfe5d4b370d45ce76450671980df18c3..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/DummyDynamicPropertyEvaluationRunnable.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2008 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property; - -import org.apache.log4j.Logger; -import org.hibernate.SessionFactory; -import org.springframework.orm.hibernate5.support.HibernateDaoSupport; - -import ch.systemsx.cisd.common.logging.LogCategory; -import ch.systemsx.cisd.common.logging.LogFactory; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.DynamicPropertyEvaluationOperation; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDynamicPropertyEvaluationScheduler; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IFullTextIndexUpdateScheduler; - -/** - * @author Piotr Buczek - */ -public final class DummyDynamicPropertyEvaluationRunnable extends HibernateDaoSupport implements - IDynamicPropertyEvaluationScheduler, Runnable -{ - - private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, - DummyDynamicPropertyEvaluationRunnable.class); - - public DummyDynamicPropertyEvaluationRunnable(final SessionFactory sessionFactory, - final IFullTextIndexUpdateScheduler fullTextIFullTextIndexUpdateScheduler) - { - setSessionFactory(sessionFactory); - operationLog.debug("dummy property evaluator created"); - } - - @Override - public void scheduleUpdate(DynamicPropertyEvaluationOperation operation) - { - operationLog.debug("scheduling " + operation); - } - - // - // Runnable - // - - @Override - public final void run() - { - operationLog.debug("started"); - } - -} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/DynamicPropertyEvaluationRunnable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/DynamicPropertyEvaluationRunnable.java index 4bd18bec6a0e56ad9c4e92297777ff4c188119d7..8bec5580dc9d186c48f9e6a0116a502c19b4ee0f 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/DynamicPropertyEvaluationRunnable.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/DynamicPropertyEvaluationRunnable.java @@ -17,8 +17,6 @@ package ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property; import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedList; import java.util.List; import org.apache.commons.lang3.time.StopWatch; @@ -32,8 +30,6 @@ import ch.systemsx.cisd.common.logging.LogFactory; import ch.systemsx.cisd.openbis.generic.server.dataaccess.DynamicPropertyEvaluationOperation; import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory; import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDynamicPropertyEvaluationSchedulerWithQueue; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IFullTextIndexUpdateScheduler; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IndexUpdateOperation; import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityInformationWithPropertiesHolder; import ch.systemsx.cisd.openbis.generic.shared.managed_property.IManagedPropertyEvaluatorFactory; diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/calculator/AbstractEntityAdaptor.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/calculator/AbstractEntityAdaptor.java index eb6892b0bfe99467be5cc8db6c7a45e66f6d63d3..fc0e2f3861a1f89efa22e93e278082126927fc18 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/calculator/AbstractEntityAdaptor.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/calculator/AbstractEntityAdaptor.java @@ -21,22 +21,10 @@ import java.util.HashMap; import java.util.Map; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.lucene.index.Term; -import org.apache.lucene.search.BooleanClause; -import org.apache.lucene.search.BooleanQuery; -import org.apache.lucene.search.Query; -import org.apache.lucene.search.RegexpQuery; -import org.hibernate.ScrollMode; -import org.hibernate.ScrollableResults; -import org.hibernate.Session; -import org.hibernate.search.FullTextQuery; -import org.hibernate.search.FullTextSession; -import org.hibernate.search.Search; import ch.systemsx.cisd.common.reflection.ModifiedShortPrefixToStringStyle; import ch.systemsx.cisd.common.resource.IReleasable; import ch.systemsx.cisd.common.resource.Resources; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.LuceneQueryBuilder; import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.IDynamicPropertyEvaluator; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialIdentifier; import ch.systemsx.cisd.openbis.generic.shared.dto.EntityPropertyPE; @@ -204,35 +192,6 @@ public class AbstractEntityAdaptor implements IEntityAdaptor, IReleasable return propertiesMap().values(); } - protected Query regexpConstraint(String field, String value) - { - return new RegexpQuery(new Term(field, value.toLowerCase())); - } - - protected Query constraint(String field, String value) - { - return LuceneQueryBuilder.parseQuery(field, value, - LuceneQueryBuilder.createSearchAnalyzer()); - } - - protected Query and(Query... queries) - { - BooleanQuery query = new BooleanQuery(); - for (Query subquery : queries) - { - query.add(subquery, BooleanClause.Occur.MUST); - } - return query; - } - - protected ScrollableResults execute(Query query, Class<?> resultClass, Session session) - { - FullTextSession fullTextSession = Search.getFullTextSession(session); - FullTextQuery ftQuery = fullTextSession.createFullTextQuery(query, resultClass); - ftQuery.setFetchSize(10); - return ftQuery.scroll(ScrollMode.FORWARD_ONLY); - } - @Override public void release() { diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/calculator/ExperimentAdaptor.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/calculator/ExperimentAdaptor.java index bbfda1d647d48b6a1225e23908cfa367b8512cd8..ee3107777fa13f3df01c7721bba873c6daeefae0 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/calculator/ExperimentAdaptor.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/calculator/ExperimentAdaptor.java @@ -16,18 +16,14 @@ package ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator; -import org.apache.lucene.search.Query; -import org.hibernate.ScrollableResults; +import ch.systemsx.cisd.common.exceptions.NotImplementedException; import org.hibernate.Session; import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.IDynamicPropertyEvaluator; import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.api.IDataAdaptor; import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.api.IExperimentAdaptor; import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.api.ISampleAdaptor; -import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE; import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE; -import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE; -import ch.systemsx.cisd.openbis.generic.shared.dto.hibernate.SearchFieldConstants; import ch.systemsx.cisd.openbis.generic.shared.hotdeploy_plugins.api.IEntityAdaptor; /** @@ -64,40 +60,28 @@ public class ExperimentAdaptor extends AbstractEntityAdaptor implements IExperim @Override public Iterable<ISampleAdaptor> samples() { - return samplesOfType(ENTITY_TYPE_ANY_CODE_REGEXP); + //TODO Lucene: Method to be implemented if is used after removing lucene. + throw new NotImplementedException("TODO Lucene: Method to be implemented if is used after removing lucene."); } @Override public Iterable<ISampleAdaptor> samplesOfType(String typeRegexp) { - Query typeConstraint = regexpConstraint(ENTITY_TYPE_CODE_FIELD, typeRegexp.toLowerCase()); - Query experimentCodeConstraint = - constraint(SearchFieldConstants.EXPERIMENT_ID, Long.toString(experimentPE.getId())); - Query query = and(typeConstraint, experimentCodeConstraint); - - ScrollableResults results = execute(query, SamplePE.class, session); - EntityAdaptorIterator<ISampleAdaptor> iterator = new EntityAdaptorIterator<ISampleAdaptor>(results, evaluator, session); - getResources().add(iterator); - return iterator; + //TODO Lucene: Method to be implemented if is used after removing lucene. + throw new NotImplementedException("TODO Lucene: Method to be implemented if is used after removing lucene."); } @Override public Iterable<IDataAdaptor> dataSets() { - return dataSetsOfType(ENTITY_TYPE_ANY_CODE_REGEXP); + //TODO Lucene: Method to be implemented if is used after removing lucene. + throw new NotImplementedException("TODO Lucene: Method to be implemented if is used after removing lucene."); } @Override public Iterable<IDataAdaptor> dataSetsOfType(String typeRegexp) { - Query typeConstraint = regexpConstraint(ENTITY_TYPE_CODE_FIELD, typeRegexp.toLowerCase()); - Query experimentCodeConstraint = - constraint(SearchFieldConstants.EXPERIMENT_ID, Long.toString(experimentPE.getId())); - Query query = and(typeConstraint, experimentCodeConstraint); - - ScrollableResults results = execute(query, DataPE.class, session); - EntityAdaptorIterator<IDataAdaptor> iterator = new EntityAdaptorIterator<IDataAdaptor>(results, evaluator, session); - getResources().add(iterator); - return iterator; + //TODO Lucene: Method to be implemented if is used after removing lucene. + throw new NotImplementedException("TODO Lucene: Method to be implemented if is used after removing lucene."); } } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/calculator/SampleAdaptor.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/calculator/SampleAdaptor.java index e1382715d3ee6d59cc5405793bed8b4ba0975753..62942c8c34f83898adc2026ba2b83ef814021f03 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/calculator/SampleAdaptor.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/calculator/SampleAdaptor.java @@ -16,8 +16,7 @@ package ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator; -import org.apache.lucene.search.Query; -import org.hibernate.ScrollableResults; +import ch.systemsx.cisd.common.exceptions.NotImplementedException; import org.hibernate.Session; import ch.systemsx.cisd.common.resource.ReleasableIterable; @@ -25,9 +24,7 @@ import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.IDyna import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.api.IDataAdaptor; import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.api.IExperimentAdaptor; import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.api.ISampleAdaptor; -import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE; import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE; -import ch.systemsx.cisd.openbis.generic.shared.dto.hibernate.SearchFieldConstants; import ch.systemsx.cisd.openbis.generic.shared.hotdeploy_plugins.api.IEntityAdaptor; /** @@ -118,45 +115,29 @@ public class SampleAdaptor extends AbstractEntityAdaptor implements ISampleAdapt @Override public Iterable<ISampleAdaptor> contained() { - return containedOfType(ENTITY_TYPE_ANY_CODE_REGEXP); + //TODO Lucene: Method to be implemented if is used after removing lucene. + throw new NotImplementedException("TODO Lucene: Method to be implemented if is used after removing lucene."); } @Override public Iterable<ISampleAdaptor> containedOfType(String typeCodeRegexp) { - Query typeConstraint = - regexpConstraint(ENTITY_TYPE_CODE_FIELD, typeCodeRegexp.toLowerCase()); - Query containerConstraint = - constraint(SearchFieldConstants.CONTAINER_ID, Long.toString(samplePE.getId())); - Query query = and(typeConstraint, containerConstraint); - - ScrollableResults results = execute(query, SamplePE.class, session); - EntityAdaptorIterator<ISampleAdaptor> iterator = - new EntityAdaptorIterator<ISampleAdaptor>(results, evaluator, session); - getResources().add(iterator); - return iterator; + //TODO Lucene: Method to be implemented if is used after removing lucene. + throw new NotImplementedException("TODO Lucene: Method to be implemented if is used after removing lucene."); } @Override public Iterable<IDataAdaptor> dataSets() { - return dataSetsOfType(ENTITY_TYPE_ANY_CODE_REGEXP); + //TODO Lucene: Method to be implemented if is used after removing lucene. + throw new NotImplementedException("TODO Lucene: Method to be implemented if is used after removing lucene."); } @Override public Iterable<IDataAdaptor> dataSetsOfType(String typeCodeRegexp) { - Query typeConstraint = - regexpConstraint(ENTITY_TYPE_CODE_FIELD, typeCodeRegexp.toLowerCase()); - Query sampleConstraint = - constraint(SearchFieldConstants.SAMPLE_ID, Long.toString(samplePE.getId())); - Query query = and(typeConstraint, sampleConstraint); - - ScrollableResults results = execute(query, DataPE.class, session); - EntityAdaptorIterator<IDataAdaptor> iterator = - new EntityAdaptorIterator<IDataAdaptor>(results, evaluator, session); - getResources().add(iterator); - return iterator; + //TODO Lucene: Method to be implemented if is used after removing lucene. + throw new NotImplementedException("TODO Lucene: Method to be implemented if is used after removing lucene."); } } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/util/UpdateUtils.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/util/UpdateUtils.java index 5a9ee1603697e33bb7c9f41dfee6cdd1a7d5b725..8822a47a9f6861b8a95e2dadae01d7f4b67bb4c5 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/util/UpdateUtils.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/util/UpdateUtils.java @@ -18,18 +18,12 @@ package ch.systemsx.cisd.openbis.generic.server.dataaccess.util; import java.util.Date; -import org.apache.log4j.Logger; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.type.DbTimestampType; import org.hibernate.type.TimestampType; -import org.springframework.beans.factory.BeanFactory; -import ch.systemsx.cisd.common.collection.IExtendedBlockingQueue; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.DynamicPropertyEvaluationOperation; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.DynamicPropertyEvaluationScheduler; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.FullTextIndexUpdater; /** * @author Franz-Josef Elmer @@ -38,43 +32,6 @@ public class UpdateUtils { private static final TimestampType TIMESTAMP_TYPE = new DbTimestampType(); - public static void waitUntilIndexUpdaterIsIdle(BeanFactory applicationContext, Logger operationLog) - { - FullTextIndexUpdater indexUpdater = (FullTextIndexUpdater) applicationContext.getBean("full-text-index-updater"); - DynamicPropertyEvaluationScheduler dynamicPropertyScheduler = - (DynamicPropertyEvaluationScheduler) applicationContext.getBean("dynamic-property-scheduler"); - - if (indexUpdater != null) - { - while (true) - { - IExtendedBlockingQueue<DynamicPropertyEvaluationOperation> dynamicPropertiesQueue = dynamicPropertyScheduler.getEvaluatorQueue(); - int indexingQueueSize = indexUpdater.getQueueSize(); - - try - { - if (dynamicPropertiesQueue != null && dynamicPropertiesQueue.size() > 0) - { - operationLog.info("Waiting on dynamic properties updater. Still " + dynamicPropertiesQueue.size() - + " update operations in the queue."); - Thread.sleep(1000); - } else if (indexingQueueSize > 0) - { - operationLog.info("Waiting on index updater. Still " + indexingQueueSize + " update operations in the queue."); - Thread.sleep(1000); - } else - { - return; - } - } catch (Exception ex) - { - // silently ignore - return; - } - } - } - } - public static Date getTransactionTimeStamp(SessionFactory sessionFactory) { Session currentSession = sessionFactory.getCurrentSession(); diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ProjectSampleTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ProjectSampleTest.java index 47680b279f87ef1bf684374f01276a6819d3b7c0..dda546ceaf3f0c7dd6b014ab0d0c447135670d69 100644 --- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ProjectSampleTest.java +++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ProjectSampleTest.java @@ -132,7 +132,6 @@ public class ProjectSampleTest extends BaseTest createSamples(systemSessionToken, space1, project1inSpace1, null, "SAMPLE3", "SAMPLE4"); createSamples(systemSessionToken, space2, project2inSpace2, null, "SAMPLE5", "SAMPLE6"); waitAtLeastASecond(); // to allow checks on modification time stamps - UpdateUtils.waitUntilIndexUpdaterIsIdle(applicationContext, operationLog); SessionBuilder session = aSession().withInstanceRole(RoleCode.ADMIN); adminUser = session.getUserID(); adminSessionToken = create(session); diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/index/RemoveFromIndexState.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/index/RemoveFromIndexState.java index c6e32025cc82b2314acafae9df879d9cdc5924e5..6549ae8891d840046a94a2b50ba58dc536b5c608 100644 --- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/index/RemoveFromIndexState.java +++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/index/RemoveFromIndexState.java @@ -18,12 +18,6 @@ package ch.ethz.sis.openbis.systemtest.asapi.v3.index; import java.util.ArrayList; import java.util.Collection; -import java.util.List; - -import ch.systemsx.cisd.openbis.generic.server.CommonServiceProvider; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.FullTextIndexUpdater; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IndexUpdateOperation; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IndexUpdateOperation.IndexUpdateOperationKind; /** * @author pkupczyk @@ -38,16 +32,6 @@ public class RemoveFromIndexState extends IndexState private static Collection<RemoveFromIndexOperation> createOperations() { - FullTextIndexUpdater indexUpdater = (FullTextIndexUpdater) CommonServiceProvider.tryToGetBean("full-text-index-updater"); - Collection<IndexUpdateOperation> updateOperations = indexUpdater.getQueue(); - List<RemoveFromIndexOperation> removeOperations = new ArrayList<RemoveFromIndexOperation>(); - - for (IndexUpdateOperation updateOperation : updateOperations) { - if (IndexUpdateOperationKind.REMOVE.equals(updateOperation.getOperationKind())) { - removeOperations.add(new RemoveFromIndexOperation(updateOperation)); - } - } - - return removeOperations; + return new ArrayList<>(); } } diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/DefaultFullTextIndexerTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/DefaultFullTextIndexerTest.java deleted file mode 100644 index d6ea025fcffcbff54518f9713344396b78345162..0000000000000000000000000000000000000000 --- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/DefaultFullTextIndexerTest.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright 2013 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -import java.util.Arrays; - -import org.apache.log4j.Level; -import org.hamcrest.BaseMatcher; -import org.hamcrest.Description; -import org.hibernate.Criteria; -import org.hibernate.Transaction; -import org.hibernate.criterion.Criterion; -import org.hibernate.criterion.Order; -import org.hibernate.criterion.Projection; -import org.hibernate.search.FullTextSession; -import org.hibernate.search.SearchFactory; -import org.jmock.Expectations; -import org.jmock.Mockery; -import org.jmock.internal.NamedSequence; -import org.testng.AssertJUnit; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import ch.systemsx.cisd.common.logging.BufferedAppender; -import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE; - -/** - * @author Franz-Josef Elmer - */ -public class DefaultFullTextIndexerTest extends AssertJUnit -{ - private BufferedAppender logRecorder; - - private Mockery context; - - private Criteria criteria; - - private DefaultFullTextIndexer indexer; - - private FullTextSession session; - - private Transaction transaction; - - private NamedSequence criteriaListSequence; - - private SearchFactory searchFactory; - - private SamplePE exampleEntity; - - @BeforeMethod - public final void setUp() - { - logRecorder = new BufferedAppender("%-5p %c - %m%n", Level.INFO); - context = new Mockery(); - criteria = context.mock(Criteria.class); - session = context.mock(FullTextSession.class); - transaction = context.mock(Transaction.class); - searchFactory = context.mock(SearchFactory.class); - indexer = new DefaultFullTextIndexer(2); - criteriaListSequence = new NamedSequence("criteria.list"); - exampleEntity = new SamplePE(); - exampleEntity.setCode("1"); - } - - @AfterMethod - public void tearDown() - { - context.assertIsSatisfied(); - } - - @Test - public void testDoFullTextIndexForNone() - { - prepareBeginTransaction(); - prepareGetAllIds(); - prepareCommit(); - - indexer.doFullTextIndex(session, SamplePE.class); - - assertEquals( - getEodSqlUtilsWarnString() - + "INFO OPERATION.DefaultFullTextIndexer - ... got 0 'SamplePE' ids...\n" - + "INFO OPERATION.DefaultFullTextIndexer - " - + "'SamplePE' index complete. 0 entities have been indexed.", - logRecorder.getLogContent()); - context.assertIsSatisfied(); - } - - private String getEodSqlUtilsWarnString() - { - return "WARN TRACKING.EodSqlUtils - Attempt to create an EodSql managed transaction with an underlying transaction that has no JDBC context: transaction\n"; - } - - @Test - public void testDoFullTextIndexInOneBatchesForOne() - { - prepareBeginTransaction(); - prepareGetAllIds(42L); - prepareListEntities(42L, Integer.MAX_VALUE); - prepareIndexEntities(); - prepareCommit(); - - indexer.doFullTextIndex(session, SamplePE.class); - - assertEquals(getEodSqlUtilsWarnString() + "INFO OPERATION.DefaultFullTextIndexer - ... got 1 'SamplePE' ids...\n" - + "INFO OPERATION.DefaultFullTextIndexer - " - + "1/1 SamplePEs have been indexed...\n" - + "INFO OPERATION.DefaultFullTextIndexer - " - + "'SamplePE' index complete. 1 entities have been indexed.", - logRecorder.getLogContent()); - context.assertIsSatisfied(); - } - - @Test - public void testDoFullTextIndexInOneBatchesForTwo() - { - prepareBeginTransaction(); - prepareGetAllIds(42L, 43L); - prepareListEntities(42L, Integer.MAX_VALUE); - prepareIndexEntities(); - prepareCommit(); - - indexer.doFullTextIndex(session, SamplePE.class); - - assertEquals(getEodSqlUtilsWarnString() + "INFO OPERATION.DefaultFullTextIndexer - ... got 2 'SamplePE' ids...\n" - + "INFO OPERATION.DefaultFullTextIndexer - " - + "2/2 SamplePEs have been indexed...\n" - + "INFO OPERATION.DefaultFullTextIndexer - " - + "'SamplePE' index complete. 2 entities have been indexed.", - logRecorder.getLogContent()); - context.assertIsSatisfied(); - } - - @Test - public void testDoFullTextIndexInTwoBatchesWithThree() - { - prepareBeginTransaction(); - prepareGetAllIds(42L, 43L, 50L); - prepareListEntities(42L, 50L); - prepareIndexEntities(); - prepareListEntities(50L, Integer.MAX_VALUE); - prepareIndexEntities(); - prepareCommit(); - - indexer.doFullTextIndex(session, SamplePE.class); - - assertEquals(getEodSqlUtilsWarnString() + "INFO OPERATION.DefaultFullTextIndexer - ... got 3 'SamplePE' ids...\n" - + "INFO OPERATION.DefaultFullTextIndexer - " - + "2/3 SamplePEs have been indexed...\n" - + "INFO OPERATION.DefaultFullTextIndexer - " - + "3/3 SamplePEs have been indexed...\n" - + "INFO OPERATION.DefaultFullTextIndexer - " - + "'SamplePE' index complete. 3 entities have been indexed.", - logRecorder.getLogContent()); - context.assertIsSatisfied(); - } - - @Test - public void testDoFullTextIndexInTwoBatchesWithFour() - { - prepareBeginTransaction(); - prepareGetAllIds(42L, 43L, 50L, 52L); - prepareListEntities(42L, 50L); - prepareIndexEntities(); - prepareListEntities(50L, Integer.MAX_VALUE); - prepareIndexEntities(); - prepareCommit(); - - indexer.doFullTextIndex(session, SamplePE.class); - - assertEquals(getEodSqlUtilsWarnString() + "INFO OPERATION.DefaultFullTextIndexer - ... got 4 'SamplePE' ids...\n" - + "INFO OPERATION.DefaultFullTextIndexer - " - + "2/4 SamplePEs have been indexed...\n" - + "INFO OPERATION.DefaultFullTextIndexer - " - + "4/4 SamplePEs have been indexed...\n" - + "INFO OPERATION.DefaultFullTextIndexer - " - + "'SamplePE' index complete. 4 entities have been indexed.", - logRecorder.getLogContent()); - context.assertIsSatisfied(); - } - - private void prepareBeginTransaction() - { - context.checking(new Expectations() - { - { - one(session).beginTransaction(); - will(returnValue(transaction)); - } - }); - } - - private void prepareGetAllIds(final Long... ids) - { - context.checking(new Expectations() - { - { - one(session).createCriteria(SamplePE.class); - will(returnValue(criteria)); - - one(criteria).setProjection(with(any(Projection.class))); - will(returnValue(criteria)); - - one(criteria).addOrder(with(any(Order.class))); - will(returnValue(criteria)); - - one(criteria).list(); - will(returnValue(Arrays.asList(ids))); - inSequence(criteriaListSequence); - } - }); - } - - private void prepareListEntities(final long minId, final long maxId) - { - context.checking(new Expectations() - { - { - one(session).createCriteria(SamplePE.class); - will(returnValue(criteria)); - - one(criteria).add(with(new BaseMatcher<Criterion>() - { - @Override - public boolean matches(Object item) - { - assertEquals("id>=" + minId, String.valueOf(item)); - return true; - } - - @Override - public void describeTo(Description description) - { - description.appendText(">= " + minId); - } - })); - will(returnValue(criteria)); - - one(criteria).add(with(new BaseMatcher<Criterion>() - { - @Override - public boolean matches(Object item) - { - assertEquals("id<" + maxId, String.valueOf(item)); - return true; - } - - @Override - public void describeTo(Description description) - { - description.appendText("< " + maxId); - } - })); - will(returnValue(criteria)); - - one(criteria).list(); - will(returnValue(Arrays.asList(exampleEntity))); - inSequence(criteriaListSequence); - } - }); - } - - private void prepareIndexEntities() - { - context.checking(new Expectations() - { - { - one(session).index(exampleEntity); - one(session).flushToIndexes(); - one(session).clear(); - } - }); - } - - private void prepareCommit() - { - context.checking(new Expectations() - { - { - one(session).getSearchFactory(); - will(returnValue(searchFactory)); - - one(searchFactory).optimize(SamplePE.class); - one(transaction).commit(); - } - }); - } -} diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/LuceneQueryBuilderTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/LuceneQueryBuilderTest.java deleted file mode 100644 index a0bb9a4b513da2a6a2cf652dc7a49f632ab04c3a..0000000000000000000000000000000000000000 --- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/LuceneQueryBuilderTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2009 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -import org.testng.AssertJUnit; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import ch.rinn.restrictions.Friend; - -/** - * @author Tomasz Pylak - */ -@Friend(toClasses = LuceneQueryBuilder.class) -public class LuceneQueryBuilderTest extends AssertJUnit -{ - @DataProvider(name = "basicModeQueries") - protected Object[][] getQueriesToTestInBasicMode() - { - return new Object[][] - { - { "abc", "(*abc*)" }, - { "code:CP registrator:Joe", "(*code\\:CP*) (*registrator\\:Joe*)" }, - { "ab#c OR d", "(*ab* AND *c*) OR (*d*)" } }; - } - - @DataProvider(name = "wildcardModeQueries") - protected Object[][] getQueriesToTestInWildcardMode() - { - return new Object[][] - { - { "abc", "abc" }, - { "code:CP registrator:Joe", "code\\:CP registrator\\:Joe" }, - { "*ab#c OR d", "*ab#c OR d" } }; - } - - @Test(dataProvider = "basicModeQueries") - public final void testBasicSearchMode(String originalQuery, String adaptedQuery) - { - String query = LuceneQueryBuilder.adaptQuery(originalQuery, false); - assertEquals(adaptedQuery, query); - } - - @Test(dataProvider = "wildcardModeQueries") - public final void testWildcardSearchMode(String originalQuery, String adaptedQuery) - { - String query = LuceneQueryBuilder.adaptQuery(originalQuery, true); - assertEquals(adaptedQuery, query); - } - -} diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/PackageBasedIndexedEntityFinderTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/PackageBasedIndexedEntityFinderTest.java deleted file mode 100644 index d8735080c7513e1deb77d46da572b222455f8d9a..0000000000000000000000000000000000000000 --- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/PackageBasedIndexedEntityFinderTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2008 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search; - -import static org.testng.AssertJUnit.assertEquals; -import static org.testng.AssertJUnit.assertFalse; -import static org.testng.AssertJUnit.assertTrue; -import static org.testng.AssertJUnit.fail; - -import java.util.Set; - -import org.testng.annotations.Test; - -import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE; -import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE; -import ch.systemsx.cisd.openbis.generic.shared.dto.MaterialPE; -import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE; -import ch.systemsx.cisd.openbis.generic.shared.dto.SampleTypePE; - -/** - * Test cases for the {@link PackageBasedIndexedEntityFinder}. - * - * @author Christian Ribeaud - */ -public final class PackageBasedIndexedEntityFinderTest -{ - - @Test - public final void testGetIndexedEntitiesFailed() - { - boolean fail = true; - // Null value - try - { - new PackageBasedIndexedEntityFinder(null); - } catch (final AssertionError e) - { - fail = false; - } - assertFalse(fail); - // Package does not exist. - try - { - new PackageBasedIndexedEntityFinder("does.not.exist"); - fail("'" + IllegalArgumentException.class.getName() + "' expected."); - } catch (final IllegalArgumentException e) - { - // Nothing to do here. - } - } - - @Test - public final void testGetIndexedEntities() - { - final PackageBasedIndexedEntityFinder entityFinder = - new PackageBasedIndexedEntityFinder("ch.systemsx.cisd.openbis.generic.shared.dto"); - final Set<Class<?>> entities = entityFinder.getIndexedEntities(); - assertEquals(5, entities.size()); - assertTrue(entities.contains(SamplePE.class)); - assertTrue(entities.contains(SampleTypePE.class)); - assertTrue(entities.contains(ExperimentPE.class)); - assertTrue(entities.contains(MaterialPE.class)); - assertTrue(entities.contains(DataPE.class)); - } -} diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/util/TestInitializer.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/util/TestInitializer.java index d0e62218baa931da57957ef46efcdc2ffd208ad5..15459c5f701d352a9c5560c6102eb2da3e9ea8b0 100644 --- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/util/TestInitializer.java +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/util/TestInitializer.java @@ -17,27 +17,21 @@ package ch.systemsx.cisd.openbis.generic.server.util; import java.io.File; -import java.io.FileFilter; -import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.List; -import org.apache.commons.io.FileUtils; +import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.IndexCreationUtil; import org.apache.log4j.Logger; import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel; -import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked; import ch.systemsx.cisd.common.filesystem.FileUtilities; import ch.systemsx.cisd.common.logging.LogCategory; import ch.systemsx.cisd.common.logging.LogFactory; import ch.systemsx.cisd.common.logging.LogInitializer; import ch.systemsx.cisd.common.process.ProcessExecutionHelper; import ch.systemsx.cisd.dbmigration.postgresql.DumpPreparator; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.IndexCreationUtil; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.FullTextIndexerRunnable; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IndexMode; /** * @author Franz-Josef Elmer @@ -68,27 +62,27 @@ public class TestInitializer public static void initWithoutIndex() { - init(IndexMode.NO_INDEX, getScriptFolderTestDB()); + init(getScriptFolderTestDB()); } public static void initWithIndex() { - init(IndexMode.SKIP_IF_MARKER_FOUND, getScriptFolderTestDB()); + initWithoutIndex(); } public static void initEmptyDbNoIndex() { - init(IndexMode.NO_INDEX, getScriptFolderEmptyDB()); + init(getScriptFolderEmptyDB()); } public static void initEmptyDbWithIndex() { - init(IndexMode.SKIP_IF_MARKER_FOUND, getScriptFolderEmptyDB()); + initEmptyDbNoIndex(); } private static boolean firstTry = true; - private static void init(IndexMode hibernateIndexMode, String scriptFolder) + private static void init(String scriptFolder) { LogInitializer.init(); @@ -155,10 +149,6 @@ public class TestInitializer System.setProperty("database.create-from-scratch", String.valueOf(getCreateDBFromScratch())); System.setProperty("database.kind", getDBKind()); System.setProperty("script-folder", scriptFolder); - System.setProperty("hibernate.search.index-mode", hibernateIndexMode.name()); - System.setProperty("hibernate.search.index-base", LUCENE_INDEX_PATH); - System.setProperty("hibernate.search.worker.execution", "sync"); - } public static boolean getCreateDBFromScratch()