/*
*
* This is a simple Content Management System (CMS)
* Copyright (C) 2011 Imran M Yousuf (imyousuf@smartitengineering.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.smartitengineering.cms.spi.impl.type.search;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import com.smartitengineering.cms.api.common.SearchResult;
import com.smartitengineering.cms.api.event.Event.EventType;
import com.smartitengineering.cms.api.event.Event.Type;
import com.smartitengineering.cms.api.event.EventListener;
import com.smartitengineering.cms.api.factory.SmartContentAPI;
import com.smartitengineering.cms.api.type.ContentType;
import com.smartitengineering.cms.api.type.ContentTypeId;
import com.smartitengineering.cms.api.type.Filter;
import com.smartitengineering.cms.api.workspace.WorkspaceId;
import com.smartitengineering.cms.spi.impl.SearchBeanLoader;
import com.smartitengineering.cms.spi.impl.content.search.ContentSearcherImpl;
import com.smartitengineering.cms.spi.impl.events.SolrFieldNames;
import com.smartitengineering.cms.spi.type.ContentTypeSearcher;
import com.smartitengineering.common.dao.search.CommonFreeTextSearchDao;
import com.smartitengineering.dao.common.queryparam.MatchMode;
import com.smartitengineering.dao.common.queryparam.QueryParameter;
import com.smartitengineering.dao.common.queryparam.QueryParameterFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.solr.client.solrj.util.ClientUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author imyousuf
*/
public class ContentTypeSearcherImpl implements ContentTypeSearcher {
public static final String REINDEX_LISTENER_NAME = "typeReindexEventListener";
protected final transient Logger logger = LoggerFactory.getLogger(getClass());
@Inject
private CommonFreeTextSearchDao<ContentType> textSearchDao;
@Inject
private SearchBeanLoader<ContentType, ContentTypeId> contentTypeLoader;
@Inject
@Named(REINDEX_LISTENER_NAME)
private EventListener reindexListener;
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
private static final String SOLR_DATE_FORMAT = DateFormatUtils.ISO_DATETIME_FORMAT.getPattern() + "'Z'";
@Override
public void reIndex(ContentTypeId typeId) {
if (typeId != null) {
ContentType contentType = contentTypeLoader.loadById(typeId);
if (contentType != null) {
reindexListener.notify(SmartContentAPI.getInstance().getEventRegistrar().<ContentType>createEvent(
EventType.UPDATE, Type.CONTENT_TYPE, contentType));
}
}
}
@Override
public void reIndex(final WorkspaceId workspaceId) {
executorService.submit(new Runnable() {
@Override
public void run() {
final QueryParameter param;
if (workspaceId == null) {
param = null;
}
else {
param = QueryParameterFactory.getStringLikePropertyParam("id", new StringBuilder(workspaceId.toString()).
append(':').toString(), MatchMode.START);
}
final QueryParameter<Integer> maxResultsParam = QueryParameterFactory.getMaxResultsParam(100);
boolean hasMore = true;
ContentTypeId lastId = null;
List<QueryParameter> params = new ArrayList<QueryParameter>();
while (hasMore) {
params.clear();
if (param != null) {
params.add(param);
}
params.add(maxResultsParam);
if (lastId != null) {
try {
params.add(QueryParameterFactory.getGreaterThanPropertyParam("id", contentTypeLoader.getByteArrayFromId(
lastId)));
}
catch (Exception ex) {
logger.warn("Could not add last id clause " + lastId.toString(), ex);
}
}
List<ContentType> list = contentTypeLoader.getQueryResult(params);
if (list == null || list.isEmpty()) {
hasMore = false;
}
else {
final ContentType[] contents = new ContentType[list.size()];
int index = 0;
for (ContentType content : list) {
reindexListener.notify(SmartContentAPI.getInstance().getEventRegistrar().<ContentType>createEvent(
EventType.UPDATE, Type.CONTENT_TYPE, content));
contents[index++] = content;
}
lastId = contents[contents.length - 1].getContentTypeID();
}
}
}
});
}
@Override
public SearchResult<ContentType> search(Filter filter) {
final StringBuilder finalQuery = new StringBuilder();
String disjunctionSeperator = " OR ";
String conjunctionSeperator = " AND ";
String seperator = filter.isDisjunction() ? disjunctionSeperator : conjunctionSeperator;
int count = 0;
finalQuery.append(SolrFieldNames.TYPE).append(": ").append(ContentTypeHelper.CONTENT_TYPE);
final WorkspaceId workspaceId = filter.getWorkspaceId();
if (workspaceId != null) {
finalQuery.append(conjunctionSeperator);
finalQuery.append((" ("));
finalQuery.append(SolrFieldNames.WORKSPACEID).append(": ").append(ClientUtils.escapeQueryChars(
workspaceId.toString()));
if (filter.isFriendliesIncluded()) {
Collection<WorkspaceId> friendlies = workspaceId.getWorkspace().getFriendlies();
if (friendlies != null && !friendlies.isEmpty()) {
finalQuery.append(disjunctionSeperator).append("(private: false AND (");
boolean first = true;
for (WorkspaceId friendly : friendlies) {
if (friendly != null) {
if (first) {
first = false;
}
else {
finalQuery.append(disjunctionSeperator);
}
finalQuery.append(SolrFieldNames.WORKSPACEID).append(": ").append(ClientUtils.escapeQueryChars(friendly.
toString()));
}
}
finalQuery.append("))");
}
}
finalQuery.append((") "));
}
final StringBuilder query = new StringBuilder();
ContentTypeId parentId = filter.getChildOf();
if (parentId != null) {
if (query.length() > 0) {
query.append(seperator);
}
query.append(SolrFieldNames.CONTENTTYPEID).append(": ").append(ClientUtils.escapeQueryChars(parentId.toString()));
}
Set<ContentTypeId> contentTypeIds = filter.getInstanceOfContentTypeFilters();
if (contentTypeIds != null && !contentTypeIds.isEmpty()) {
if (query.length() > 0) {
query.append(seperator);
}
query.append("(");
}
for (ContentTypeId contentTypeId : contentTypeIds) {
if (count > 0) {
query.append(disjunctionSeperator);
}
if (contentTypeId != null) {
query.append(SolrFieldNames.INSTANCE_OF).append(": ").append(ClientUtils.escapeQueryChars(
contentTypeId.toString()));
}
count++;
}
if (contentTypeIds != null && !contentTypeIds.isEmpty()) {
query.append(")");
}
if (StringUtils.isNotBlank(filter.getSearchTerms())) {
if (query.length() > 0) {
query.append(seperator);
}
query.append(SolrFieldNames.ALL_TEXT).append(": ").append(ClientUtils.escapeQueryChars(filter.getSearchTerms()));
}
if (filter.getCreationDateFilter() != null) {
if (query.length() > 0) {
query.append(seperator);
}
else {
query.append("workspaceId: [* TO *]").append(seperator);
}
QueryParameter<Date> creationDateFilter = filter.getCreationDateFilter();
String queryStr = ContentSearcherImpl.generateDateQuery(SolrFieldNames.CREATIONDATE, creationDateFilter);
query.append(queryStr);
}
if (filter.getLastModifiedDateFilter() != null) {
if (query.length() > 0) {
query.append(seperator);
}
else {
query.append("workspaceId: [* TO *]").append(seperator);
}
QueryParameter<Date> lastModifiedDateFilter = filter.getLastModifiedDateFilter();
String queryStr = ContentSearcherImpl.generateDateQuery(SolrFieldNames.LASTMODIFIEDDATE, lastModifiedDateFilter);
query.append(queryStr);
}
if (query.length() > 0) {
finalQuery.append(conjunctionSeperator).append('(').append(query.toString()).append(')');
}
if (logger.isDebugEnabled()) {
logger.debug("Query q = " + finalQuery.toString());
}
final com.smartitengineering.common.dao.search.SearchResult<ContentType> searchResult =
textSearchDao.detailedSearch(QueryParameterFactory.
getStringLikePropertyParam("q", finalQuery.toString()), QueryParameterFactory.getFirstResultParam(filter.
getStartFrom()), QueryParameterFactory.getMaxResultsParam(filter.getMaxContents()));
final Collection<ContentType> result;
if (searchResult == null || searchResult.getResult() == null || searchResult.getResult().isEmpty()) {
result = Collections.emptyList();
}
else {
result = new ArrayList<ContentType>();
for (ContentType content : searchResult.getResult()) {
if (content != null) {
result.add(content);
}
}
}
return SmartContentAPI.getInstance().getContentTypeLoader().createSearchResult(result,
searchResult.getTotalResults());
}
}