001/*
002 * (C) Copyright 2006-2010 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Thierry Delprat
016 */
017package org.nuxeo.apidoc.search;
018
019import java.util.ArrayList;
020import java.util.Arrays;
021import java.util.Collections;
022import java.util.HashMap;
023import java.util.List;
024import java.util.Map;
025
026import org.apache.commons.lang.text.StrBuilder;
027import org.nuxeo.apidoc.adapters.BaseNuxeoArtifactDocAdapter;
028import org.nuxeo.apidoc.adapters.BundleGroupDocAdapter;
029import org.nuxeo.apidoc.adapters.BundleInfoDocAdapter;
030import org.nuxeo.apidoc.adapters.ComponentInfoDocAdapter;
031import org.nuxeo.apidoc.adapters.ExtensionInfoDocAdapter;
032import org.nuxeo.apidoc.adapters.ExtensionPointInfoDocAdapter;
033import org.nuxeo.apidoc.adapters.ServiceInfoDocAdapter;
034import org.nuxeo.apidoc.api.BundleGroup;
035import org.nuxeo.apidoc.api.BundleInfo;
036import org.nuxeo.apidoc.api.ComponentInfo;
037import org.nuxeo.apidoc.api.DocumentationItem;
038import org.nuxeo.apidoc.api.ExtensionInfo;
039import org.nuxeo.apidoc.api.ExtensionPointInfo;
040import org.nuxeo.apidoc.api.NuxeoArtifact;
041import org.nuxeo.apidoc.api.QueryHelper;
042import org.nuxeo.apidoc.api.ServiceInfo;
043import org.nuxeo.apidoc.repository.RepositoryDistributionSnapshot;
044import org.nuxeo.apidoc.snapshot.DistributionSnapshot;
045import org.nuxeo.apidoc.snapshot.SnapshotManager;
046import org.nuxeo.ecm.core.api.CoreSession;
047import org.nuxeo.ecm.core.api.DocumentModel;
048import org.nuxeo.ecm.core.api.DocumentModelList;
049import org.nuxeo.ecm.core.query.sql.NXQL;
050import org.nuxeo.runtime.api.Framework;
051
052public class ArtifactSearcherImpl implements ArtifactSearcher {
053
054    protected NuxeoArtifact mapDoc2Artifact(DocumentModel doc) {
055        NuxeoArtifact artifact = null;
056
057        if (doc.getType().equals(BundleGroup.TYPE_NAME)) {
058            artifact = new BundleGroupDocAdapter(doc);
059        } else if (doc.getType().equals(BundleInfo.TYPE_NAME)) {
060            artifact = new BundleInfoDocAdapter(doc);
061        } else if (doc.getType().equals(ComponentInfo.TYPE_NAME)) {
062            artifact = new ComponentInfoDocAdapter(doc);
063        } else if (doc.getType().equals(ExtensionPointInfo.TYPE_NAME)) {
064            artifact = new ExtensionPointInfoDocAdapter(doc);
065        } else if (doc.getType().equals(ExtensionInfo.TYPE_NAME)) {
066            artifact = new ExtensionInfoDocAdapter(doc);
067        } else if (doc.getType().equals(DistributionSnapshot.TYPE_NAME)) {
068            artifact = new RepositoryDistributionSnapshot(doc);
069        } else if (doc.getType().equals(ServiceInfo.TYPE_NAME)) {
070            artifact = new ServiceInfoDocAdapter(doc);
071        }
072
073        return artifact;
074    }
075
076    @Override
077    public List<NuxeoArtifact> searchArtifact(CoreSession session, String fulltext) {
078        List<NuxeoArtifact> result = new ArrayList<NuxeoArtifact>();
079        StrBuilder q = new StrBuilder("SELECT * FROM Document WHERE " + NXQL.ECM_PRIMARYTYPE + " IN ('");
080        q.appendWithSeparators(Arrays.asList(BundleGroup.TYPE_NAME, BundleInfo.TYPE_NAME, ComponentInfo.TYPE_NAME,
081                ExtensionPointInfo.TYPE_NAME, ExtensionInfo.TYPE_NAME, DistributionSnapshot.TYPE_NAME,
082                ServiceInfo.TYPE_NAME), "', '");
083        q.append("')");
084        String query = q.toString();
085        if (fulltext != null) {
086            query += " AND " + NXQL.ECM_FULLTEXT + " = " + NXQL.escapeString(fulltext);
087        }
088        DocumentModelList docs = session.query(query);
089        for (DocumentModel doc : docs) {
090            NuxeoArtifact artifact = mapDoc2Artifact(doc);
091            if (artifact != null) {
092                result.add(artifact);
093            }
094        }
095        return result;
096    }
097
098    @Override
099    public List<DocumentationItem> searchDocumentation(CoreSession session, String distribId, String fulltext,
100            String targetType) {
101        DistributionSnapshot snap = Framework.getLocalService(SnapshotManager.class).getSnapshot(distribId, session);
102        DocumentModel dist = ((RepositoryDistributionSnapshot) snap).getDoc();
103        String query = QueryHelper.select(DocumentationItem.TYPE_NAME, dist, NXQL.ECM_FULLTEXT, fulltext);
104        if (targetType != null) {
105            query += " AND " + DocumentationItem.PROP_TARGET_TYPE + " = " + NXQL.escapeString(targetType);
106        }
107        DocumentModelList docs = session.query(query);
108        List<DocumentationItem> result = new ArrayList<DocumentationItem>();
109        for (DocumentModel doc : docs) {
110            DocumentationItem docItem = doc.getAdapter(DocumentationItem.class);
111            if (docItem != null) {
112                result.add(docItem);
113            }
114        }
115        return result;
116    }
117
118    @Override
119    public List<NuxeoArtifact> filterArtifact(CoreSession session, String distribId, String type, String fulltext) {
120        List<NuxeoArtifact> result = new ArrayList<NuxeoArtifact>();
121
122        List<NuxeoArtifact> matchingArtifacts = searchArtifact(session, fulltext);
123        List<DocumentationItem> matchingDocumentationItems = searchDocumentation(session, distribId, fulltext, null);
124
125        Map<String, ArtifactWithWeight> sortMap = new HashMap<String, ArtifactWithWeight>();
126
127        for (NuxeoArtifact matchingArtifact : matchingArtifacts) {
128            NuxeoArtifact resultArtifact = resolveInTree(session, distribId, matchingArtifact, type);
129            if (resultArtifact != null) {
130                if (sortMap.containsKey(resultArtifact.getId())) {
131                    sortMap.get(resultArtifact.getId()).addHit();
132                } else {
133                    sortMap.put(resultArtifact.getId(), new ArtifactWithWeight(resultArtifact));
134                }
135            }
136        }
137
138        for (DocumentationItem matchingDocumentationItem : matchingDocumentationItems) {
139            NuxeoArtifact resultArtifact = resolveInTree(session, distribId, matchingDocumentationItem, type);
140            if (resultArtifact != null) {
141                if (sortMap.containsKey(resultArtifact.getId())) {
142                    sortMap.get(resultArtifact.getId()).addHit();
143                } else {
144                    sortMap.put(resultArtifact.getId(), new ArtifactWithWeight(resultArtifact));
145                }
146            }
147        }
148
149        List<ArtifactWithWeight> artifacts = new ArrayList<ArtifactWithWeight>(sortMap.values());
150        Collections.sort(artifacts);
151
152        for (ArtifactWithWeight item : artifacts) {
153            result.add(item.getArtifact());
154        }
155        return result;
156    }
157
158    protected NuxeoArtifact resolveInTree(CoreSession session, String distribId, NuxeoArtifact matchingArtifact,
159            String searchedType) {
160        String cType = matchingArtifact.getArtifactType();
161        if (cType.equals(searchedType)) {
162            return matchingArtifact;
163        }
164        BaseNuxeoArtifactDocAdapter docAdapter = (BaseNuxeoArtifactDocAdapter) matchingArtifact;
165        DocumentModel doc = docAdapter.getDoc();
166        List<DocumentModel> parents = session.getParentDocuments(doc.getRef());
167        Collections.reverse(parents);
168        for (DocumentModel parent : parents) {
169            if (parent.getType().equals(searchedType)) {
170                return mapDoc2Artifact(parent);
171            }
172        }
173        return null;
174    }
175
176    protected NuxeoArtifact resolveInTree(CoreSession session, String distribId,
177            DocumentationItem matchingDocumentationItem, String searchedType) {
178        DistributionSnapshot snap = Framework.getLocalService(SnapshotManager.class).getSnapshot(distribId, session);
179        String targetId = matchingDocumentationItem.getTarget();
180        String targetType = matchingDocumentationItem.getTargetType();
181        NuxeoArtifact artifact;
182        if (targetType.equals(BundleGroup.TYPE_NAME)) {
183            artifact = snap.getBundleGroup(targetId);
184        } else if (targetType.equals(BundleInfo.TYPE_NAME)) {
185            artifact = snap.getBundle(targetId);
186        } else if (targetType.equals(ComponentInfo.TYPE_NAME)) {
187            artifact = snap.getComponent(targetId);
188        } else if (targetType.equals(ExtensionPointInfo.TYPE_NAME)) {
189            artifact = snap.getExtensionPoint(targetId);
190        } else if (targetType.equals(ExtensionInfo.TYPE_NAME)) {
191            artifact = snap.getContribution(targetId);
192        } else if (targetType.equals(ServiceInfo.TYPE_NAME)) {
193            artifact = snap.getService(targetId);
194        } else {
195            artifact = null;
196        }
197        return resolveInTree(session, distribId, artifact, searchedType);
198    }
199
200}