# This patch file was generated by NetBeans IDE # Following Index: paths are relative to: /Users/mkleint/src/core-main # This patch can be applied using context Tools: Patch action on respective folder. # It uses platform neutral UTF-8 encoding and \n newlines. # Above lines and this line are ignored by the patching process. Index: maven/src/org/netbeans/modules/maven/queries/AbstractMavenForBinaryQueryImpl.java --- maven/src/org/netbeans/modules/maven/queries/AbstractMavenForBinaryQueryImpl.java Base (BASE) +++ maven/src/org/netbeans/modules/maven/queries/AbstractMavenForBinaryQueryImpl.java Locally New @@ -0,0 +1,168 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2008 Sun Microsystems, Inc. + */ + +package org.netbeans.modules.maven.queries; + +import java.net.URI; +import java.net.URL; +import java.util.Collection; +import java.util.LinkedHashSet; +import org.netbeans.api.annotations.common.CheckForNull; +import org.netbeans.api.annotations.common.NullAllowed; +import org.netbeans.api.annotations.common.SuppressWarnings; +import org.netbeans.modules.maven.NbMavenProjectImpl; +import org.netbeans.modules.maven.api.FileUtilities; +import org.netbeans.api.java.queries.SourceForBinaryQuery; +import org.netbeans.api.project.Project; +import org.netbeans.modules.maven.spi.queries.JavaLikeRootProvider; +import org.netbeans.spi.java.queries.JavadocForBinaryQueryImplementation; +import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation2; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; + + +/** + * SourceForBinary and JavadocForBinary query impls. + * @author Milos Kleint + */ +abstract class AbstractMavenForBinaryQueryImpl implements SourceForBinaryQueryImplementation2, + JavadocForBinaryQueryImplementation { + + + + protected AbstractMavenForBinaryQueryImpl() { + } + + public @Override SourceForBinaryQuery.Result findSourceRoots(URL url) { + return findSourceRoots2(url); + } + + + static @CheckForNull String jarify(@NullAllowed String path) { // #200088 + return path != null ? path.replaceFirst("[.][^./]+$", ".jar") : null; + } + + static FileObject[] getProjectSrcRoots(Project p) { + NbMavenProjectImpl project = p.getLookup().lookup(NbMavenProjectImpl.class); + Collection toReturn = new LinkedHashSet(); + for (String item : project.getOriginalMavenProject().getCompileSourceRoots()) { + FileObject fo = FileUtilities.convertStringToFileObject(item); + if (fo != null) { + toReturn.add(fo); + } + } + for (URI genRoot : project.getGeneratedSourceRoots(false)) { + FileObject fo = FileUtilities.convertURItoFileObject(genRoot); + if (fo != null) { + toReturn.add(fo); + } + } + for (JavaLikeRootProvider rp : project.getLookup().lookupAll(JavaLikeRootProvider.class)) { + FileObject fo = project.getProjectDirectory().getFileObject("src/main/" + rp.kind()); + if (fo != null) { + toReturn.add(fo); + } + } + + URI[] res = project.getResources(false); + for (int i = 0; i < res.length; i++) { + FileObject fo = FileUtilities.convertURItoFileObject(res[i]); + if (fo != null) { + boolean ok = true; + //#166655 resource root cannot contain the real java/xxx roots + for (FileObject form : toReturn) { + if (FileUtil.isParentOf(fo, form)) { + ok = false; + break; + } + } + if (ok) { + toReturn.add(fo); + } + } + } + return toReturn.toArray(new FileObject[toReturn.size()]); + } + + static FileObject[] getProjectTestSrcRoots(Project p) { + NbMavenProjectImpl project = p.getLookup().lookup(NbMavenProjectImpl.class); + Collection toReturn = new LinkedHashSet(); + for (String item : project.getOriginalMavenProject().getTestCompileSourceRoots()) { + FileObject fo = FileUtilities.convertStringToFileObject(item); + if (fo != null) { + toReturn.add(fo); + } + } + for (URI genRoot : project.getGeneratedSourceRoots(true)) { + FileObject fo = FileUtilities.convertURItoFileObject(genRoot); + if (fo != null) { + toReturn.add(fo); + } + } + for (JavaLikeRootProvider rp : project.getLookup().lookupAll(JavaLikeRootProvider.class)) { + FileObject fo = project.getProjectDirectory().getFileObject("src/test/" + rp.kind()); + if (fo != null) { + toReturn.add(fo); + } + } + + URI[] res = project.getResources(true); + for (int i = 0; i < res.length; i++) { + FileObject fo = FileUtilities.convertURItoFileObject(res[i]); + if (fo != null) { + boolean ok = true; + //#166655 resource root cannot contain the real java/xxx roots + for (FileObject form : toReturn) { + if (FileUtil.isParentOf(fo, form)) { + ok = false; + break; + } + } + if (ok) { + toReturn.add(fo); + } + } + } + return toReturn.toArray(new FileObject[toReturn.size()]); + } + +} Index: maven/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImpl.java --- maven/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImpl.java Base (BASE) +++ maven/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImpl.java Locally Modified (Based On LOCAL) @@ -71,6 +71,7 @@ import org.openide.util.ChangeSupport; import org.openide.util.Lookup; import org.openide.util.NbPreferences; +import org.openide.util.WeakListeners; import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; @@ -106,6 +107,10 @@ project.getProjectWatcher().addPropertyChangeListener(projectListener); } + public static String cacheKey(String groupId, String artifactId, String version) { + return groupId + ':' + artifactId + ":" + version; + } + public void registerCoordinates(String groupId, String artifactId, String version, URL owner) { String oldkey = groupId + ':' + artifactId; //remove old key if pointing to the same project @@ -113,7 +118,7 @@ prefs().remove(oldkey); } - String key = oldkey + ":" + version; + String key = cacheKey(groupId, artifactId, version); String prevKey = reversePrefs().get(owner.toString(), null); if (prevKey != null && !prevKey.equals(key)) { prefs().remove(prevKey); @@ -228,7 +233,7 @@ public Project getOwner(String groupId, String artifactId, String version) { LOG.log(Level.FINER, "Checking {0} / {1} / {2}", new Object[] {groupId, artifactId, version}); String oldKey = groupId + ":" + artifactId; - String key = oldKey + ":" + version; + String key = cacheKey(groupId, artifactId, version); String ownerURI = prefs().get(key, null); boolean usingOldKey = false; if (ownerURI == null) { @@ -282,7 +287,6 @@ } else { prefs().remove(key); // stale } - //TODO fire change.. } } else { LOG.log(Level.FINE, "No known owner for {0}", key); @@ -293,7 +297,7 @@ public File getOwnerPOM(String groupId, String artifactId, String version) { LOG.log(Level.FINER, "Checking {0} / {1} / {2} (POM only)", new Object[] {groupId, artifactId, version}); String oldKey = groupId + ":" + artifactId; - String key = oldKey + ":" + version; + String key = cacheKey(groupId, artifactId, version); String ownerURI = prefs().get(key, null); boolean usingOldKey = false; if (ownerURI == null) { Index: maven/src/org/netbeans/modules/maven/queries/MavenForBinaryQueryImpl.java --- maven/src/org/netbeans/modules/maven/queries/MavenForBinaryQueryImpl.java Base (BASE) +++ maven/src/org/netbeans/modules/maven/queries/MavenForBinaryQueryImpl.java Locally Modified (Based On LOCAL) @@ -44,28 +44,20 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.io.File; -import java.net.URI; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.HashMap; -import java.util.LinkedHashSet; import java.util.List; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.netbeans.api.annotations.common.CheckForNull; import org.netbeans.api.annotations.common.NullAllowed; -import org.netbeans.api.annotations.common.SuppressWarnings; -import org.netbeans.modules.maven.NbMavenProjectImpl; -import org.netbeans.modules.maven.api.NbMavenProject; -import org.netbeans.modules.maven.api.FileUtilities; import org.netbeans.api.java.queries.JavadocForBinaryQuery; -import org.netbeans.api.java.queries.SourceForBinaryQuery; import org.netbeans.api.project.Project; +import org.netbeans.modules.maven.NbMavenProjectImpl; +import org.netbeans.modules.maven.api.NbMavenProject; import org.netbeans.modules.maven.spi.queries.ForeignClassBundler; -import org.netbeans.modules.maven.spi.queries.JavaLikeRootProvider; import org.netbeans.spi.java.queries.JavadocForBinaryQueryImplementation; import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation; import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation2; @@ -79,13 +71,13 @@ * @author Milos Kleint */ @ProjectServiceProvider(service={SourceForBinaryQueryImplementation.class, SourceForBinaryQueryImplementation2.class, JavadocForBinaryQueryImplementation.class}, projectType="org-netbeans-modules-maven") -public class MavenForBinaryQueryImpl implements SourceForBinaryQueryImplementation2, - JavadocForBinaryQueryImplementation { +public class MavenForBinaryQueryImpl extends AbstractMavenForBinaryQueryImpl { private final Project p; private final HashMap map; public MavenForBinaryQueryImpl(Project proj) { + super(); p = proj; map = new HashMap(); NbMavenProject.addPropertyChangeListener(proj, new PropertyChangeListener() { @@ -103,19 +95,12 @@ }); } - public @Override SourceForBinaryQuery.Result findSourceRoots(URL url) { - return findSourceRoots2(url); - } - public @Override SourceForBinaryQueryImplementation2.Result findSourceRoots2(URL url) { synchronized (map) { BinResult toReturn = map.get(url.toString()); if (toReturn != null) { return toReturn; } - if (url.getProtocol().equals("jar") && checkURL(url) != -1) { //NOI18N - toReturn = new BinResult(url); - } if (url.getProtocol().equals("file")) { //NOI18N int result = checkURL(url); if (result == 1 || result == 0) { @@ -153,8 +138,7 @@ * 0 - source * 1 - test source */ - @SuppressWarnings("DMI_BLOCKING_METHODS_ON_URL") - private int checkURL(URL url) { + protected int checkURL(URL url) { NbMavenProjectImpl project = p.getLookup().lookup(NbMavenProjectImpl.class); if ("file".equals(url.getProtocol())) { //NOI18N // true for directories. @@ -166,111 +150,9 @@ return -1; } } - if (Boolean.getBoolean("mevenide.projectLinksDisable")) { // #198951 return -1; } - File file = FileUtil.archiveOrDirForURL(url); - if (file != null) { - String filepath = file.getAbsolutePath().replace('\\', '/'); //NOI18N - String path = jarify(project.getArtifactRelativeRepositoryPath()); - int ret = path == null ? -1 : filepath.endsWith(path) ? 0 : -1; - if (ret == -1) { - path = jarify(project.getTestArtifactRelativeRepositoryPath()); - ret = path == null ? -1 : filepath.endsWith(path) ? 1 : -1; - } - return ret; - } - return -1; - } - static @CheckForNull String jarify(@NullAllowed String path) { // #200088 - return path != null ? path.replaceFirst("[.][^./]+$", ".jar") : null; - } - private FileObject[] getSrcRoot() { - NbMavenProjectImpl project = p.getLookup().lookup(NbMavenProjectImpl.class); - Collection toReturn = new LinkedHashSet(); - for (String item : project.getOriginalMavenProject().getCompileSourceRoots()) { - FileObject fo = FileUtilities.convertStringToFileObject(item); - if (fo != null) { - toReturn.add(fo); - } - } - for (URI genRoot : project.getGeneratedSourceRoots(false)) { - FileObject fo = FileUtilities.convertURItoFileObject(genRoot); - if (fo != null) { - toReturn.add(fo); - } - } - for (JavaLikeRootProvider rp : project.getLookup().lookupAll(JavaLikeRootProvider.class)) { - FileObject fo = project.getProjectDirectory().getFileObject("src/main/" + rp.kind()); - if (fo != null) { - toReturn.add(fo); - } - } - - URI[] res = project.getResources(false); - for (int i = 0; i < res.length; i++) { - FileObject fo = FileUtilities.convertURItoFileObject(res[i]); - if (fo != null) { - boolean ok = true; - //#166655 resource root cannot contain the real java/xxx roots - for (FileObject form : toReturn) { - if (FileUtil.isParentOf(fo, form)) { - ok = false; - break; - } - } - if (ok) { - toReturn.add(fo); - } - } - } - return toReturn.toArray(new FileObject[toReturn.size()]); - } - - private FileObject[] getTestSrcRoot() { - NbMavenProjectImpl project = p.getLookup().lookup(NbMavenProjectImpl.class); - Collection toReturn = new LinkedHashSet(); - for (String item : project.getOriginalMavenProject().getTestCompileSourceRoots()) { - FileObject fo = FileUtilities.convertStringToFileObject(item); - if (fo != null) { - toReturn.add(fo); - } - } - for (URI genRoot : project.getGeneratedSourceRoots(true)) { - FileObject fo = FileUtilities.convertURItoFileObject(genRoot); - if (fo != null) { - toReturn.add(fo); - } - } - for (JavaLikeRootProvider rp : project.getLookup().lookupAll(JavaLikeRootProvider.class)) { - FileObject fo = project.getProjectDirectory().getFileObject("src/test/" + rp.kind()); - if (fo != null) { - toReturn.add(fo); - } - } - - URI[] res = project.getResources(true); - for (int i = 0; i < res.length; i++) { - FileObject fo = FileUtilities.convertURItoFileObject(res[i]); - if (fo != null) { - boolean ok = true; - //#166655 resource root cannot contain the real java/xxx roots - for (FileObject form : toReturn) { - if (FileUtil.isParentOf(fo, form)) { - ok = false; - break; - } - } - if (ok) { - toReturn.add(fo); - } - } - } - return toReturn.toArray(new FileObject[toReturn.size()]); - } - - private URL[] getJavadocRoot() { //TODO shall we delegate to "possibly" generated javadoc in project or in site? return new URL[0]; @@ -291,9 +173,9 @@ public @Override FileObject[] getRoots() { int xxx = checkURL(url); if (xxx == 0) { - results = getSrcRoot(); + results = getProjectSrcRoots(p); } else if (xxx == 1) { - results = getTestSrcRoot(); + results = getProjectTestSrcRoots(p); } else { results = new FileObject[0]; } Index: maven/src/org/netbeans/modules/maven/queries/RepositoryJavadocForBinaryQueryImpl.java --- maven/src/org/netbeans/modules/maven/queries/RepositoryJavadocForBinaryQueryImpl.java Base (BASE) +++ maven/src/org/netbeans/modules/maven/queries/RepositoryJavadocForBinaryQueryImpl.java Locally Deleted @@ -1,219 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2010 Oracle and/or its affiliates. All rights reserved. - * - * Oracle and Java are registered trademarks of Oracle and/or its affiliates. - * Other names may be trademarks of their respective owners. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common - * Development and Distribution License("CDDL") (collectively, the - * "License"). You may not use this file except in compliance with the - * License. You can obtain a copy of the License at - * http://www.netbeans.org/cddl-gplv2.html - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the - * specific language governing permissions and limitations under the - * License. When distributing the software, include this License Header - * Notice in each file and include the License file at - * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the GPL Version 2 section of the License file that - * accompanied this code. If applicable, add the following below the - * License Header, with the fields enclosed by brackets [] replaced by - * your own identifying information: - * "Portions Copyrighted [year] [name of copyright owner]" - * - * If you wish your version of this file to be governed by only the CDDL - * or only the GPL Version 2, indicate your decision by adding - * "[Contributor] elects to include this software in this distribution - * under the [CDDL or GPL Version 2] license." If you do not indicate a - * single choice of license, a recipient has the option to distribute - * your version of this file under either the CDDL, the GPL Version 2 or - * to extend the choice of license to its licensees as provided above. - * However, if you add GPL Version 2 code and therefore, elected the GPL - * Version 2 license, then the option applies only if the new code is - * made subject to such option by the copyright holder. - * - * Contributor(s): - * - * Portions Copyrighted 2008 Sun Microsystems, Inc. - */ - -package org.netbeans.modules.maven.queries; - -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Date; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.swing.event.ChangeListener; -import org.netbeans.api.java.queries.JavadocForBinaryQuery; -import org.netbeans.spi.java.project.support.JavadocAndSourceRootDetection; -import org.netbeans.spi.java.queries.JavadocForBinaryQueryImplementation; -import org.openide.ErrorManager; -import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileUtil; -import org.openide.filesystems.URLMapper; -import org.openide.util.Exceptions; -import org.openide.modules.InstalledFileLocator; -import org.openide.util.lookup.ServiceProvider; - -/** - * - * JavadocForBinaryQueryImplementation implementation - * for items in the maven repository. It checks the artifact and - * looks for the same artifact but of type "javadoc.jar" or "javadoc" - * @author Milos Kleint - */ -@ServiceProvider(service=JavadocForBinaryQueryImplementation.class, position=999) -public class RepositoryJavadocForBinaryQueryImpl implements JavadocForBinaryQueryImplementation { - - /** - * Find any Javadoc corresponding to the given classpath root containing - * Java classes. - *

