001/* 002 * (C) Copyright 2006-2010 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Thierry Delprat 018 */ 019package org.nuxeo.apidoc.search; 020 021import java.util.ArrayList; 022import java.util.Collections; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026 027import org.apache.commons.lang.text.StrBuilder; 028import org.nuxeo.apidoc.adapters.BaseNuxeoArtifactDocAdapter; 029import org.nuxeo.apidoc.adapters.BundleGroupDocAdapter; 030import org.nuxeo.apidoc.adapters.BundleInfoDocAdapter; 031import org.nuxeo.apidoc.adapters.ComponentInfoDocAdapter; 032import org.nuxeo.apidoc.adapters.ExtensionInfoDocAdapter; 033import org.nuxeo.apidoc.adapters.ExtensionPointInfoDocAdapter; 034import org.nuxeo.apidoc.adapters.ServiceInfoDocAdapter; 035import org.nuxeo.apidoc.api.BundleGroup; 036import org.nuxeo.apidoc.api.BundleInfo; 037import org.nuxeo.apidoc.api.ComponentInfo; 038import org.nuxeo.apidoc.api.DocumentationItem; 039import org.nuxeo.apidoc.api.ExtensionInfo; 040import org.nuxeo.apidoc.api.ExtensionPointInfo; 041import org.nuxeo.apidoc.api.NuxeoArtifact; 042import org.nuxeo.apidoc.api.QueryHelper; 043import org.nuxeo.apidoc.api.ServiceInfo; 044import org.nuxeo.apidoc.repository.RepositoryDistributionSnapshot; 045import org.nuxeo.apidoc.snapshot.DistributionSnapshot; 046import org.nuxeo.apidoc.snapshot.SnapshotManager; 047import org.nuxeo.ecm.core.api.CoreSession; 048import org.nuxeo.ecm.core.api.DocumentModel; 049import org.nuxeo.ecm.core.api.DocumentModelList; 050import org.nuxeo.ecm.core.query.sql.NXQL; 051import org.nuxeo.elasticsearch.api.ElasticSearchService; 052import org.nuxeo.elasticsearch.query.NxQueryBuilder; 053import org.nuxeo.runtime.api.Framework; 054 055public class ArtifactSearcherImpl implements ArtifactSearcher { 056 057 protected static final int MAX_RESULTS = 1000; 058 059 protected NuxeoArtifact mapDoc2Artifact(DocumentModel doc) { 060 NuxeoArtifact artifact = null; 061 062 if (doc.getType().equals(BundleGroup.TYPE_NAME)) { 063 artifact = new BundleGroupDocAdapter(doc); 064 } else if (doc.getType().equals(BundleInfo.TYPE_NAME)) { 065 artifact = new BundleInfoDocAdapter(doc); 066 } else if (doc.getType().equals(ComponentInfo.TYPE_NAME)) { 067 artifact = new ComponentInfoDocAdapter(doc); 068 } else if (doc.getType().equals(ExtensionPointInfo.TYPE_NAME)) { 069 artifact = new ExtensionPointInfoDocAdapter(doc); 070 } else if (doc.getType().equals(ExtensionInfo.TYPE_NAME)) { 071 artifact = new ExtensionInfoDocAdapter(doc); 072 } else if (doc.getType().equals(DistributionSnapshot.TYPE_NAME)) { 073 artifact = new RepositoryDistributionSnapshot(doc); 074 } else if (doc.getType().equals(ServiceInfo.TYPE_NAME)) { 075 artifact = new ServiceInfoDocAdapter(doc); 076 } 077 078 return artifact; 079 } 080 081 @Override 082 public List<NuxeoArtifact> searchArtifact(CoreSession session, String distribId, String fulltext) { 083 List<NuxeoArtifact> result = new ArrayList<>(); 084 085 DistributionSnapshot snap = Framework.getService(SnapshotManager.class).getSnapshot(distribId, session); 086 if (!(snap instanceof RepositoryDistributionSnapshot)) { 087 return Collections.emptyList(); 088 } 089 090 DocumentModel dist = ((RepositoryDistributionSnapshot) snap).getDoc(); 091 StrBuilder q = new StrBuilder("SELECT * FROM Document WHERE "); 092 q.append("ecm:path STARTSWITH '").append(dist.getPathAsString()).append("'"); 093 String query = q.toString(); 094 if (fulltext != null) { 095 query += " AND " + NXQL.ECM_FULLTEXT + " = " + NXQL.escapeString(fulltext); 096 } 097 098 ElasticSearchService ess = Framework.getService(ElasticSearchService.class); 099 DocumentModelList docs = ess.query(new NxQueryBuilder(session).nxql(query).limit(MAX_RESULTS)); 100 for (DocumentModel doc : docs) { 101 NuxeoArtifact artifact = mapDoc2Artifact(doc); 102 if (artifact != null) { 103 result.add(artifact); 104 } 105 } 106 return result; 107 } 108 109 @Override 110 public List<DocumentationItem> searchDocumentation(CoreSession session, String distribId, String fulltext, 111 String targetType) { 112 DistributionSnapshot snap = Framework.getService(SnapshotManager.class).getSnapshot(distribId, session); 113 DocumentModel dist = ((RepositoryDistributionSnapshot) snap).getDoc(); 114 String query = QueryHelper.select(DocumentationItem.TYPE_NAME, dist, NXQL.ECM_FULLTEXT, fulltext); 115 if (targetType != null) { 116 query += " AND " + DocumentationItem.PROP_TARGET_TYPE + " = " + NXQL.escapeString(targetType); 117 } 118 119 ElasticSearchService ess = Framework.getService(ElasticSearchService.class); 120 DocumentModelList docs = ess.query(new NxQueryBuilder(session).nxql(query).limit(MAX_RESULTS)); 121 List<DocumentationItem> result = new ArrayList<>(); 122 for (DocumentModel doc : docs) { 123 DocumentationItem docItem = doc.getAdapter(DocumentationItem.class); 124 if (docItem != null) { 125 result.add(docItem); 126 } 127 } 128 return result; 129 } 130 131 @Override 132 public List<NuxeoArtifact> filterArtifact(CoreSession session, String distribId, String type, String fulltext) { 133 List<NuxeoArtifact> result = new ArrayList<>(); 134 135 List<NuxeoArtifact> matchingArtifacts = searchArtifact(session, distribId, fulltext); 136 List<DocumentationItem> matchingDocumentationItems = searchDocumentation(session, distribId, fulltext, null); 137 138 Map<String, ArtifactWithWeight> sortMap = new HashMap<>(); 139 140 for (NuxeoArtifact matchingArtifact : matchingArtifacts) { 141 ArtifactWithWeight artifactWithWeight; 142 NuxeoArtifact matchingParentArtifact = resolveInTree(session, distribId, matchingArtifact, type); 143 if (matchingParentArtifact != null) { 144 artifactWithWeight = new ArtifactWithWeight(matchingParentArtifact); 145 } else if (matchingArtifact.getArtifactType().equals(type)) { 146 artifactWithWeight = new ArtifactWithWeight(matchingArtifact); 147 } else { 148 continue; 149 } 150 151 String id = artifactWithWeight.getArtifact().getId(); 152 if (sortMap.containsKey(id)) { 153 sortMap.get(id).addHit(); 154 } else { 155 sortMap.put(id, new ArtifactWithWeight(matchingParentArtifact)); 156 } 157 } 158 159 for (DocumentationItem matchingDocumentationItem : matchingDocumentationItems) { 160 NuxeoArtifact resultArtifact = resolveInTree(session, distribId, matchingDocumentationItem, type); 161 if (resultArtifact != null) { 162 if (sortMap.containsKey(resultArtifact.getId())) { 163 sortMap.get(resultArtifact.getId()).addHit(); 164 } else { 165 sortMap.put(resultArtifact.getId(), new ArtifactWithWeight(resultArtifact)); 166 } 167 } 168 } 169 170 List<ArtifactWithWeight> artifacts = new ArrayList<>(sortMap.values()); 171 Collections.sort(artifacts); 172 173 for (ArtifactWithWeight item : artifacts) { 174 result.add(item.getArtifact()); 175 } 176 return result; 177 } 178 179 protected NuxeoArtifact resolveInTree(CoreSession session, String distribId, NuxeoArtifact matchingArtifact, 180 String searchedType) { 181 String cType = matchingArtifact.getArtifactType(); 182 if (cType.equals(searchedType)) { 183 return matchingArtifact; 184 } 185 BaseNuxeoArtifactDocAdapter docAdapter = (BaseNuxeoArtifactDocAdapter) matchingArtifact; 186 DocumentModel doc = docAdapter.getDoc(); 187 List<DocumentModel> parents = session.getParentDocuments(doc.getRef()); 188 Collections.reverse(parents); 189 for (DocumentModel parent : parents) { 190 if (parent.getType().equals(searchedType)) { 191 return mapDoc2Artifact(parent); 192 } 193 } 194 return null; 195 } 196 197 protected NuxeoArtifact resolveInTree(CoreSession session, String distribId, 198 DocumentationItem matchingDocumentationItem, String searchedType) { 199 DistributionSnapshot snap = Framework.getService(SnapshotManager.class).getSnapshot(distribId, session); 200 String targetId = matchingDocumentationItem.getTarget(); 201 String targetType = matchingDocumentationItem.getTargetType(); 202 NuxeoArtifact artifact; 203 if (targetType.equals(BundleGroup.TYPE_NAME)) { 204 artifact = snap.getBundleGroup(targetId); 205 } else if (targetType.equals(BundleInfo.TYPE_NAME)) { 206 artifact = snap.getBundle(targetId); 207 } else if (targetType.equals(ComponentInfo.TYPE_NAME)) { 208 artifact = snap.getComponent(targetId); 209 } else if (targetType.equals(ExtensionPointInfo.TYPE_NAME)) { 210 artifact = snap.getExtensionPoint(targetId); 211 } else if (targetType.equals(ExtensionInfo.TYPE_NAME)) { 212 artifact = snap.getContribution(targetId); 213 } else if (targetType.equals(ServiceInfo.TYPE_NAME)) { 214 artifact = snap.getService(targetId); 215 } else { 216 artifact = null; 217 } 218 return resolveInTree(session, distribId, artifact, searchedType); 219 } 220 221}