jp.aegif.nemaki.cmis.aspect.query.solr.SolrQueryProcessor.java Source code

Java tutorial

Introduction

Here is the source code for jp.aegif.nemaki.cmis.aspect.query.solr.SolrQueryProcessor.java

Source

/*******************************************************************************
 * Copyright (c) 2013 aegif.
 *
 * This file is part of NemakiWare.
 *
 * NemakiWare 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.
 *
 * NemakiWare 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 NemakiWare.
 * If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *     linzhixing(https://github.com/linzhixing) - initial API and implementation
 ******************************************************************************/
package jp.aegif.nemaki.cmis.aspect.query.solr;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;

import jp.aegif.nemaki.businesslogic.ContentService;
import jp.aegif.nemaki.cmis.aspect.CompileService;
import jp.aegif.nemaki.cmis.aspect.ExceptionService;
import jp.aegif.nemaki.cmis.aspect.PermissionService;
import jp.aegif.nemaki.cmis.aspect.query.QueryProcessor;
import jp.aegif.nemaki.cmis.aspect.type.TypeManager;
import jp.aegif.nemaki.model.Content;
import jp.aegif.nemaki.util.lock.ThreadLockService;

import org.antlr.runtime.tree.Tree;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.data.ObjectList;
import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer;
import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectListImpl;
import org.apache.chemistry.opencmis.commons.server.CallContext;
import org.apache.chemistry.opencmis.server.support.query.QueryObject;
import org.apache.chemistry.opencmis.server.support.query.QueryObject.SortSpec;
import org.apache.chemistry.opencmis.server.support.query.QueryUtilStrict;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.params.CommonParams;

public class SolrQueryProcessor implements QueryProcessor {

    private TypeManager typeManager;
    private ContentService contentService;
    private PermissionService permissionService;
    private CompileService compileService;
    private ExceptionService exceptionService;
    private ThreadLockService threadLockService;
    private SolrUtil solrUtil;
    private static final Log logger = LogFactory.getLog(SolrQueryProcessor.class);

    public SolrQueryProcessor() {

    }

    private class CmisTypeManager implements org.apache.chemistry.opencmis.server.support.TypeManager {
        private String repositoryId;
        private TypeManager typeManager;

        public CmisTypeManager(String repositoryId, TypeManager typeManager) {
            this.repositoryId = repositoryId;
            this.typeManager = typeManager;
        }

        @Override
        public void addTypeDefinition(TypeDefinition arg0, boolean arg1) {
            // TODO Auto-generated method stub

        }

        @Override
        public void deleteTypeDefinition(String typeId) {
            typeManager.deleteTypeDefinition(repositoryId, typeId);

        }

        @Override
        public String getPropertyIdForQueryName(TypeDefinition typeDefinition, String propQueryName) {
            return typeManager.getPropertyIdForQueryName(repositoryId, typeDefinition, propQueryName);
        }

        @Override
        public List<TypeDefinitionContainer> getRootTypes() {
            return typeManager.getRootTypes(repositoryId);
        }

        @Override
        public TypeDefinitionContainer getTypeById(String typeId) {
            return typeManager.getTypeById(repositoryId, typeId);
        }

        @Override
        public TypeDefinition getTypeByQueryName(String typeQueryName) {
            return typeManager.getTypeByQueryName(repositoryId, typeQueryName);
        }

        @Override
        public Collection<TypeDefinitionContainer> getTypeDefinitionList() {
            return typeManager.getTypeDefinitionList(repositoryId);
        }

        @Override
        public void updateTypeDefinition(TypeDefinition typeDefinition) {
            typeManager.updateTypeDefinition(repositoryId, typeDefinition);

        }
    }