- * Any absolute URL may be used but typically it will use the file - * protocol for directory entries and jar protocol for JAR entries - * (e.g. jar:file:/tmp/foo.jar!/). - *

- * @param binaryRoot the class path root of Java class files - * @return a result object encapsulating the roots and permitting changes to - * be listened to, or null if the binary root is not recognized - */ - @Override public JavadocForBinaryQuery.Result findJavadoc(URL url) { - File stored = SourceJavadocByHash.find(url, true); - if (stored != null) { - return new DocResult(stored); - } - URL binRoot = url; - if ("jar".equals(url.getProtocol())) { //NOI18N - binRoot = FileUtil.getArchiveFile(url); - } else { - // null for directories. - return null; - } - //hack for javaee6 jar docs which we ship with netbeans and which are not in any maven repository - if (binRoot.getPath().endsWith("/javax/javaee-api/6.0/javaee-api-6.0.jar") - || binRoot.getPath().endsWith("/javax/javaee-web-api/6.0/javaee-web-api-6.0.jar")) { //NOI18N - return new Javaee6Result(); - } - FileObject jarFO = URLMapper.findFileObject(binRoot); - if (jarFO != null) { - File jarFile = FileUtil.toFile(jarFO); - if (jarFile != null) { -// String name = jarFile.getName(); - File parent = jarFile.getParentFile(); - if (parent != null) { - File parentParent = parent.getParentFile(); - if (parentParent != null) { - // each repository artifact should have this structure - String artifact = parentParent.getName(); - String version = parent.getName(); - File javadoc = new File(parent, artifact + "-" + version + "-javadoc.jar"); //NOI18N - if (javadoc.exists() || - (jarFile.getName().startsWith(artifact) && jarFile.getName().contains(version))) { //#121657 - return new DocResult(javadoc); - } - } - } - } - } - return null; - - } - - private static class DocResult implements JavadocForBinaryQuery.Result { - private static final String ATTR_PATH = "lastRootCheckPath"; //NOI18N - private static final String ATTR_STAMP = "lastRootCheckStamp"; //NOI18N - private File file; - - DocResult(File javadoc) { - file = javadoc; - } - - @Override public void addChangeListener(ChangeListener changeListener) {} - - @Override public void removeChangeListener(ChangeListener changeListener) {} - - @Override public URL[] getRoots() { - try { - if (file.exists()) { - FileObject fo = FileUtil.toFileObject(file); - if (!FileUtil.isArchiveFile(fo)) { - //#124175 ignore any jar files that are not jar files (like when downloaded file is actually an error html page). - Logger.getLogger(RepositoryJavadocForBinaryQueryImpl.class.getName()).log(Level.INFO, "javadoc in repository is not really a JAR: {0}", file); - return new URL[0]; - } - //try detecting the source path root, in case the source jar has the sources not in root. - Date date = (Date) fo.getAttribute(ATTR_STAMP); - String path = (String) fo.getAttribute(ATTR_PATH); - if (date == null || fo.lastModified().after(date)) { - path = checkPath(FileUtil.getArchiveRoot(fo), fo); - } - - URL[] url; - if (path != null) { - url = new URL[1]; - URL root = FileUtil.getArchiveRoot(file.toURI().toURL()); - if (!path.endsWith("/")) { //NOI18N - path = path + "/"; //NOI18N - } - url[0] = new URL(root, path); - } else { - url = new URL[1]; - url[0] = FileUtil.getArchiveRoot(file.toURI().toURL()); - } - return url; - } - } catch (MalformedURLException exc) { - ErrorManager.getDefault().notify(exc); - } - return new URL[0]; - } - - private String checkPath(FileObject jarRoot, FileObject fo) { - String toRet = null; - FileObject root = JavadocAndSourceRootDetection.findJavadocRoot(jarRoot); - try { - if (root != null && !root.equals(jarRoot)) { - toRet = FileUtil.getRelativePath(jarRoot, root); - fo.setAttribute(ATTR_PATH, toRet); - } - fo.setAttribute(ATTR_STAMP, new Date()); - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - return toRet; - } - - - } - - private static class Javaee6Result implements JavadocForBinaryQuery.Result { - - Javaee6Result() {} - - @Override public void addChangeListener(ChangeListener changeListener) {} - - @Override public void removeChangeListener(ChangeListener changeListener) {} - - @Override public URL[] getRoots() { - try { - File j2eeDoc = InstalledFileLocator.getDefault().locate("docs/javaee6-doc-api.zip", "org.netbeans.modules.j2ee.platform", false); // NOI18N - if (j2eeDoc != null) { - URL url = FileUtil.getArchiveRoot(j2eeDoc.toURI().toURL()); - url = new URL(url + "docs/api/"); //NOI18N - return new URL[]{url}; - } - } catch (MalformedURLException ex) { - Exceptions.printStackTrace(ex); - } - return new URL[0]; - } - - } - -} Index: maven/src/org/netbeans/modules/maven/queries/RepositorySourceForBinaryQueryImpl.java --- maven/src/org/netbeans/modules/maven/queries/RepositorySourceForBinaryQueryImpl.java Base (BASE) +++ maven/src/org/netbeans/modules/maven/queries/RepositorySourceForBinaryQueryImpl.java Locally Modified (Based On LOCAL) @@ -42,19 +42,46 @@ package org.netbeans.modules.maven.queries; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; +import java.lang.ref.WeakReference; +import java.net.MalformedURLException; +import java.net.URI; import java.net.URL; +import java.util.Arrays; +import java.util.Collections; import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.prefs.PreferenceChangeEvent; +import java.util.prefs.PreferenceChangeListener; import javax.swing.event.ChangeListener; -import org.netbeans.api.java.queries.SourceForBinaryQuery; +import org.netbeans.api.java.queries.JavadocForBinaryQuery; +import org.netbeans.api.project.Project; +import org.netbeans.modules.maven.api.NbMavenProject; +import org.netbeans.modules.maven.embedder.EmbedderFactory; +import org.netbeans.modules.maven.spi.queries.ForeignClassBundler; import org.netbeans.spi.java.project.support.JavadocAndSourceRootDetection; +import org.netbeans.spi.java.queries.JavadocForBinaryQueryImplementation; import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation; +import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation2; +import org.openide.ErrorManager; +import org.openide.filesystems.FileChangeAdapter; +import org.openide.filesystems.FileChangeListener; +import org.openide.filesystems.FileEvent; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; -import org.openide.filesystems.URLMapper; +import org.openide.modules.InstalledFileLocator; +import org.openide.util.ChangeSupport; import org.openide.util.Exceptions; +import org.openide.util.RequestProcessor; +import org.openide.util.WeakListeners; import org.openide.util.lookup.ServiceProvider; +import org.openide.util.lookup.ServiceProviders; /** * @@ -64,24 +91,100 @@ * * @author Milos Kleint */ -@ServiceProvider(service=SourceForBinaryQueryImplementation.class, position=999) -public class RepositorySourceForBinaryQueryImpl implements SourceForBinaryQueryImplementation { +@ServiceProviders({ + @ServiceProvider(service=SourceForBinaryQueryImplementation.class, position=68), + @ServiceProvider(service=SourceForBinaryQueryImplementation2.class, position=68), + @ServiceProvider(service=JavadocForBinaryQueryImplementation.class, position=68) +}) +public class RepositorySourceForBinaryQueryImpl extends AbstractMavenForBinaryQueryImpl { - @Override public SourceForBinaryQuery.Result findSourceRoots(URL url) { - File stored = SourceJavadocByHash.find(url, false); - if (stored != null) { - return new SrcResult(stored); + + private final Map> srcCache = Collections.synchronizedMap(new HashMap>()); + private final Map> javadocCache = Collections.synchronizedMap(new HashMap>()); + + + private static final RequestProcessor RP = new RequestProcessor("Maven Repository SFBQ result change"); + + @Override + public synchronized Result findSourceRoots2(URL url) { + if (!"jar".equals(url.getProtocol())) { //NOI18N + // null for directories. + return null; } - URL binRoot = url; + + WeakReference cached = srcCache.get(url); + if (cached != null) { + SrcResult result = cached.get(); + if (result != null) { + return result; + } + } + + File jarFile = FileUtil.archiveOrDirForURL(url); + if (jarFile != null) { +// String name = jarFile.getName(); + File parent = jarFile.getParentFile(); + if (parent != null) { + File parentParent = parent.getParentFile(); + if (parentParent != null) { + // each repository artifact should have this structure + String artifact = parentParent.getName(); + String version = parent.getName(); +// File pom = new File(parent, artifact + "-" + version + ".pom"); +// // maybe this condition is already overkill.. +// if (pom.exists()) { + File srcs = new File(parent, artifact + "-" + version + "-sources.jar"); //NOI18N + if (jarFile.getName().startsWith(artifact + "-" + version)) { //one last perf check before calling the embedder + URI localRepo = EmbedderFactory.getProjectEmbedder().getLocalRepositoryFile().toURI(); + URI rel = localRepo.relativize(parentParent.getParentFile().toURI()); + if (!rel.isAbsolute()) { + String groupId = rel.getPath(); + if (groupId != null && !groupId.equals("")) { + groupId = groupId.replace("/", "."); + if (groupId.endsWith(".")) { + groupId = groupId.substring(0, groupId.length() - 1); + } + SrcResult result = new SrcResult(groupId, artifact, version, FileUtil.getArchiveFile(url), srcs); + srcCache.put(url, new WeakReference(result)); + return result; + } + } + + } +// } + } + } + } + return null; + + } + + @Override + public JavadocForBinaryQuery.Result findJavadoc(URL url) { + URL binRoot; if ("jar".equals(url.getProtocol())) { //NOI18N binRoot = FileUtil.getArchiveFile(url); } else { // null for directories. return null; } - FileObject jarFO = URLMapper.findFileObject(binRoot); - if (jarFO != null) { - File jarFile = FileUtil.toFile(jarFO); + + //hack for javaee6 jar docs which we ship with netbeans and which are not in any maven repository + if (binRoot.getPath().endsWith("/javax/javaee-api/6.0/javaee-api-6.0.jar") + || binRoot.getPath().endsWith("/javax/javaee-web-api/6.0/javaee-web-api-6.0.jar")) { //NOI18N + return new Javaee6Result(); + } + + WeakReference cached = javadocCache.get(url); + if (cached != null) { + JavadocResult result = cached.get(); + if (result != null) { + return result; + } + } + + + File jarFile = FileUtil.archiveOrDirForURL(url); if (jarFile != null) { // String name = jarFile.getName(); File parent = jarFile.getParentFile(); @@ -94,35 +197,176 @@ // File pom = new File(parent, artifact + "-" + version + ".pom"); // // maybe this condition is already overkill.. // if (pom.exists()) { - File srcs = new File(parent, artifact + "-" + version + "-sources.jar"); //NOI18N - if (srcs.exists()) { - return new SrcResult(srcs); + File javadoc = new File(parent, artifact + "-" + version + "-javadoc.jar"); //NOI18N + if (jarFile.getName().startsWith(artifact + "-" + version)) { //one last perf check before calling the embedder + URI localRepo = EmbedderFactory.getProjectEmbedder().getLocalRepositoryFile().toURI(); + URI rel = localRepo.relativize(parentParent.getParentFile().toURI()); + if (!rel.isAbsolute()) { + String groupId = rel.getPath(); + if (groupId != null && !groupId.equals("")) { + groupId = groupId.replace("/", "."); + if (groupId.endsWith(".")) { + groupId = groupId.substring(0, groupId.length() - 1); } -// } + JavadocResult result = new JavadocResult(groupId, artifact, version, binRoot, javadoc); + javadocCache.put(url, new WeakReference(result)); + return result; } } + } +// } } + } + } return null; - } - private static class SrcResult implements SourceForBinaryQuery.Result { + private static class SrcResult implements SourceForBinaryQueryImplementation2.Result { private static final String ATTR_PATH = "lastRootCheckPath"; //NOI18N private static final String ATTR_STAMP = "lastRootCheckStamp"; //NOI18N - private File file; + private final File sourceJarFile; + private final ChangeSupport support; + private final PreferenceChangeListener prefListener; + private final PropertyChangeListener projectListener; + private final FileChangeListener sourceJarChangeListener; + private final String groupId; + private final String artifactId; + private final String version; + private final String gav; + private final URL binary; - SrcResult(File src) { - file = src; + private Project currentProject; + private FileObject[] cached; + + + SrcResult(String groupId, String artifactId, String version, URL binary, File sourceJar) { + sourceJarFile = sourceJar; + this.groupId = groupId; + this.artifactId = artifactId; + this.version = version; + this.binary = binary; + this.gav = MavenFileOwnerQueryImpl.cacheKey(groupId, artifactId, version); + + support = new ChangeSupport(this); + prefListener = new PreferenceChangeListener() { + @Override + public void preferenceChange(PreferenceChangeEvent evt) { + if (gav.equals(evt.getKey())) { + //external root in local repository changed.. + checkChanges(); } + } + }; + projectListener = new PropertyChangeListener() { + public @Override + void propertyChange(PropertyChangeEvent event) { + if (NbMavenProject.PROP_PROJECT.equals(event.getPropertyName())) { + //project could have changed source roots.. + checkChanges(); + } + } + }; + sourceJarChangeListener = new FileChangeAdapter(){ + @Override + public void fileDataCreated(FileEvent fe) { + //source jar was created.. + checkChanges(); + } - @Override public void addChangeListener(ChangeListener changeListener) {} + }; + MavenFileOwnerQueryImpl.prefs().addPreferenceChangeListener( + WeakListeners.create(PreferenceChangeListener.class, prefListener, MavenFileOwnerQueryImpl.prefs())); - @Override public void removeChangeListener(ChangeListener changeListener) {} + FileUtil.addFileChangeListener(FileUtil.weakFileChangeListener(sourceJarChangeListener, sourceJar)); + } - @Override public FileObject[] getRoots() { - if (file.exists()) { - FileObject fo = FileUtil.toFileObject(file); + private void checkChanges() { + if (!Arrays.equals(getCached(), getRoots())) { + support.fireChange(); + } + } + /** + * use MFOQI to determine what is the current project owning our coordinates in local repository. + */ + private void checkCurrentProject() { + Project owner = MavenFileOwnerQueryImpl.getInstance().getOwner(groupId, artifactId, version); + if (owner != null && owner.getLookup().lookup(NbMavenProject.class) == null) { + owner = null; + } + //XXX TODO should we be attaching a weak listener here? + if (currentProject != null && !currentProject.equals(owner)) { + currentProject.getLookup().lookup(NbMavenProject.class).removePropertyChangeListener(projectListener); + } + if (owner != null && !owner.equals(currentProject)) { + owner.getLookup().lookup(NbMavenProject.class).addPropertyChangeListener(projectListener); + } + currentProject = owner; + } + + @Override + public void addChangeListener(ChangeListener changeListener) { + support.addChangeListener(changeListener); + } + + @Override + public void removeChangeListener(ChangeListener changeListener) { + support.removeChangeListener(changeListener); + } + + @Override + public FileObject[] getRoots() { + FileObject[] toRet; + checkCurrentProject(); + Project prj = currentProject; + if (prj != null) { + toRet = getProjectSrcRoots(prj); + } else { + File f = SourceJavadocByHash.find(binary, false); + if (f != null && f.exists()) { + toRet = getSourceJarRoot(f); + } + else if (sourceJarFile.exists()) { + toRet = getSourceJarRoot(sourceJarFile); + } else { + toRet = new FileObject[0]; + } + } + if (!Arrays.equals(cached, toRet)) { + //how to figure otherwise that something changed, possibly multiple people hold the result instance + // and one asks the roots, later we get event from outside, but then the cached value already updated.. + RP.post(new Runnable() { + @Override + public void run() { + support.fireChange(); + } + }); + } + cached = toRet; + return toRet; + } + + public FileObject[] getCached() { + return cached; + } + + private String checkPath(FileObject jarRoot, FileObject fo) { + String toRet = null; + FileObject root = JavadocAndSourceRootDetection.findSourceRoot(jarRoot); + try { + if (root != null && !root.equals(jarRoot)) { + toRet = FileUtil.getRelativePath(jarRoot, root); + fo.setAttribute(ATTR_PATH, toRet); + } + fo.setAttribute(ATTR_STAMP, new Date()); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + return toRet; + } + + private FileObject[] getSourceJarRoot(File sourceJar) { + FileObject fo = FileUtil.toFileObject(sourceJar); FileObject jarRoot = FileUtil.getArchiveRoot(fo); if (jarRoot != null) { //#139894 it seems that sometimes it can return null. // I suppose it's in the case when the jar/zip file in repository exists @@ -145,13 +389,177 @@ } return fos; } - } return new FileObject[0]; } + @Override + public boolean preferSources() { + Project prj = currentProject; + if (prj != null) { + //TODO is project broken or not, handle accordingly.. + return prj.getLookup().lookup(ForeignClassBundler.class).preferSources(); + } + return false; + } + + } + + private static class JavadocResult implements JavadocForBinaryQuery.Result { + private final File sourceJarFile; + private final String groupId; + private final String artifactId; + private final String version; + private final URL binary; + private final String gav; + private final ChangeSupport support; + private final PreferenceChangeListener prefListener; + private final PropertyChangeListener projectListener; + private final FileChangeAdapter javadocJarChangeListener; + private Project currentProject; + private URL[] cached; + private static final String ATTR_PATH = "lastRootCheckPath"; //NOI18N + private static final String ATTR_STAMP = "lastRootCheckStamp"; //NOI18N + + + + JavadocResult(String groupId, String artifactId, String version, URL binary, File javadocJar) { + sourceJarFile = javadocJar; + this.groupId = groupId; + this.artifactId = artifactId; + this.version = version; + this.binary = binary; + this.gav = MavenFileOwnerQueryImpl.cacheKey(groupId, artifactId, version); + + support = new ChangeSupport(this); + prefListener = new PreferenceChangeListener() { + @Override + public void preferenceChange(PreferenceChangeEvent evt) { + if (gav.equals(evt.getKey())) { + //external root in local repository changed.. + checkCurrentProject(); + checkChanges(); + } + } + }; + projectListener = new PropertyChangeListener() { + public @Override + void propertyChange(PropertyChangeEvent event) { + if (NbMavenProject.PROP_PROJECT.equals(event.getPropertyName())) { + //project could have changed coordinates.. + checkCurrentProject(); + checkChanges(); + } + } + }; + javadocJarChangeListener = new FileChangeAdapter(){ + @Override + public void fileDataCreated(FileEvent fe) { + //source jar was created.. + checkChanges(); + } + + }; + MavenFileOwnerQueryImpl.prefs().addPreferenceChangeListener( + WeakListeners.create(PreferenceChangeListener.class, prefListener, MavenFileOwnerQueryImpl.prefs())); + + FileUtil.addFileChangeListener(javadocJarChangeListener, javadocJar); + } + @Override + public URL[] getRoots() { + URL[] toRet; + Project prj = currentProject; + if (prj != null) { + toRet = new URL[0]; + } else { + File f = SourceJavadocByHash.find(binary, true); + if (f != null && f.exists()) { + toRet = getJavadocJarRoot(f); + } + else if (sourceJarFile.exists()) { + toRet = getJavadocJarRoot(sourceJarFile); + } else { + toRet = new URL[0]; + } + } + cached = toRet; + return toRet; + } + + public URL[] getCached() { + return cached; + } + + @Override + public void addChangeListener(ChangeListener l) { + support.addChangeListener(l); + } + + @Override + public void removeChangeListener(ChangeListener l) { + support.removeChangeListener(l); + } + + private void checkChanges() { + if (!Arrays.equals(getCached(), getRoots())) { + support.fireChange(); + } + } + /** + * use MFOQI to determine what is the current project owning our coordinates in local repository. + */ + private void checkCurrentProject() { + Project owner = MavenFileOwnerQueryImpl.getInstance().getOwner(groupId, artifactId, version); + if (owner != null && owner.getLookup().lookup(NbMavenProject.class) == null) { + owner = null; + } + if (currentProject != null && !currentProject.equals(owner)) { + currentProject.getLookup().lookup(NbMavenProject.class).removePropertyChangeListener(projectListener); + } + if (owner != null && !owner.equals(currentProject)) { + owner.getLookup().lookup(NbMavenProject.class).addPropertyChangeListener(projectListener); + } + currentProject = owner; + } + + private URL[] getJavadocJarRoot(File file) { + try { + if (file.exists()) { + FileObject fo = FileUtil.toFileObject(file); + if (!FileUtil.isArchiveFile(fo)) { + //#124175 ignore any jar files that are not jar files (like when downloaded file is actually an error html page). + Logger.getLogger(RepositorySourceForBinaryQueryImpl.class.getName()).log(Level.INFO, "javadoc in repository is not really a JAR: {0}", file); + return new URL[0]; + } + //try detecting the source path root, in case the source jar has the sources not in root. + Date date = (Date) fo.getAttribute(ATTR_STAMP); + String path = (String) fo.getAttribute(ATTR_PATH); + if (date == null || fo.lastModified().after(date)) { + path = checkPath(FileUtil.getArchiveRoot(fo), fo); + } + + URL[] url; + if (path != null) { + url = new URL[1]; + URL root = FileUtil.getArchiveRoot(file.toURI().toURL()); + if (!path.endsWith("/")) { //NOI18N + path = path + "/"; //NOI18N + } + url[0] = new URL(root, path); + } else { + url = new URL[1]; + url[0] = FileUtil.getArchiveRoot(file.toURI().toURL()); + } + return url; + } + } catch (MalformedURLException exc) { + ErrorManager.getDefault().notify(exc); + } + return new URL[0]; + } + private String checkPath(FileObject jarRoot, FileObject fo) { String toRet = null; - FileObject root = JavadocAndSourceRootDetection.findSourceRoot(jarRoot); + FileObject root = JavadocAndSourceRootDetection.findJavadocRoot(jarRoot); try { if (root != null && !root.equals(jarRoot)) { toRet = FileUtil.getRelativePath(jarRoot, root); @@ -166,4 +574,28 @@ } + private static class Javaee6Result implements JavadocForBinaryQuery.Result { + + Javaee6Result() {} + + @Override public void addChangeListener(ChangeListener changeListener) {} + + @Override public void removeChangeListener(ChangeListener changeListener) {} + + @Override public URL[] getRoots() { + try { + File j2eeDoc = InstalledFileLocator.getDefault().locate("docs/javaee6-doc-api.zip", "org.netbeans.modules.j2ee.platform", false); // NOI18N + if (j2eeDoc != null) { + URL url = FileUtil.getArchiveRoot(j2eeDoc.toURI().toURL()); + url = new URL(url + "docs/api/"); //NOI18N + return new URL[]{url}; } + } catch (MalformedURLException ex) { + Exceptions.printStackTrace(ex); + } + return new URL[0]; + } + + } + +} Index: maven/test/unit/data/source.jar --- maven/test/unit/data/source.jar Base (BASE) +++ maven/test/unit/data/source.jar Locally New Index: maven/test/unit/src/org/netbeans/modules/maven/queries/RepositorySourceForBinaryQueryImplTest.java --- maven/test/unit/src/org/netbeans/modules/maven/queries/RepositorySourceForBinaryQueryImplTest.java Base (BASE) +++ maven/test/unit/src/org/netbeans/modules/maven/queries/RepositorySourceForBinaryQueryImplTest.java Locally New @@ -0,0 +1,137 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.modules.maven.queries; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Arrays; +import org.junit.Test; +import static org.junit.Assert.*; +import org.netbeans.api.project.ProjectManager; +import org.netbeans.junit.NbTestCase; +import org.netbeans.modules.maven.NbMavenProjectImpl; +import org.netbeans.modules.maven.embedder.EmbedderFactory; +import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation2.Result; +import org.openide.filesystems.FileUtil; +import org.openide.util.Exceptions; +import org.openide.util.test.TestFileUtils; + +/** + * + * @author mkleint + */ +public class RepositorySourceForBinaryQueryImplTest extends NbTestCase{ + + public RepositorySourceForBinaryQueryImplTest(String name) { + super(name); + } + + /** + * Test of findSourceRoots2 method, of class RepositorySourceForBinaryQueryImpl. + */ + @Test + public void testResultChanging() throws IOException { + RepositorySourceForBinaryQueryImpl query = new RepositorySourceForBinaryQueryImpl(); + File repo = EmbedderFactory.getProjectEmbedder().getLocalRepositoryFile(); + File art10 = new File(repo, "nbtest/testprj/1.0/testprj-1.0.jar"); + org.codehaus.plexus.util.FileUtils.deleteDirectory(art10.getParentFile()); + URL url = FileUtil.getArchiveRoot(art10.toURI().toURL()); + TestFileUtils.writeZipFile(art10, "META-INF/MANIFEST.MF:Version:1.0"); + Result result = query.findSourceRoots2(url); + assertNotNull(result); + assertEquals(0, result.getRoots().length); + + + // now create source jar + File sourceJar = new File(this.getDataDir(), "source.jar"); + File repoSourceJar = new File(art10.getParentFile(), "testprj-1.0-sources.jar"); + org.codehaus.plexus.util.FileUtils.copyFile(sourceJar, repoSourceJar); + assertEquals(1, result.getRoots().length); + assertEquals(FileUtil.getArchiveRoot(FileUtil.toFileObject(repoSourceJar)), result.getRoots()[0]); + + + + //now create project + File prj10 = new File(getWorkDir(), "prj10"); + TestFileUtils.writeFile(new File(prj10, "pom.xml"), "4.0.0" + + "nbtesttestprj" + + "jar1.0"); + //create main source root. + File prjroot = new File(new File(new File(prj10, "src"), "main"), "java"); + prjroot.mkdirs(); + + NbMavenProjectImpl p10 = (NbMavenProjectImpl) ProjectManager.getDefault().findProject(FileUtil.toFileObject(prj10)); + assertNotNull(p10); + MavenFileOwnerQueryImpl.getInstance().registerProject(p10); + try { + //preferences changes get fired in different thread, need to wait for it.. + Thread.sleep(2000); + } catch (InterruptedException ex) { + Exceptions.printStackTrace(ex); + } + assertEquals(1, result.getRoots().length); + assertEquals(FileUtil.toFileObject(prjroot), result.getRoots()[0]); + + //overwrite the pom file to point to different + TestFileUtils.writeFile(new File(prj10, "pom.xml"), "4.0.0" + + "nbtesttestprj" + + "jar1.0" + + "src/main2/java" + + ""); + //manually reload the project, only opened projects listen on pom.xml changes. + p10.fireProjectReload(); + + + System.out.println("res=" + Arrays.toString(result.getRoots())); + assertEquals(0, result.getRoots().length); + prjroot = new File(new File(new File(prj10, "src"), "main2"), "java"); + prjroot.mkdirs(); + + assertEquals(1, result.getRoots().length); + assertEquals(FileUtil.toFileObject(prjroot), result.getRoots()[0]); + + + + } + +}