Lines 41-47
Link Here
|
41 |
*/ |
41 |
*/ |
42 |
package org.netbeans.modules.maven.indexer; |
42 |
package org.netbeans.modules.maven.indexer; |
43 |
|
43 |
|
|
|
44 |
import java.io.ByteArrayInputStream; |
45 |
import java.io.ByteArrayOutputStream; |
46 |
import java.io.DataInput; |
47 |
import java.io.DataInputStream; |
44 |
import java.io.FileNotFoundException; |
48 |
import java.io.FileNotFoundException; |
|
|
49 |
import java.util.Map.Entry; |
45 |
import org.apache.maven.index.expr.StringSearchExpression; |
50 |
import org.apache.maven.index.expr.StringSearchExpression; |
46 |
import org.codehaus.plexus.util.FileUtils; |
51 |
import org.codehaus.plexus.util.FileUtils; |
47 |
import java.util.Map; |
52 |
import java.util.Map; |
Lines 53-58
Link Here
|
53 |
import org.netbeans.modules.maven.indexer.api.NBVersionInfo; |
58 |
import org.netbeans.modules.maven.indexer.api.NBVersionInfo; |
54 |
import java.io.File; |
59 |
import java.io.File; |
55 |
import java.io.IOException; |
60 |
import java.io.IOException; |
|
|
61 |
import java.io.InputStream; |
56 |
import java.lang.ref.WeakReference; |
62 |
import java.lang.ref.WeakReference; |
57 |
import java.net.URI; |
63 |
import java.net.URI; |
58 |
import java.util.ArrayList; |
64 |
import java.util.ArrayList; |
Lines 61-73
Link Here
|
61 |
import java.util.Collections; |
67 |
import java.util.Collections; |
62 |
import java.util.Comparator; |
68 |
import java.util.Comparator; |
63 |
import java.util.Date; |
69 |
import java.util.Date; |
|
|
70 |
import java.util.Enumeration; |
64 |
import java.util.HashMap; |
71 |
import java.util.HashMap; |
65 |
import java.util.HashSet; |
72 |
import java.util.HashSet; |
66 |
import java.util.Iterator; |
73 |
import java.util.Iterator; |
67 |
import java.util.List; |
74 |
import java.util.List; |
68 |
import java.util.Set; |
75 |
import java.util.Set; |
|
|
76 |
import java.util.TreeMap; |
69 |
import java.util.TreeSet; |
77 |
import java.util.TreeSet; |
70 |
import java.util.WeakHashMap; |
78 |
import java.util.WeakHashMap; |
|
|
79 |
import java.util.concurrent.atomic.AtomicBoolean; |
80 |
import java.util.jar.JarEntry; |
81 |
import java.util.jar.JarFile; |
71 |
import java.util.logging.Level; |
82 |
import java.util.logging.Level; |
72 |
import java.util.logging.Logger; |
83 |
import java.util.logging.Logger; |
73 |
import java.util.regex.Matcher; |
84 |
import java.util.regex.Matcher; |
Lines 80-86
Link Here
|
80 |
import org.apache.lucene.search.MultiTermQuery; |
91 |
import org.apache.lucene.search.MultiTermQuery; |
81 |
import org.apache.lucene.search.PrefixQuery; |
92 |
import org.apache.lucene.search.PrefixQuery; |
82 |
import org.apache.lucene.search.Query; |
93 |
import org.apache.lucene.search.Query; |
|
|
94 |
import org.apache.lucene.search.ScoreDoc; |
83 |
import org.apache.lucene.search.TermQuery; |
95 |
import org.apache.lucene.search.TermQuery; |
|
|
96 |
import org.apache.lucene.search.TopScoreDocCollector; |
84 |
import org.apache.lucene.store.LockObtainFailedException; |
97 |
import org.apache.lucene.store.LockObtainFailedException; |
85 |
import org.apache.maven.artifact.Artifact; |
98 |
import org.apache.maven.artifact.Artifact; |
86 |
import org.apache.maven.artifact.InvalidArtifactRTException; |
99 |
import org.apache.maven.artifact.InvalidArtifactRTException; |
Lines 106-115
Link Here
|
106 |
import org.apache.maven.index.creator.AbstractIndexCreator; |
119 |
import org.apache.maven.index.creator.AbstractIndexCreator; |
107 |
import org.apache.maven.index.SearchEngine; |
120 |
import org.apache.maven.index.SearchEngine; |
108 |
import org.apache.maven.index.context.IndexCreator; |
121 |
import org.apache.maven.index.context.IndexCreator; |
109 |
import org.apache.maven.index.creator.JarFileContentsIndexCreator; |
|
|
110 |
import org.apache.maven.index.creator.MavenArchetypeArtifactInfoIndexCreator; |
111 |
import org.apache.maven.index.creator.MavenPluginArtifactInfoIndexCreator; |
112 |
import org.apache.maven.index.creator.MinimalArtifactInfoIndexCreator; |
113 |
import org.apache.maven.index.updater.IndexUpdateRequest; |
122 |
import org.apache.maven.index.updater.IndexUpdateRequest; |
114 |
import org.apache.maven.index.updater.IndexUpdater; |
123 |
import org.apache.maven.index.updater.IndexUpdater; |
115 |
import org.apache.maven.index.updater.ResourceFetcher; |
124 |
import org.apache.maven.index.updater.ResourceFetcher; |
Lines 140-150
Link Here
|
140 |
import org.codehaus.plexus.classworlds.ClassWorld; |
149 |
import org.codehaus.plexus.classworlds.ClassWorld; |
141 |
import org.codehaus.plexus.classworlds.realm.ClassRealm; |
150 |
import org.codehaus.plexus.classworlds.realm.ClassRealm; |
142 |
import org.codehaus.plexus.component.repository.exception.ComponentLookupException; |
151 |
import org.codehaus.plexus.component.repository.exception.ComponentLookupException; |
|
|
152 |
import org.netbeans.api.progress.ProgressHandle; |
153 |
import org.netbeans.api.progress.ProgressHandleFactory; |
143 |
import org.netbeans.modules.maven.embedder.MavenEmbedder; |
154 |
import org.netbeans.modules.maven.embedder.MavenEmbedder; |
144 |
import org.netbeans.modules.maven.indexer.spi.ContextLoadedQuery; |
155 |
import org.netbeans.modules.maven.indexer.spi.ContextLoadedQuery; |
145 |
import org.openide.awt.StatusDisplayer; |
156 |
import org.openide.awt.StatusDisplayer; |
146 |
import org.openide.filesystems.FileObject; |
157 |
import org.openide.filesystems.FileObject; |
147 |
import org.openide.filesystems.FileUtil; |
158 |
import org.openide.filesystems.FileUtil; |
|
|
159 |
import org.openide.util.Cancellable; |
148 |
import org.openide.util.Exceptions; |
160 |
import org.openide.util.Exceptions; |
149 |
import org.openide.util.Lookup; |
161 |
import org.openide.util.Lookup; |
150 |
import org.openide.util.Mutex; |
162 |
import org.openide.util.Mutex; |
Lines 178-183
Link Here
|
178 |
private static final String NB_DEPENDENCY_GROUP = "nbdg"; //NOI18N |
190 |
private static final String NB_DEPENDENCY_GROUP = "nbdg"; //NOI18N |
179 |
private static final String NB_DEPENDENCY_ARTIFACT = "nbda"; //NOI18N |
191 |
private static final String NB_DEPENDENCY_ARTIFACT = "nbda"; //NOI18N |
180 |
private static final String NB_DEPENDENCY_VERSION = "nbdv"; //NOI18N |
192 |
private static final String NB_DEPENDENCY_VERSION = "nbdv"; //NOI18N |
|
|
193 |
/** Used for indexing all classes in a local repository artifact: bar.Foo<foo.Bar (class bar.Foo is used by class for.Bar) |
194 |
* < may be confusing to read, but will speed up the lucene prefix search: query: bar.Foo<* |
195 |
*/ |
196 |
private static final String NB_DEPENDENCY_CLASSES = "nbdc"; //NOI18N |
197 |
/** Used for separating a class and it's dependencies as field value of {@link #NB_DEPENDENCY_CLASSES} bar.Foo<foo.Bar */ |
198 |
private static final String NB_DEPENDENCY_CLASS_SEPARATOR = "<"; |
181 |
private static final Logger LOGGER = Logger.getLogger(NexusRepositoryIndexerImpl.class.getName()); |
199 |
private static final Logger LOGGER = Logger.getLogger(NexusRepositoryIndexerImpl.class.getName()); |
182 |
/*custom Index creators*/ |
200 |
/*custom Index creators*/ |
183 |
/** |
201 |
/** |
Lines 281-287
Link Here
|
281 |
LOGGER.log(Level.FINE, "Local context changed: {0}, unload/load", info.getId()); |
299 |
LOGGER.log(Level.FINE, "Local context changed: {0}, unload/load", info.getId()); |
282 |
unloadIndexingContext(info); |
300 |
unloadIndexingContext(info); |
283 |
} else { |
301 |
} else { |
284 |
LOGGER.log(Level.FINER, "Skipping Context: {0}, already loaded.", info.getId()); |
302 |
LOGGER.log(Level.FINE, "Skipping Context: {0}, already loaded.", info.getId()); |
285 |
break LOAD; // XXX does it suffice to just return here, or is code after block needed? |
303 |
break LOAD; // XXX does it suffice to just return here, or is code after block needed? |
286 |
} |
304 |
} |
287 |
} |
305 |
} |
Lines 296-312
Link Here
|
296 |
|
314 |
|
297 |
List<IndexCreator> creators = new ArrayList<IndexCreator>(); |
315 |
List<IndexCreator> creators = new ArrayList<IndexCreator>(); |
298 |
try { |
316 |
try { |
299 |
// XXX MINDEXER-34: maven-plugin must follow min, so using embedder.lookupList(IndexCreator.class) does not work |
317 |
creators.addAll(embedder.lookupList(IndexCreator.class)); |
300 |
for (String id : new String[] {MinimalArtifactInfoIndexCreator.ID, MavenPluginArtifactInfoIndexCreator.ID, MavenArchetypeArtifactInfoIndexCreator.ID, JarFileContentsIndexCreator.ID}) { |
|
|
301 |
creators.add(embedder.lookup(IndexCreator.class, id)); |
302 |
} |
303 |
} catch (ComponentLookupException x) { |
318 |
} catch (ComponentLookupException x) { |
304 |
throw new IOException(x); |
319 |
throw new IOException(x); |
305 |
} |
320 |
} |
306 |
if (info.isLocal()) { // #164593 |
321 |
if (info.isLocal()) { // #164593 |
307 |
creators.add(new NbIndexCreator()); |
322 |
creators.add(new NbIndexCreator()); |
|
|
323 |
creators.add(new NbClassDependenciesIndexCreator()); |
308 |
} else { |
324 |
} else { |
309 |
creators.add(new NotifyingIndexCreator()); |
325 |
creators.add(new NotifyingIndexCreator(info)); |
310 |
} |
326 |
} |
311 |
try { |
327 |
try { |
312 |
indexer.addIndexingContextForced( |
328 |
indexer.addIndexingContextForced( |
Lines 317-323
Link Here
|
317 |
info.isRemoteDownloadable() ? info.getRepositoryUrl() : null, // repositoryUrl |
333 |
info.isRemoteDownloadable() ? info.getRepositoryUrl() : null, // repositoryUrl |
318 |
info.isRemoteDownloadable() ? indexUpdateUrl : null, |
334 |
info.isRemoteDownloadable() ? indexUpdateUrl : null, |
319 |
creators); |
335 |
creators); |
320 |
LOGGER.log(Level.FINE, "using index creators: {0}", creators); |
|
|
321 |
} catch (IOException ex) { |
336 |
} catch (IOException ex) { |
322 |
LOGGER.log(Level.INFO, "Found a broken index at " + loc.getAbsolutePath(), ex); |
337 |
LOGGER.log(Level.INFO, "Found a broken index at " + loc.getAbsolutePath(), ex); |
323 |
FileUtils.deleteDirectory(loc); |
338 |
FileUtils.deleteDirectory(loc); |
Lines 517-523
Link Here
|
517 |
} |
532 |
} |
518 |
} |
533 |
} |
519 |
if (nic != null) { |
534 |
if (nic != null) { |
520 |
nic.start(listener); |
535 |
nic.start(); |
521 |
} |
536 |
} |
522 |
try { |
537 |
try { |
523 |
remoteIndexUpdater.fetchAndUpdateIndex(iur); |
538 |
remoteIndexUpdater.fetchAndUpdateIndex(iur); |
Lines 554-569
Link Here
|
554 |
} |
569 |
} |
555 |
/** Just tracks what is being unpacked after a remote index has been downloaded. */ |
570 |
/** Just tracks what is being unpacked after a remote index has been downloaded. */ |
556 |
private static final class NotifyingIndexCreator implements IndexCreator { |
571 |
private static final class NotifyingIndexCreator implements IndexCreator { |
557 |
private RemoteIndexTransferListener listener; |
572 |
private final RepositoryInfo beingIndexed; |
558 |
NotifyingIndexCreator() {} |
573 |
private ProgressHandle handle; |
559 |
private void start(RemoteIndexTransferListener listener) { |
574 |
private final AtomicBoolean canceled = new AtomicBoolean(); |
560 |
this.listener = listener; |
575 |
NotifyingIndexCreator(RepositoryInfo info) { |
|
|
576 |
beingIndexed = info; |
577 |
} |
578 |
private void start() { |
579 |
handle = null; |
580 |
canceled.set(false); |
561 |
} |
581 |
} |
562 |
private void end() { |
582 |
private void end() { |
563 |
listener = null; |
583 |
if (handle != null) { |
|
|
584 |
handle.finish(); |
585 |
handle = null; |
586 |
} |
587 |
canceled.set(false); |
564 |
} |
588 |
} |
565 |
public @Override void updateDocument(ArtifactInfo artifactInfo, Document document) { |
589 |
public @Override void updateDocument(ArtifactInfo artifactInfo, Document document) { |
566 |
listener.unpackingProgress(artifactInfo.groupId + ':' + artifactInfo.artifactId); |
590 |
if (canceled.get()) { |
|
|
591 |
throw new Cancellation(); |
592 |
} |
593 |
if (handle == null) { |
594 |
handle = ProgressHandleFactory.createHandle(NbBundle.getMessage(NexusRepositoryIndexerImpl.class, "LBL_unpacking", beingIndexed.getName()), new Cancellable() { { |
595 |
Cancellation.register(this); |
596 |
} |
597 |
public @Override boolean cancel() { |
598 |
return canceled.compareAndSet(false, true); |
599 |
} |
600 |
}); |
601 |
handle.start(); |
602 |
} |
603 |
handle.progress(artifactInfo.groupId + ':' + artifactInfo.artifactId); |
567 |
} |
604 |
} |
568 |
public @Override Collection<IndexerField> getIndexerFields() { |
605 |
public @Override Collection<IndexerField> getIndexerFields() { |
569 |
return Collections.emptySet(); |
606 |
return Collections.emptySet(); |
Lines 915-920
Link Here
|
915 |
} |
952 |
} |
916 |
|
953 |
|
917 |
@Override |
954 |
@Override |
|
|
955 |
public Set<String> findDependendClassesFromClass(final String className, final List<RepositoryInfo> repos) { |
956 |
try { |
957 |
final Set<String> dependendClasses = new HashSet<String>(); |
958 |
for (final RepositoryInfo repo : repos) { |
959 |
if (repo.isLocal()) { |
960 |
getRepoMutex(repo).writeAccess(new Mutex.ExceptionAction<Void>() { |
961 |
|
962 |
public @Override |
963 |
Void run() throws Exception { |
964 |
loadIndexingContext(repo); |
965 |
final String searchString = className.replace(".", "/"); |
966 |
// TODO Query is not really efficient, should return only hits which contain: 'className<' in field |
967 |
final Query refClassQuery = indexer.constructQuery(NbClassDependenciesIndexCreator.FLD_NB_DEPENDENCY_CLASS.getOntology(), new StringSearchExpression(searchString)); |
968 |
final TopScoreDocCollector collector = TopScoreDocCollector.create(MAX_RESULT_COUNT, true); |
969 |
final Collection<IndexingContext> contexts = getContexts(new RepositoryInfo[]{repo}); |
970 |
final IndexingContext context = (IndexingContext) contexts.toArray()[0]; |
971 |
context.getIndexSearcher().search(refClassQuery, collector); |
972 |
final ScoreDoc[] hits = collector.topDocs().scoreDocs; |
973 |
for (ScoreDoc hit : hits) { |
974 |
int docId = hit.doc; |
975 |
Document d = context.getIndexSearcher().doc(docId); |
976 |
// LOGGER.log(Level.INFO, className + "uses: " + d.get(NB_DEPENDENCY_CLASSES)); |
977 |
final Set<String> refClasses = parseField(searchString, d.get(NB_DEPENDENCY_CLASSES)); |
978 |
for (String binaryClass : refClasses) { |
979 |
dependendClasses.add(binaryClass); |
980 |
} |
981 |
} |
982 |
return null; |
983 |
} |
984 |
|
985 |
private Set<String> parseField(final String className, final String fldValue) { |
986 |
final Set<String> refClasses = new HashSet<String>(); |
987 |
final String[] split = fldValue.split("\n"); |
988 |
for (String grp : split) { |
989 |
// TODO this condition is only necessary because the not fully working query --> it filters false positives. |
990 |
if (grp.contains(className + NB_DEPENDENCY_CLASS_SEPARATOR)) { |
991 |
final String classGrp = grp.substring(grp.indexOf(NB_DEPENDENCY_CLASS_SEPARATOR) + 1, grp.length() - 1); |
992 |
final String[] classes = classGrp.split(","); |
993 |
refClasses.addAll(Arrays.asList(classes)); |
994 |
} |
995 |
} |
996 |
return refClasses; |
997 |
} |
998 |
|
999 |
}); |
1000 |
} |
1001 |
} |
1002 |
return dependendClasses; |
1003 |
} catch (MutexException ex) { |
1004 |
Exceptions.printStackTrace(ex); |
1005 |
} |
1006 |
return Collections.<String>emptySet(); |
1007 |
} |
1008 |
|
1009 |
@Override |
918 |
public List<NBVersionInfo> findDependencyUsage(final String groupId, final String artifactId, final String version, List<RepositoryInfo> repos) { |
1010 |
public List<NBVersionInfo> findDependencyUsage(final String groupId, final String artifactId, final String version, List<RepositoryInfo> repos) { |
919 |
try { |
1011 |
try { |
920 |
final List<NBVersionInfo> infos = new ArrayList<NBVersionInfo>(); |
1012 |
final List<NBVersionInfo> infos = new ArrayList<NBVersionInfo>(); |
Lines 1213-1220
Link Here
|
1213 |
// we don't want javadoc and sources shown anywhere, we use the getJavadocExists(), getSourceExists() methods. |
1305 |
// we don't want javadoc and sources shown anywhere, we use the getJavadocExists(), getSourceExists() methods. |
1214 |
continue; |
1306 |
continue; |
1215 |
} |
1307 |
} |
|
|
1308 |
// fextension != packaging - e.g a pom could be packaging "bundle" but from type/extension "jar" |
1216 |
NBVersionInfo nbvi = new NBVersionInfo(ai.repository, ai.groupId, ai.artifactId, |
1309 |
NBVersionInfo nbvi = new NBVersionInfo(ai.repository, ai.groupId, ai.artifactId, |
1217 |
ai.version, ai.packaging, ai.packaging, ai.name, ai.description, ai.classifier); |
1310 |
ai.version, ai.fextension, ai.packaging, ai.name, ai.description, ai.classifier); |
1218 |
/*Javadoc & Sources*/ |
1311 |
/*Javadoc & Sources*/ |
1219 |
nbvi.setJavadocExists(ai.javadocExists == ArtifactAvailablility.PRESENT); |
1312 |
nbvi.setJavadocExists(ai.javadocExists == ArtifactAvailablility.PRESENT); |
1220 |
nbvi.setSourcesExists(ai.sourcesExists == ArtifactAvailablility.PRESENT); |
1313 |
nbvi.setSourcesExists(ai.sourcesExists == ArtifactAvailablility.PRESENT); |
Lines 1237-1243
Link Here
|
1237 |
} |
1330 |
} |
1238 |
return q; |
1331 |
return q; |
1239 |
} |
1332 |
} |
|
|
1333 |
|
1334 |
/** |
1335 |
* Scanns every class in all artifacts located in local maven repository for it's class dependencies. |
1336 |
*/ |
1337 |
private static class NbClassDependenciesIndexCreator extends AbstractIndexCreator { |
1240 |
|
1338 |
|
|
|
1339 |
private final List<ArtifactRepository> remoteRepos; |
1340 |
NbClassDependenciesIndexCreator() { |
1341 |
remoteRepos = new ArrayList<ArtifactRepository>(); |
1342 |
for (RepositoryInfo info : RepositoryPreferences.getInstance().getRepositoryInfos()) { |
1343 |
if (!info.isLocal()) { |
1344 |
remoteRepos.add(new MavenArtifactRepository(info.getId(), info.getRepositoryUrl(), new DefaultRepositoryLayout(), new ArtifactRepositoryPolicy(), new ArtifactRepositoryPolicy())); |
1345 |
} |
1346 |
} |
1347 |
} |
1348 |
|
1349 |
private WeakReference<MavenEmbedder> embedderRef = null; |
1350 |
|
1351 |
private MavenEmbedder getEmbedder() { |
1352 |
MavenEmbedder res = (null != embedderRef ? embedderRef.get() : null); |
1353 |
if (null == res) { |
1354 |
res = EmbedderFactory.getOnlineEmbedder(); |
1355 |
embedderRef = new WeakReference<MavenEmbedder>(res); |
1356 |
} |
1357 |
return res; |
1358 |
} |
1359 |
|
1360 |
private MavenProject load(ArtifactInfo ai) { |
1361 |
try { |
1362 |
Artifact projectArtifact = getEmbedder().createArtifact( |
1363 |
ai.groupId, |
1364 |
ai.artifactId, |
1365 |
ai.version, |
1366 |
ai.packaging != null ? ai.packaging : "jar"); |
1367 |
DefaultProjectBuildingRequest dpbr = new DefaultProjectBuildingRequest(); |
1368 |
dpbr.setLocalRepository(getEmbedder().getLocalRepository()); |
1369 |
dpbr.setRemoteRepositories(remoteRepos); |
1370 |
dpbr.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL); |
1371 |
dpbr.setSystemProperties(getEmbedder().getSystemProperties()); |
1372 |
|
1373 |
ProjectBuildingResult res = getEmbedder().buildProject(projectArtifact, dpbr); |
1374 |
if (res.getProject() != null) { |
1375 |
return res.getProject(); |
1376 |
} else { |
1377 |
LOGGER.log(Level.FINE, "No project model from repository for {0}: {1}", new Object[]{ai, res.getProblems()}); |
1378 |
} |
1379 |
} catch (ProjectBuildingException ex) { |
1380 |
LOGGER.log(Level.FINE, "Failed to load project model from repository for {0}: {1}", new Object[]{ai, ex}); |
1381 |
} catch (Exception exception) { |
1382 |
LOGGER.log(Level.FINE, "Failed to load project model from repository for " + ai, exception); |
1383 |
} |
1384 |
return null; |
1385 |
} |
1386 |
|
1387 |
private Artifact artifact; |
1388 |
|
1389 |
public @Override void populateArtifactInfo(ArtifactContext context) throws IOException { |
1390 |
ArtifactInfo ai = context.getArtifactInfo(); |
1391 |
if (ai.classifier != null) { |
1392 |
//don't process items with classifier |
1393 |
return; |
1394 |
} |
1395 |
try { |
1396 |
MavenProject mp = load(ai); |
1397 |
|
1398 |
if (mp != null) { |
1399 |
artifact = getEmbedder().getLocalRepository().find(mp.getArtifact()); |
1400 |
ai.setFieldValue(NbClassDependenciesIndexCreator.FLD_NB_DEPENDENCY_CLASS.getOntology(), "empty"); |
1401 |
} |
1402 |
} catch (InvalidArtifactRTException ex) { |
1403 |
Exceptions.printStackTrace(ex); |
1404 |
} |
1405 |
} |
1406 |
|
1407 |
@Override |
1408 |
public boolean updateArtifactInfo(Document document, ArtifactInfo artifactInfo) { |
1409 |
// Add the data to the ArtifactInfo |
1410 |
artifactInfo.setFieldValue(NbClassDependenciesIndexCreator.FLD_NB_DEPENDENCY_CLASS.getOntology(), document.get(NB_DEPENDENCY_CLASSES)); |
1411 |
return true; |
1412 |
} |
1413 |
|
1414 |
public @Override void updateDocument(ArtifactInfo ai, Document doc) { |
1415 |
final Map<String, Set<String>> classDeps = new HashMap<String, Set<String>>(); |
1416 |
Map<String, byte[]> classfiles = new TreeMap<String, byte[]>(); |
1417 |
File jar = null; |
1418 |
if (artifact != null) { |
1419 |
// TODO are there any other possible archive types? |
1420 |
if (isArchiveSupported(artifact) && isArtifactFileArchive(artifact)) { |
1421 |
try { |
1422 |
read(new JarFile(artifact.getFile()), classfiles, new HashSet<File>(Collections.singleton(jar)), ""); |
1423 |
for (Map.Entry<String, byte[]> entry : classfiles.entrySet()) { |
1424 |
String clazz = entry.getKey(); |
1425 |
byte[] data = entry.getValue(); |
1426 |
addDependenciesToMap(clazz, data, classDeps); |
1427 |
} |
1428 |
addMapToIndex(classDeps, doc); |
1429 |
} catch (IOException ex) { |
1430 |
Exceptions.printStackTrace(ex); |
1431 |
} |
1432 |
} |
1433 |
} |
1434 |
} |
1435 |
|
1436 |
private boolean isArtifactFileArchive(final Artifact arti) { |
1437 |
final File artifactFile = arti.getFile(); |
1438 |
return artifactFile != null && artifactFile.exists(); |
1439 |
} |
1440 |
|
1441 |
private boolean isArchiveSupported(final Artifact arti) { |
1442 |
final String type = arti.getType(); |
1443 |
if (type.equals("jar")) { |
1444 |
return true; |
1445 |
} else if (type.equals("war")) { |
1446 |
return true; |
1447 |
} |
1448 |
return false; |
1449 |
} |
1450 |
|
1451 |
private void addDependenciesToMap(final String clazz, final byte[] data, final Map<String,Set<String>> depsMap) throws IOException{ |
1452 |
//log("Verifying linkage of " + clazz.replace('/', '.'), Project.MSG_DEBUG); |
1453 |
final Set<String> dependencies = dependencies(data); |
1454 |
|
1455 |
for (String usedClass : dependencies) { |
1456 |
// filter classes out which are referring themselfs |
1457 |
if (!usedClass.equals(clazz)) { |
1458 |
Set<String> refClasses = depsMap.get(usedClass); |
1459 |
if (refClasses == null) { |
1460 |
refClasses = new HashSet<String>(); |
1461 |
depsMap.put(usedClass, refClasses); |
1462 |
} |
1463 |
refClasses.add(clazz); |
1464 |
} |
1465 |
} |
1466 |
} |
1467 |
|
1468 |
private void addMapToIndex(final Map<String, Set<String>> classDeps, final Document doc) { |
1469 |
final StringBuilder fldBuilder = new StringBuilder(); |
1470 |
for (Entry<String, Set<String>> entry : classDeps.entrySet()) { |
1471 |
String usedClass = entry.getKey(); |
1472 |
// add usedClass with a separator |
1473 |
fldBuilder.append(usedClass.replace(".", "/")).append(NB_DEPENDENCY_CLASS_SEPARATOR); |
1474 |
// add all classes which refer usedClass (,) seperated |
1475 |
Set<String> value = entry.getValue(); |
1476 |
for (String refClass : value) { |
1477 |
fldBuilder.append(refClass.replace(".", "/")).append(","); |
1478 |
} |
1479 |
// Mark the end of all referring classes |
1480 |
fldBuilder.append("\n"); |
1481 |
} |
1482 |
LOGGER.log(Level.FINE, "Class dependencies index field: {0}", fldBuilder.toString()); |
1483 |
doc.add(FLD_NB_DEPENDENCY_CLASS.toField(fldBuilder.toString())); |
1484 |
} |
1485 |
|
1486 |
static void read(JarFile jf, Map<String, byte[]> classfiles, Set<File> alreadyRead, String ignores) throws IOException { |
1487 |
Pattern p = (ignores != null)? Pattern.compile(ignores): null; |
1488 |
Enumeration<JarEntry> e = jf.entries(); |
1489 |
while (e.hasMoreElements()) { |
1490 |
JarEntry entry = e.nextElement(); |
1491 |
String name = entry.getName(); |
1492 |
if (!name.endsWith(".class")) { |
1493 |
continue; |
1494 |
} |
1495 |
String clazz = name.substring(0, name.length() - 6).replace('/', '.'); |
1496 |
if (p != null && p.matcher(clazz).matches()) { |
1497 |
continue; |
1498 |
} |
1499 |
ByteArrayOutputStream baos = new ByteArrayOutputStream(Math.max((int) entry.getSize(), 0)); |
1500 |
InputStream is = jf.getInputStream(entry); |
1501 |
try { |
1502 |
byte[] buf = new byte[4096]; |
1503 |
int read; |
1504 |
while ((read = is.read(buf)) != -1) { |
1505 |
baos.write(buf, 0, read); |
1506 |
} |
1507 |
} finally { |
1508 |
is.close(); |
1509 |
} |
1510 |
classfiles.put(clazz, baos.toByteArray()); |
1511 |
} |
1512 |
} |
1513 |
|
1514 |
|
1515 |
static Set<String> dependencies(byte[] data) throws IOException { |
1516 |
Set<String> result = new TreeSet<String>(); |
1517 |
DataInput input = new DataInputStream(new ByteArrayInputStream(data)); |
1518 |
skip(input, 8); // magic, minor_version, major_version |
1519 |
int size = input.readUnsignedShort() - 1; // constantPoolCount |
1520 |
String[] utf8Strings = new String[size]; |
1521 |
boolean[] isClassName = new boolean[size]; |
1522 |
boolean[] isDescriptor = new boolean[size]; |
1523 |
for (int i = 0; i < size; i++) { |
1524 |
byte tag = input.readByte(); |
1525 |
switch (tag) { |
1526 |
case 1: // CONSTANT_Utf8 |
1527 |
utf8Strings[i] = input.readUTF(); |
1528 |
break; |
1529 |
case 7: // CONSTANT_Class |
1530 |
int index = input.readUnsignedShort() - 1; |
1531 |
if (index >= size) { |
1532 |
throw new IOException("@" + i + ": CONSTANT_Class_info.name_index " + index + " too big for size of pool " + size); |
1533 |
} |
1534 |
//log("Class reference at " + index, Project.MSG_DEBUG); |
1535 |
isClassName[index] = true; |
1536 |
break; |
1537 |
case 3: // CONSTANT_Integer |
1538 |
case 4: // CONSTANT_Float |
1539 |
case 9: // CONSTANT_Fieldref |
1540 |
case 10: // CONSTANT_Methodref |
1541 |
case 11: // CONSTANT_InterfaceMethodref |
1542 |
skip(input, 4); |
1543 |
break; |
1544 |
case 12: // CONSTANT_NameAndType |
1545 |
skip(input, 2); |
1546 |
index = input.readUnsignedShort() - 1; |
1547 |
if (index >= size || index < 0) { |
1548 |
throw new IOException("@" + i + ": CONSTANT_NameAndType_info.descriptor_index " + index + " too big for size of pool " + size); |
1549 |
} |
1550 |
isDescriptor[index] = true; |
1551 |
break; |
1552 |
case 8: // CONSTANT_String |
1553 |
skip(input, 2); |
1554 |
break; |
1555 |
case 5: // CONSTANT_Long |
1556 |
case 6: // CONSTANT_Double |
1557 |
skip(input, 8); |
1558 |
i++; // weirdness in spec |
1559 |
break; |
1560 |
default: |
1561 |
LOGGER.log(Level.WARNING, "Unrecognized constant pool tag {0} at index {1}; running UTF-8 strings: {2}", new Object[]{tag, i, Arrays.asList(utf8Strings)}); |
1562 |
continue; |
1563 |
} |
1564 |
} |
1565 |
//task.log("UTF-8 strings: " + Arrays.asList(utf8Strings), Project.MSG_DEBUG); |
1566 |
for (int i = 0; i < size; i++) { |
1567 |
String s = utf8Strings[i]; |
1568 |
if (s != null) { |
1569 |
if (isClassName[i]) { |
1570 |
while (s.charAt(0) == '[') { |
1571 |
// array type |
1572 |
s = s.substring(1); |
1573 |
} |
1574 |
if (s.length() == 1) { |
1575 |
// primitive |
1576 |
continue; |
1577 |
} |
1578 |
String c; |
1579 |
if (s.charAt(s.length() - 1) == ';' && s.charAt(0) == 'L') { |
1580 |
// Uncommon but seems sometimes this happens. |
1581 |
c = s.substring(1, s.length() - 1); |
1582 |
} else { |
1583 |
c = s; |
1584 |
} |
1585 |
result.add(c.replace('/', '.')); |
1586 |
} else if (isDescriptor[i]) { |
1587 |
int idx = 0; |
1588 |
while ((idx = s.indexOf('L', idx)) != -1) { |
1589 |
int semi = s.indexOf(';', idx); |
1590 |
if (semi == -1) { |
1591 |
throw new IOException("Invalid type or descriptor: " + s); |
1592 |
} |
1593 |
result.add(s.substring(idx + 1, semi).replace('/', '.')); |
1594 |
idx = semi; |
1595 |
} |
1596 |
} |
1597 |
} |
1598 |
} |
1599 |
return result; |
1600 |
} |
1601 |
|
1602 |
private static void skip(DataInput input, int bytes) throws IOException { |
1603 |
int skipped = input.skipBytes(bytes); |
1604 |
if (skipped != bytes) { |
1605 |
throw new IOException("Truncated class file"); |
1606 |
} |
1607 |
} |
1608 |
|
1609 |
private static final String NS = "urn:NbClassDependenciesIndexCreator"; // NOI18N |
1610 |
public static final IndexerField FLD_NB_DEPENDENCY_CLASS = new IndexerField(new Field( |
1611 |
null, NS, NB_DEPENDENCY_CLASSES, "From a class's inside an artifact used class-dependencies"), |
1612 |
IndexerFieldVersion.V3, NB_DEPENDENCY_CLASSES, "From a class's inside an artifact used class-dependencies", Store.YES, Index.ANALYZED); |
1613 |
@Override |
1614 |
public Collection<IndexerField> getIndexerFields() { |
1615 |
return Arrays.asList(FLD_NB_DEPENDENCY_CLASS); |
1616 |
} |
1617 |
} |
1618 |
|
1241 |
private static class NbIndexCreator extends AbstractIndexCreator { |
1619 |
private static class NbIndexCreator extends AbstractIndexCreator { |
1242 |
|
1620 |
|
1243 |
private final List<ArtifactRepository> remoteRepos; |
1621 |
private final List<ArtifactRepository> remoteRepos; |
Lines 1273-1279
Link Here
|
1273 |
MavenProject mp = load(ai); |
1651 |
MavenProject mp = load(ai); |
1274 |
if (mp != null) { |
1652 |
if (mp != null) { |
1275 |
List<Dependency> dependencies = mp.getDependencies(); |
1653 |
List<Dependency> dependencies = mp.getDependencies(); |
1276 |
LOGGER.log(Level.FINER, "Successfully loaded project model from repository for {0} with {1} dependencies", new Object[] {ai, dependencies.size()}); |
1654 |
LOGGER.log(Level.FINE, "Successfully loaded project model from repository for {0} with {1} dependencies", new Object[] {ai, dependencies.size()}); |
1277 |
dependenciesByArtifact.put(ai, dependencies); |
1655 |
dependenciesByArtifact.put(ai, dependencies); |
1278 |
} |
1656 |
} |
1279 |
} catch (InvalidArtifactRTException ex) { |
1657 |
} catch (InvalidArtifactRTException ex) { |
Lines 1320-1331
Link Here
|
1320 |
if (res.getProject() != null) { |
1698 |
if (res.getProject() != null) { |
1321 |
return res.getProject(); |
1699 |
return res.getProject(); |
1322 |
} else { |
1700 |
} else { |
1323 |
LOGGER.log(Level.FINER, "No project model from repository for {0}: {1}", new Object[] {ai, res.getProblems()}); |
1701 |
LOGGER.log(Level.FINE, "No project model from repository for {0}: {1}", new Object[] {ai, res.getProblems()}); |
1324 |
} |
1702 |
} |
1325 |
} catch (ProjectBuildingException ex) { |
1703 |
} catch (ProjectBuildingException ex) { |
1326 |
LOGGER.log(Level.FINER, "Failed to load project model from repository for {0}: {1}", new Object[] {ai, ex}); |
1704 |
LOGGER.log(Level.FINE, "Failed to load project model from repository for {0}: {1}", new Object[] {ai, ex}); |
1327 |
} catch (Exception exception) { |
1705 |
} catch (Exception exception) { |
1328 |
LOGGER.log(Level.FINER, "Failed to load project model from repository for " + ai, exception); |
1706 |
LOGGER.log(Level.FINE, "Failed to load project model from repository for " + ai, exception); |
1329 |
} |
1707 |
} |
1330 |
return null; |
1708 |
return null; |
1331 |
} |
1709 |
} |