    @Override
    public ObjectList query(CallContext callContext, String repositoryId, String statement,
            Boolean searchAllVersions, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
            String renditionFilter, BigInteger maxItems, BigInteger skipCount) {

        SolrServer solrServer = solrUtil.getSolrServer();

        // TODO walker is required?
        QueryUtilStrict util = new QueryUtilStrict(statement, new CmisTypeManager(repositoryId, typeManager), null);
        QueryObject queryObject = util.getQueryObject();

        // Get where caluse as Tree
        Tree whereTree = null;
        try {
            util.processStatement();
            Tree tree = util.parseStatement();
            whereTree = extractWhereTree(tree);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // Build solr statement of WHERE
        String whereQueryString = "";
        if (whereTree == null || whereTree.isNil()) {
            whereQueryString = "*:*";
        } else {
            try {
                SolrPredicateWalker solrPredicateWalker = new SolrPredicateWalker(repositoryId, queryObject,
                        solrUtil, contentService);
                Query whereQuery = solrPredicateWalker.walkPredicate(whereTree);
                whereQueryString = whereQuery.toString();
            } catch (Exception e) {
                e.printStackTrace();
                // TODO Output more detailed exception
                exceptionService.invalidArgument("Invalid CMIS SQL statement!");
            }
        }

        // Build solr query of FROM
        String fromQueryString = "";

        String repositoryQuery = "repository_id:" + repositoryId;

        fromQueryString += repositoryQuery + " AND ";

        TypeDefinition td = queryObject.getMainFromName();
        // includedInSupertypeQuery
        List<TypeDefinitionContainer> typeDescendants = typeManager.getTypesDescendants(repositoryId, td.getId(),
                BigInteger.valueOf(-1), false);
        Iterator<TypeDefinitionContainer> iterator = typeDescendants.iterator();
        List<String> tables = new ArrayList<String>();
        while (iterator.hasNext()) {
            TypeDefinition descendant = iterator.next().getTypeDefinition();
            if (td.getId() != descendant.getId()) {
                boolean isq = (descendant.isIncludedInSupertypeQuery() == null) ? false
                        : descendant.isIncludedInSupertypeQuery();
                if (!isq)
                    continue;
            }
            String table = descendant.getQueryName();
            tables.add(table.replaceAll(":", "\\\\:"));
        }

        Term t = new Term(solrUtil.getPropertyNameInSolr(PropertyIds.OBJECT_TYPE_ID),
                StringUtils.join(tables, " "));
        fromQueryString += new TermQuery(t).toString();

        // Execute query
        SolrQuery solrQuery = new SolrQuery();
        solrQuery.setQuery(whereQueryString);
        solrQuery.setFilterQueries(fromQueryString);

        //TEST
        solrQuery.set(CommonParams.START, 0);
        solrQuery.set(CommonParams.ROWS, maxItems.intValue());

        QueryResponse resp = null;
        try {
            resp = solrServer.query(solrQuery);
        } catch (SolrServerException e) {
            e.printStackTrace();
        }

        // Output search results to ObjectList
        if (resp != null && resp.getResults() != null && resp.getResults().getNumFound() != 0) {
            SolrDocumentList docs = resp.getResults();

            List<Content> contents = new ArrayList<Content>();
            for (SolrDocument doc : docs) {
                String docId = (String) doc.getFieldValue("object_id");
                Content c = contentService.getContent(repositoryId, docId);

                // When for some reason the content is missed, pass through
                if (c == null) {
                    logger.warn("[objectId=" + docId + "]It is missed in DB but still rests in Solr.");
                } else {
                    contents.add(c);
                }

            }

            List<Lock> locks = threadLockService.readLocks(repositoryId, contents);
            try {
                threadLockService.bulkLock(locks);

                // Filter out by permissions
                List<Content> permitted = permissionService.getFiltered(callContext, repositoryId, contents);

                // Filter return value with SELECT clause
                Map<String, String> requestedWithAliasKey = queryObject.getRequestedPropertiesByAlias();
                String filter = null;
                if (!requestedWithAliasKey.keySet().contains("*")) {
                    // Create filter(queryNames) from query aliases
                    filter = StringUtils.join(requestedWithAliasKey.values(), ",");
                }

                // Build ObjectList
                String orderBy = orderBy(queryObject);
                ObjectList result = compileService.compileObjectDataList(callContext, repositoryId, permitted,
                        filter, includeAllowableActions, includeRelationships, renditionFilter, false, maxItems,
                        skipCount, false, orderBy);

                return result;

            } finally {
                threadLockService.bulkUnlock(locks);
            }
        } else {
            ObjectListImpl nullList = new ObjectListImpl();
            nullList.setHasMoreItems(false);
            nullList.setNumItems(BigInteger.ZERO);
            return nullList;
        }
    }

    private String orderBy(QueryObject queryObject) {
        List<SortSpec> sortSpecs = queryObject.getOrderBys();
        List<String> _orderBy = new ArrayList<String>();
        for (SortSpec sortSpec : sortSpecs) {
            List<String> _sortSpec = new ArrayList<String>();
            _sortSpec.add(sortSpec.getSelector().getName());
            if (!sortSpec.isAscending()) {
                _sortSpec.add("DESC");
            }

            _orderBy.add(StringUtils.join(_sortSpec, " "));
        }
        String orderBy = StringUtils.join(_orderBy, ",");
        return orderBy;
    }

    private Tree extractWhereTree(Tree tree) {
        for (int i = 0; i < tree.getChildCount(); i++) {
            Tree selectTree = tree.getChild(i);
            if ("SELECT".equals(selectTree.getText())) {
                for (int j = 0; j < selectTree.getChildCount(); j++) {
                    Tree whereTree = selectTree.getChild(j);
                    if ("WHERE".equals(whereTree.getText())) {
                        return whereTree.getChild(0);
                    }
                }

            }
        }

        return null;
    }

    public void setTypeManager(TypeManager typeManager) {
        this.typeManager = typeManager;
    }

    public void setContentService(ContentService contentService) {
        this.contentService = contentService;
    }

    public void setPermissionService(PermissionService permissionService) {
        this.permissionService = permissionService;
    }

    public void setCompileService(CompileService compileService) {
        this.compileService = compileService;
    }

    public void setExceptionService(ExceptionService exceptionService) {
        this.exceptionService = exceptionService;
    }

    public void setSolrUtil(SolrUtil solrUtil) {
        this.solrUtil = solrUtil;
    }

    public void setThreadLockService(ThreadLockService threadLockService) {
        this.threadLockService = threadLockService;
    }
}