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 NuxeoArtifact mapDoc2Artifact(DocumentModel doc) { 058 NuxeoArtifact artifact = null; 059 060 if (doc.getType().equals(BundleGroup.TYPE_NAME)) { 061 artifact = new BundleGroupDocAdapter(doc); 062 } else if (doc.getType().equals(BundleInfo.TYPE_NAME)) { 063 artifact = new BundleInfoDocAdapter(doc); 064 } else if (doc.getType().equals(ComponentInfo.TYPE_NAME)) { 065 artifact = new ComponentInfoDocAdapter(doc); 066 } else if (doc.getType().equals(ExtensionPointInfo.TYPE_NAME)) { 067 artifact = new ExtensionPointInfoDocAdapter(doc); 068 } else if (doc.getType().equals(ExtensionInfo.TYPE_NAME)) { 069 artifact = new ExtensionInfoDocAdapter(doc); 070 } else if (doc.getType().equals(DistributionSnapshot.TYPE_NAME)) { 071 artifact = new RepositoryDistributionSnapshot(doc); 072 } else if (doc.getType().equals(ServiceInfo.TYPE_NAME)) { 073 artifact = new ServiceInfoDocAdapter(doc); 074 } 075 076 return artifact; 077 } 078 079 @Override 080 public List<NuxeoArtifact> searchArtifact(CoreSession session, String distribId, String fulltext) { 081 List<NuxeoArtifact> result = new ArrayList<>(); 082 083 DistributionSnapshot snap = Framework.getLocalService(SnapshotManager.class).getSnapshot(distribId, session); 084 if (!(snap instanceof RepositoryDistributionSnapshot)) { 085 return Collections.emptyList(); 086 } 087 088 DocumentModel dist = ((RepositoryDistributionSnapshot) snap).getDoc(); 089 StrBuilder q = new StrBuilder("SELECT * FROM Document WHERE "); 090 q.append("ecm:path STARTSWITH '").append(dist.getPathAsString()).append("'"); 091 String query = q.toString(); 092 if (fulltext != null) { 093 query += " AND " + NXQL.ECM_FULLTEXT + " = " + NXQL.escapeString(fulltext); 094 } 095 096 ElasticSearchService ess = Framework.getLocalService(ElasticSearchService.class); 097 DocumentModelList docs = ess.query(new NxQueryBuilder(session).nxql(query).limit(-1)); 098 for (DocumentModel doc : docs) { 099 NuxeoArtifact artifact = mapDoc2Artifact(doc); 100 if (artifact != null) { 101 result.add(artifact); 102 } 103 } 104 return result; 105 } 106 107 @Override 108 public List<DocumentationItem> searchDocumentation(CoreSession session, String distribId, String fulltext, 109 String targetType) { 110 DistributionSnapshot snap = Framework.getLocalService(SnapshotManager.class).getSnapshot(distribId, session); 111 DocumentModel dist = ((RepositoryDistributionSnapshot) snap).getDoc(); 112 String query = QueryHelper.select(DocumentationItem.TYPE_NAME, dist, NXQL.ECM_FULLTEXT, fulltext); 113 if (targetType != null) { 114 query += " AND " + DocumentationItem.PROP_TARGET_TYPE + " = " + NXQL.escapeString(targetType); 115 } 116 117 ElasticSearchService ess = Framework.getLocalService(ElasticSearchService.class); 118 DocumentModelList docs = ess.query(new NxQueryBuilder(session).nxql(query).limit(-1)); 119 List<DocumentationItem> result = new ArrayList<>(); 120 for (DocumentModel doc : docs) { 121 DocumentationItem docItem = doc.getAdapter(DocumentationItem.class); 122 if (docItem != null) { 123 result.add(docItem); 124 } 125 } 126 return result; 127 } 128 129 @Override 130 public List<NuxeoArtifact> filterArtifact(CoreSession session, String distribId, String type, String fulltext) { 131 List<NuxeoArtifact> result = new ArrayList<>(); 132 133 List<NuxeoArtifact> matchingArtifacts = searchArtifact(session, distribId, fulltext); 134 List<DocumentationItem> matchingDocumentationItems = searchDocumentation(session, distribId, fulltext, null); 135 136 Map<String, ArtifactWithWeight> sortMap = new HashMap<>(); 137 138 for (NuxeoArtifact matchingArtifact : matchingArtifacts) { 139 ArtifactWithWeight artifactWithWeight; 140 NuxeoArtifact matchingParentArtifact = resolveInTree(session, distribId, matchingArtifact, type); 141 if (matchingParentArtifact != null) { 142 artifactWithWeight = new ArtifactWithWeight(matchingParentArtifact); 143 } else if (matchingArtifact.getArtifactType().equals(type)) { 144 artifactWithWeight = new ArtifactWithWeight(matchingArtifact); 145 } else { 146 continue; 147 } 148 149 String id = artifactWithWeight.getArtifact().getId(); 150 if (sortMap.containsKey(id)) { 151 sortMap.get(id).addHit(); 152 } else { 153 sortMap.put(id, new ArtifactWithWeight(matchingParentArtifact)); 154 } 155 } 156 157 for (DocumentationItem matchingDocumentationItem : matchingDocumentationItems) { 158 NuxeoArtifact resultArtifact = resolveInTree(session, distribId, matchingDocumentationItem, type); 159 if (resultArtifact != null) { 160 if (sortMap.containsKey(resultArtifact.getId())) { 161 sortMap.get(resultArtifact.getId()).addHit(); 162 } else { 163 sortMap.put(resultArtifact.getId(), new ArtifactWithWeight(resultArtifact)); 164 } 165 } 166 } 167 168 List<ArtifactWithWeight> artifacts = new ArrayList<>(sortMap.values()); 169 Collections.sort(artifacts); 170 171 for (ArtifactWithWeight item : artifacts) { 172 result.add(item.getArtifact()); 173 } 174 return result; 175 } 176 177 protected NuxeoArtifact resolveInTree(CoreSession session, String distribId, NuxeoArtifact matchingArtifact, 178 String searchedType) { 179 String cType = matchingArtifact.getArtifactType(); 180 if (cType.equals(searchedType)) { 181 return matchingArtifact; 182 } 183 BaseNuxeoArtifactDocAdapter docAdapter = (BaseNuxeoArtifactDocAdapter) matchingArtifact; 184 DocumentModel doc = docAdapter.getDoc(); 185 List<DocumentModel> parents = session.getParentDocuments(doc.getRef()); 186 Collections.reverse(parents); 187 for (DocumentModel parent : parents) { 188 if (parent.getType().equals(searchedType)) { 189 return mapDoc2Artifact(parent); 190 } 191 } 192 return null; 193 } 194 195 protected NuxeoArtifact resolveInTree(CoreSession session, String distribId, 196 DocumentationItem matchingDocumentationItem, String searchedType) { 197 DistributionSnapshot snap = Framework.getLocalService(SnapshotManager.class).getSnapshot(distribId, session); 198 String targetId = matchingDocumentationItem.getTarget(); 199 String targetType = matchingDocumentationItem.getTargetType(); 200 NuxeoArtifact artifact; 201 if (targetType.equals(BundleGroup.TYPE_NAME)) { 202 artifact = snap.getBundleGroup(targetId); 203 } else if (targetType.equals(BundleInfo.TYPE_NAME)) { 204 artifact = snap.getBundle(targetId); 205 } else if (targetType.equals(ComponentInfo.TYPE_NAME)) { 206 artifact = snap.getComponent(targetId); 207 } else if (targetType.equals(ExtensionPointInfo.TYPE_NAME)) { 208 artifact = snap.getExtensionPoint(targetId); 209 } else if (targetType.equals(ExtensionInfo.TYPE_NAME)) { 210 artifact = snap.getContribution(targetId); 211 } else if (targetType.equals(ServiceInfo.TYPE_NAME)) { 212 artifact = snap.getService(targetId); 213 } else { 214 artifact = null; 215 } 216 return resolveInTree(session, distribId, artifact, searchedType); 217 } 218 219}