diff --git a/api.java/apichanges.xml b/api.java/apichanges.xml
--- a/api.java/apichanges.xml
+++ b/api.java/apichanges.xml
@@ -76,6 +76,25 @@
+
+
+ Added SourceJavadocAttacher to allow clients to attach source (javadoc) roots to binary root
+
+
+
+
+
+
+ Added an API to allow clients to attach source roots and javadoc roots to binary roots.
+ The API delegates to SPI implementations which provide specific behavior depending on
+ type of binary root (platform, library, maven artifact). There is also fallback implementation
+ handling unknown binary roots by storing the bindings into IDE's userdir.
+
+
+
+
+
+
Added notifications about source level changes into SourceLevelQuery
diff --git a/api.java/manifest.mf b/api.java/manifest.mf
--- a/api.java/manifest.mf
+++ b/api.java/manifest.mf
@@ -1,6 +1,6 @@
Manifest-Version: 1.0
OpenIDE-Module: org.netbeans.api.java/1
-OpenIDE-Module-Specification-Version: 1.34
+OpenIDE-Module-Specification-Version: 1.35
OpenIDE-Module-Localizing-Bundle: org/netbeans/api/java/queries/Bundle.properties
AutoUpdate-Show-In-Client: false
diff --git a/api.java/src/org/netbeans/api/java/queries/SourceJavadocAttacher.java b/api.java/src/org/netbeans/api/java/queries/SourceJavadocAttacher.java
new file mode 100644
--- /dev/null
+++ b/api.java/src/org/netbeans/api/java/queries/SourceJavadocAttacher.java
@@ -0,0 +1,106 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 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 2011 Sun Microsystems, Inc.
+ */
+package org.netbeans.api.java.queries;
+
+import java.io.IOException;
+import java.net.URL;
+import javax.swing.SwingUtilities;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.spi.java.queries.SourceJavadocAttacherImplementation;
+import org.openide.util.Exceptions;
+import org.openide.util.Lookup;
+
+/**
+ * A support for attaching source roots and javadoc roots to binary roots.
+ * @author Tomas Zezula
+ * @since 1.35
+ */
+public final class SourceJavadocAttacher {
+
+ private SourceJavadocAttacher() {}
+
+ /**
+ * Attaches a source root provided by the SPI {@link SourceJavadocAttacherImplementation}
+ * to given binary root.
+ * Has to be called by event dispatch thread as the SPI implementation may need to show
+ * an UI to select source root(s).
+ * @param root the binary root to attach sources to
+ * @return true if the source root was successfully attached
+ */
+ public static boolean attachSources(@NonNull final URL root) {
+ return attach(root,0);
+ }
+
+ /**
+ * Attaches a javadoc root provided by the SPI {@link SourceJavadocAttacherImplementation}
+ * to given binary root.
+ * Has to be called by event dispatch thread as the SPI implementation may need to show
+ * an UI to select javadoc root(s).
+ * @param root the binary root to attach javadoc to
+ * @return true if the javadoc root was successfully attached
+ */
+ public static boolean attachJavadoc(@NonNull final URL root) {
+ return attach(root,1);
+ }
+
+ private static boolean attach(final URL root, final int mode) {
+ if (!SwingUtilities.isEventDispatchThread()) {
+ throw new IllegalStateException("Has to be called by EDT."); //NOI18N
+ }
+ try {
+ for (SourceJavadocAttacherImplementation attacher : Lookup.getDefault().lookupAll(SourceJavadocAttacherImplementation.class)) {
+ final SourceJavadocAttacherImplementation.Result res =
+ mode == 0 ?
+ attacher.attachSources(root) :
+ attacher.attachJavadoc(root);
+ if (res == SourceJavadocAttacherImplementation.Result.ATTACHED) {
+ return true;
+ } else if (res == SourceJavadocAttacherImplementation.Result.CANCELED) {
+ return false;
+ }
+ }
+ } catch (IOException ioe) {
+ Exceptions.printStackTrace(ioe);
+ }
+ return false;
+ }
+}
diff --git a/api.java/src/org/netbeans/spi/java/queries/SourceJavadocAttacherImplementation.java b/api.java/src/org/netbeans/spi/java/queries/SourceJavadocAttacherImplementation.java
new file mode 100644
--- /dev/null
+++ b/api.java/src/org/netbeans/spi/java/queries/SourceJavadocAttacherImplementation.java
@@ -0,0 +1,106 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 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 2011 Sun Microsystems, Inc.
+ */
+package org.netbeans.spi.java.queries;
+
+import java.io.IOException;
+import java.net.URL;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.java.queries.SourceJavadocAttacher;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.ServiceProvider;
+
+
+/**
+ * A SPI for attaching source roots and javadoc roots to binary roots.
+ * The implementations of this interface are registered in global {@link Lookup}
+ * @see ServiceProvider
+ * @since 1.35
+ * @author Tomas Zezula
+ * @since 1.35
+ */
+public interface SourceJavadocAttacherImplementation {
+
+ /**
+ * Result of the attaching sources (javadoc) to binary root.
+ */
+ enum Result {
+ /**
+ * The source (javadoc) root was successfully attached to
+ * the binary root.
+ */
+ ATTACHED,
+
+ /**
+ * User canceled the attaching, no other SPI provider
+ * is called and {@link SourceJavadocAttacher} returns false.
+ */
+ CANCELED,
+
+ /**
+ * The SPI is not able to attach sources (javadoc) to given
+ * binary root (it does not handle it), next SPI provider is
+ * called.
+ */
+ UNSUPPORTED
+ }
+
+
+ /**
+ * Attaches a source root provided by this SPI to given binary root.
+ * Called by event dispatch thread, it's safe to show an UI to select source root(s).
+ * @param root the binary root to attach sources to
+ * @return {@link SourceJavadocAttacherImplementation.Result} the result of
+ * attach operation.
+ */
+ @NonNull
+ Result attachSources(@NonNull URL root) throws IOException;
+
+ /**
+ * Attaches a javadoc root provided by this SPI to given binary root.
+ * Called by event dispatch thread, it's safe to show an UI to select javadoc root(s).
+ * @param root the binary root to attach javadoc to
+ * @return {@link SourceJavadocAttacherImplementation.Result} the result of
+ * attach operation.
+ */
+ @NonNull
+ Result attachJavadoc(@NonNull URL root) throws IOException;
+}
diff --git a/java.j2seplatform/nbproject/project.xml b/java.j2seplatform/nbproject/project.xml
--- a/java.j2seplatform/nbproject/project.xml
+++ b/java.j2seplatform/nbproject/project.xml
@@ -59,12 +59,21 @@
+ org.netbeans.api.annotations.common
+
+
+
+ 1
+ 1.10
+
+
+
org.netbeans.api.java
1
- 1.18
+ 1.35
diff --git a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SELibrarySourceJavadocAttacher.java b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SELibrarySourceJavadocAttacher.java
new file mode 100644
--- /dev/null
+++ b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SELibrarySourceJavadocAttacher.java
@@ -0,0 +1,159 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 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 2011 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.java.j2seplatform.libraries;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.project.libraries.Library;
+import org.netbeans.api.project.libraries.LibraryManager;
+import org.netbeans.spi.java.queries.SourceJavadocAttacherImplementation;
+import org.openide.util.Exceptions;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ *
+ * @author Tomas Zezula
+ */
+@ServiceProvider(service=SourceJavadocAttacherImplementation.class, position=151)
+public class J2SELibrarySourceJavadocAttacher implements SourceJavadocAttacherImplementation {
+
+ @Override
+ public Result attachSources(@NonNull final URL root) throws IOException {
+ return attach(root, J2SELibraryTypeProvider.VOLUME_TYPE_SRC);
+ }
+
+ @Override
+ public Result attachJavadoc(@NonNull final URL root) throws IOException {
+ return attach(root, J2SELibraryTypeProvider.VOLUME_TYPE_JAVADOC);
+ }
+
+ private Result attach(
+ @NonNull final URL root,
+ final String volume) {
+ final Pair pair = findOwner(root);
+ if (pair == null) {
+ return Result.UNSUPPORTED;
+ }
+ final LibraryManager lm = pair.first;
+ final Library lib = pair.second;
+ assert lm != null;
+ assert lib != null;
+ try {
+ final URL areaLocation = lm.getLocation();
+ final File baseFolder = areaLocation == null ? null : new File(areaLocation.toURI()).getParentFile();
+ final URI[] uris = J2SEVolumeCustomizer.select(
+ volume,
+ lib.getName(),
+ new File[1],
+ null,
+ baseFolder);
+ if (uris != null) {
+ final String name = lib.getName();
+ final String displayName = lib.getDisplayName();
+ final String desc = lib.getDescription();
+ final Map> volumes = new HashMap>();
+ for (String currentVolume : J2SELibraryTypeProvider.VOLUME_TYPES) {
+ List content = lib.getURIContent(currentVolume);
+ if (volume == currentVolume) {
+ final List newContent = new ArrayList(content.size()+uris.length);
+ newContent.addAll(content);
+ newContent.addAll(Arrays.asList(uris));
+ content = newContent;
+ }
+ volumes.put(currentVolume,content);
+ }
+ lm.removeLibrary(lib);
+ lm.createURILibrary(
+ J2SELibraryTypeProvider.LIBRARY_TYPE,
+ name,
+ displayName,
+ desc,
+ volumes);
+ return Result.ATTACHED;
+ }
+ } catch (IOException ioe) {
+ Exceptions.printStackTrace(ioe);
+ } catch (URISyntaxException use) {
+ Exceptions.printStackTrace(use);
+ }
+ return Result.CANCELED;
+ }
+
+ private Pair findOwner(final URL root) {
+ for (LibraryManager lm : LibraryManager.getOpenManagers()) {
+ for (Library l : lm.getLibraries()) {
+ if (!J2SELibraryTypeProvider.LIBRARY_TYPE.equals(l.getType())) {
+ continue;
+ }
+ final List cp = l.getContent(J2SELibraryTypeProvider.VOLUME_TYPE_CLASSPATH);
+ if (cp.contains(root)) {
+ return Pair.of(lm, l);
+ }
+ }
+ }
+ return null;
+ }
+
+ private static class Pair {
+ public final F first;
+ public final S second;
+
+ private Pair(F first, S second) {
+ this.first = first;
+ this.second = second;
+ }
+
+ public static Pair of(F first, S second) {
+ return new Pair(first,second);
+ }
+ }
+
+}
diff --git a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SEVolumeCustomizer.java b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SEVolumeCustomizer.java
--- a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SEVolumeCustomizer.java
+++ b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SEVolumeCustomizer.java
@@ -55,9 +55,11 @@
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComponent;
@@ -67,6 +69,9 @@
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileFilter;
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.project.ant.FileChooser;
import org.netbeans.spi.java.project.support.JavadocAndSourceRootDetection;
import org.netbeans.spi.project.libraries.LibraryCustomizerContext;
@@ -116,6 +121,72 @@
this.upButton.setEnabled(enabled && indices.length>0 && indices[0]>0);
}
+ @CheckForNull
+ static URI[] select(
+ @NonNull final String volumeType,
+ @NonNull final String libName,
+ @NonNull final File[] lastFolder,
+ @NullAllowed final Component owner,
+ @NullAllowed final File baseFolder) {
+ assert volumeType != null;
+ assert lastFolder != null;
+ assert lastFolder.length == 1;
+ final File libFolder = baseFolder == null ?
+ null:
+ FileUtil.normalizeFile(new File(baseFolder, libName));
+ FileChooser chooser = new FileChooser(baseFolder, libFolder);
+ // for now variable based paths are disabled in library definition
+ // can be revisit if it is needed
+ chooser.setFileHidingEnabled(false);
+ chooser.setAcceptAllFileFilterUsed(false);
+ if (volumeType.equals(J2SELibraryTypeProvider.VOLUME_TYPE_CLASSPATH)) {
+ chooser.setMultiSelectionEnabled (true);
+ chooser.setDialogTitle(NbBundle.getMessage(J2SEVolumeCustomizer.class,"TXT_OpenClasses"));
+ chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
+ chooser.setFileFilter (new ArchiveFileFilter(NbBundle.getMessage(
+ J2SEVolumeCustomizer.class,"TXT_Classpath"),new String[] {"ZIP","JAR"})); //NOI18N
+ chooser.setApproveButtonText(NbBundle.getMessage(J2SEVolumeCustomizer.class,"CTL_SelectCP"));
+ chooser.setApproveButtonMnemonic(NbBundle.getMessage(J2SEVolumeCustomizer.class,"MNE_SelectCP").charAt(0));
+ } else if (volumeType.equals(J2SELibraryTypeProvider.VOLUME_TYPE_JAVADOC)) {
+ chooser.setMultiSelectionEnabled (true);
+ chooser.setDialogTitle(NbBundle.getMessage(J2SEVolumeCustomizer.class,"TXT_OpenJavadoc"));
+ chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
+ chooser.setFileFilter (new ArchiveFileFilter(NbBundle.getMessage(
+ J2SEVolumeCustomizer.class,"TXT_Javadoc"),new String[] {"ZIP","JAR"})); //NOI18N
+ chooser.setApproveButtonText(NbBundle.getMessage(J2SEVolumeCustomizer.class,"CTL_SelectJD"));
+ chooser.setApproveButtonMnemonic(NbBundle.getMessage(J2SEVolumeCustomizer.class,"MNE_SelectJD").charAt(0));
+ } else if (volumeType.equals(J2SELibraryTypeProvider.VOLUME_TYPE_SRC)) {
+ chooser.setMultiSelectionEnabled (true);
+ chooser.setDialogTitle(NbBundle.getMessage(J2SEVolumeCustomizer.class,"TXT_OpenSources"));
+ chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
+ chooser.setFileFilter (new ArchiveFileFilter(NbBundle.getMessage(
+ J2SEVolumeCustomizer.class,"TXT_Sources"),new String[] {"ZIP","JAR"})); //NOI18N
+ chooser.setApproveButtonText(NbBundle.getMessage(J2SEVolumeCustomizer.class,"CTL_SelectSRC"));
+ chooser.setApproveButtonMnemonic(NbBundle.getMessage(J2SEVolumeCustomizer.class,"MNE_SelectSRC").charAt(0));
+ }
+ if (lastFolder[0] != null) {
+ chooser.setCurrentDirectory (lastFolder[0]);
+ } else if (baseFolder != null) {
+ chooser.setCurrentDirectory (baseFolder);
+ }
+ if (chooser.showOpenDialog(owner) == JFileChooser.APPROVE_OPTION) {
+ try {
+ lastFolder[0] = chooser.getCurrentDirectory();
+ return pathsToURIs (
+ chooser.getSelectedPaths(),
+ volumeType,
+ baseFolder);
+ } catch (MalformedURLException mue) {
+ Exceptions.printStackTrace(mue);
+ } catch (URISyntaxException ue) {
+ Exceptions.printStackTrace(ue);
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ return null;
+ }
+
private void postInitComponents () {
this.content.setCellRenderer(new ContentRenderer());
@@ -346,54 +417,16 @@
}//GEN-LAST:event_removeResource
private void addResource(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addResource
- File baseFolder = null;
- File libFolder = null;
- if (allowRelativePaths != null && allowRelativePaths.booleanValue()) {
- baseFolder = FileUtil.normalizeFile(new File(URI.create(area.getLocation().toExternalForm())).getParentFile());
- libFolder = FileUtil.normalizeFile(new File(baseFolder, impl.getName()));
- }
- FileChooser chooser = new FileChooser(baseFolder, libFolder);
- FileUtil.preventFileChooserSymlinkTraversal(chooser, null);
- // for now variable based paths are disabled in library definition
- // can be revisit if it is needed
- chooser.setFileHidingEnabled(false);
- chooser.setAcceptAllFileFilterUsed(false);
- if (this.volumeType.equals(J2SELibraryTypeProvider.VOLUME_TYPE_CLASSPATH)) {
- chooser.setMultiSelectionEnabled (true);
- chooser.setDialogTitle(NbBundle.getMessage(J2SEVolumeCustomizer.class,"TXT_OpenClasses"));
- chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
- chooser.setFileFilter (new ArchiveFileFilter(NbBundle.getMessage(
- J2SEVolumeCustomizer.class,"TXT_Classpath"),new String[] {"ZIP","JAR"})); //NOI18N
- chooser.setApproveButtonText(NbBundle.getMessage(J2SEVolumeCustomizer.class,"CTL_SelectCP"));
- chooser.setApproveButtonMnemonic(NbBundle.getMessage(J2SEVolumeCustomizer.class,"MNE_SelectCP").charAt(0));
- }
- else if (this.volumeType.equals(J2SELibraryTypeProvider.VOLUME_TYPE_JAVADOC)) {
- chooser.setMultiSelectionEnabled (true);
- chooser.setDialogTitle(NbBundle.getMessage(J2SEVolumeCustomizer.class,"TXT_OpenJavadoc"));
- chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
- chooser.setFileFilter (new ArchiveFileFilter(NbBundle.getMessage(
- J2SEVolumeCustomizer.class,"TXT_Javadoc"),new String[] {"ZIP","JAR"})); //NOI18N
- chooser.setApproveButtonText(NbBundle.getMessage(J2SEVolumeCustomizer.class,"CTL_SelectJD"));
- chooser.setApproveButtonMnemonic(NbBundle.getMessage(J2SEVolumeCustomizer.class,"MNE_SelectJD").charAt(0));
- }
- else if (this.volumeType.equals(J2SELibraryTypeProvider.VOLUME_TYPE_SRC)) {
- chooser.setMultiSelectionEnabled (true);
- chooser.setDialogTitle(NbBundle.getMessage(J2SEVolumeCustomizer.class,"TXT_OpenSources"));
- chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
- chooser.setFileFilter (new ArchiveFileFilter(NbBundle.getMessage(
- J2SEVolumeCustomizer.class,"TXT_Sources"),new String[] {"ZIP","JAR"})); //NOI18N
- chooser.setApproveButtonText(NbBundle.getMessage(J2SEVolumeCustomizer.class,"CTL_SelectSRC"));
- chooser.setApproveButtonMnemonic(NbBundle.getMessage(J2SEVolumeCustomizer.class,"MNE_SelectSRC").charAt(0));
- }
- if (lastFolder != null) {
- chooser.setCurrentDirectory (lastFolder);
- } else if (baseFolder != null) {
- chooser.setCurrentDirectory (baseFolder);
- }
- if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
+ final boolean arp = allowRelativePaths != null && allowRelativePaths.booleanValue();
+ final File baseFolder = arp ?
+ FileUtil.normalizeFile(new File(URI.create(area.getLocation().toExternalForm())).getParentFile()):
+ null;
+ final File[] cwd = new File[]{lastFolder};
+ final URI[] res = select(volumeType, impl.getName(), cwd, this, baseFolder);
+ if (res != null) {
try {
- lastFolder = chooser.getCurrentDirectory();
- addFiles (chooser.getSelectedPaths(), area != null ? area.getLocation() : null, this.volumeType);
+ lastFolder = cwd[0];
+ addFiles (res, arp);
} catch (MalformedURLException mue) {
Exceptions.printStackTrace(mue);
} catch (URISyntaxException ue) {
@@ -435,51 +468,13 @@
}
}//GEN-LAST:event_addURLButtonActionPerformed
- private void addFiles (String[] fileNames, URL libraryLocation, String volume) throws MalformedURLException, URISyntaxException {
+ private void addFiles (URI[] toAdd, boolean allowRelativePaths) throws MalformedURLException, URISyntaxException {
int firstIndex = this.model.getSize();
- for (int i = 0; i < fileNames.length; i++) {
- File f = new File(fileNames[i]);
- URI uri = LibrariesSupport.convertFilePathToURI(fileNames[i]);
- if (allowRelativePaths != null && allowRelativePaths.booleanValue()) {
- File realFile = f;
- if (!f.isAbsolute()) {
- assert area != null;
- if (area != null) {
- realFile = FileUtil.normalizeFile(new File(
- new File(URI.create(area.getLocation().toExternalForm())).getParentFile(), f.getPath()));
- }
- }
- String jarPath = checkFile(realFile, volume);
- if (FileUtil.isArchiveFile(realFile.toURI().toURL())) {
- uri = LibrariesSupport.getArchiveRoot(uri);
- if (jarPath != null) {
- assert uri.toString().endsWith("!/") : uri.toString(); //NOI18N
- uri = URI.create(uri.toString() + encodePath(jarPath));
- }
- } else if (!uri.toString().endsWith("/")){ //NOI18N
- try {
- uri = new URI(uri.toString()+"/"); //NOI18N
- } catch (URISyntaxException ex) {
- throw new AssertionError(ex);
- }
- }
+ for (URI uri : toAdd) {
+ if (allowRelativePaths) {
model.addResource(uri);
} else {
- assert f.isAbsolute() : f.getPath();
- f = FileUtil.normalizeFile (f);
- String jarPath = checkFile(f, volume);
- uri = f.toURI();
- if (FileUtil.isArchiveFile(uri.toURL())) {
- uri = LibrariesSupport.getArchiveRoot(uri);
- if (jarPath != null) {
- assert uri.toString().endsWith("!/") : uri.toString(); //NOI18N
- uri = URI.create(uri.toString() + encodePath(jarPath));
- }
- } else if (!uri.toString().endsWith("/")){ //NOI18N
- uri = URI.create(uri.toString()+"/"); //NOI18N
- }
model.addResource(uri.toURL()); //Has to be added as URL, model asserts it
-
}
}
int lastIndex = this.model.getSize()-1;
@@ -501,7 +496,57 @@
return new URI(null, null, path, null).getRawPath();
}
- private String checkFile(File f, String volume) {
+ @NonNull
+ private static URI[] pathsToURIs(
+ @NonNull final String[] fileNames,
+ @NonNull final String volume,
+ @NullAllowed final File baseFolder) throws MalformedURLException, URISyntaxException {
+ final List result = new ArrayList(fileNames.length);
+ for (int i = 0; i < fileNames.length; i++) {
+ File f = new File(fileNames[i]);
+ URI uri = LibrariesSupport.convertFilePathToURI(fileNames[i]);
+ if (baseFolder != null) {
+ File realFile = f;
+ if (!f.isAbsolute()) {
+ realFile = FileUtil.normalizeFile(new File(
+ baseFolder, f.getPath()));
+ }
+ String jarPath = checkFile(realFile, volume);
+ if (FileUtil.isArchiveFile(realFile.toURI().toURL())) {
+ uri = LibrariesSupport.getArchiveRoot(uri);
+ if (jarPath != null) {
+ assert uri.toString().endsWith("!/") : uri.toString(); //NOI18N
+ uri = URI.create(uri.toString() + encodePath(jarPath));
+ }
+ } else if (!uri.toString().endsWith("/")){ //NOI18N
+ try {
+ uri = new URI(uri.toString()+"/"); //NOI18N
+ } catch (URISyntaxException ex) {
+ throw new AssertionError(ex);
+ }
+ }
+ result.add(uri);
+ } else {
+ assert f.isAbsolute() : f.getPath();
+ f = FileUtil.normalizeFile (f);
+ String jarPath = checkFile(f, volume);
+ uri = f.toURI();
+ if (FileUtil.isArchiveFile(uri.toURL())) {
+ uri = LibrariesSupport.getArchiveRoot(uri);
+ if (jarPath != null) {
+ assert uri.toString().endsWith("!/") : uri.toString(); //NOI18N
+ uri = URI.create(uri.toString() + encodePath(jarPath));
+ }
+ } else if (!uri.toString().endsWith("/")){ //NOI18N
+ uri = URI.create(uri.toString()+"/"); //NOI18N
+ }
+ result.add(uri);
+ }
+ }
+ return result.toArray(new URI[result.size()]);
+ }
+
+ private static String checkFile(File f, String volume) {
FileObject fo = FileUtil.toFileObject(f);
if (volume.equals(J2SELibraryTypeProvider.VOLUME_TYPE_JAVADOC)) {
if (fo != null) {
diff --git a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/J2SEPlatformCustomizer.java b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/J2SEPlatformCustomizer.java
--- a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/J2SEPlatformCustomizer.java
+++ b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/J2SEPlatformCustomizer.java
@@ -94,9 +94,9 @@
private static final String CUSTOMIZERS_PATH =
"org-netbeans-api-java/platform/j2seplatform/customizers/"; //NOI18N
- private static final int CLASSPATH = 0;
- private static final int SOURCES = 1;
- private static final int JAVADOC = 2;
+ static final int CLASSPATH = 0;
+ static final int SOURCES = 1;
+ static final int JAVADOC = 2;
private J2SEPlatformImpl platform;
@@ -106,6 +106,68 @@
}
+ static boolean select(
+ final PathModel model,
+ final File[] currentDir,
+ final Component parentComponent) {
+ final JFileChooser chooser = new JFileChooser ();
+ chooser.setMultiSelectionEnabled (true);
+ String title = null;
+ String message = null;
+ String approveButtonName = null;
+ String approveButtonNameMne = null;
+ if (model.type == SOURCES) {
+ title = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_OpenSources");
+ message = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_Sources");
+ approveButtonName = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_OpenSources");
+ approveButtonNameMne = NbBundle.getMessage (J2SEPlatformCustomizer.class,"MNE_OpenSources");
+ } else if (model.type == JAVADOC) {
+ title = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_OpenJavadoc");
+ message = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_Javadoc");
+ approveButtonName = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_OpenJavadoc");
+ approveButtonNameMne = NbBundle.getMessage (J2SEPlatformCustomizer.class,"MNE_OpenJavadoc");
+ }
+ chooser.setDialogTitle(title);
+ chooser.setApproveButtonText(approveButtonName);
+ chooser.setApproveButtonMnemonic (approveButtonNameMne.charAt(0));
+ chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
+ if (Utilities.isMac()) {
+ //New JDKs and JREs are bundled into package, allow JFileChooser to navigate in
+ chooser.putClientProperty("JFileChooser.packageIsTraversable", "always"); //NOI18N
+ }
+ //#61789 on old macosx (jdk 1.4.1) these two method need to be called in this order.
+ chooser.setAcceptAllFileFilterUsed( false );
+ chooser.setFileFilter (new ArchiveFileFilter(message,new String[] {"ZIP","JAR"})); //NOI18N
+ if (currentDir[0] != null) {
+ chooser.setCurrentDirectory(currentDir[0]);
+ }
+ if (chooser.showOpenDialog(parentComponent) == JFileChooser.APPROVE_OPTION) {
+ File[] fs = chooser.getSelectedFiles();
+ boolean addingFailed = false;
+ for (File f : fs) {
+ //XXX: JFileChooser workaround (JDK bug #5075580), double click on folder returns wrong file
+ // E.g. for /foo/src it returns /foo/src/src
+ // Try to convert it back by removing last invalid name component
+ if (!f.exists()) {
+ File parent = f.getParentFile();
+ if (parent != null && f.getName().equals(parent.getName()) && parent.exists()) {
+ f = parent;
+ }
+ }
+ if (f.exists()) {
+ addingFailed|=!model.addPath (f);
+ }
+ }
+ if (addingFailed) {
+ new NotifyDescriptor.Message (NbBundle.getMessage(J2SEPlatformCustomizer.class,"TXT_CanNotAddResolve"),
+ NotifyDescriptor.ERROR_MESSAGE);
+ }
+ currentDir[0] = FileUtil.normalizeFile(chooser.getCurrentDirectory());
+ return true;
+ }
+ return false;
+ }
+
private void initComponents () {
this.getAccessibleContext().setAccessibleName (NbBundle.getMessage(J2SEPlatformCustomizer.class,"AN_J2SEPlatformCustomizer"));
this.getAccessibleContext().setAccessibleDescription (NbBundle.getMessage(J2SEPlatformCustomizer.class,"AD_J2SEPlatformCustomizer"));
@@ -369,63 +431,10 @@
}
private void addPathElement () {
- JFileChooser chooser = new JFileChooser ();
- FileUtil.preventFileChooserSymlinkTraversal(chooser, null);
- chooser.setMultiSelectionEnabled (true);
- String title = null;
- String message = null;
- String approveButtonName = null;
- String approveButtonNameMne = null;
- if (this.type == SOURCES) {
- title = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_OpenSources");
- message = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_Sources");
- approveButtonName = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_OpenSources");
- approveButtonNameMne = NbBundle.getMessage (J2SEPlatformCustomizer.class,"MNE_OpenSources");
- }
- else if (this.type == JAVADOC) {
- title = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_OpenJavadoc");
- message = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_Javadoc");
- approveButtonName = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_OpenJavadoc");
- approveButtonNameMne = NbBundle.getMessage (J2SEPlatformCustomizer.class,"MNE_OpenJavadoc");
- }
- chooser.setDialogTitle(title);
- chooser.setApproveButtonText(approveButtonName);
- chooser.setApproveButtonMnemonic (approveButtonNameMne.charAt(0));
- chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
- if (Utilities.isMac()) {
- //New JDKs and JREs are bundled into package, allow JFileChooser to navigate in
- chooser.putClientProperty("JFileChooser.packageIsTraversable", "always"); //NOI18N
- }
- //#61789 on old macosx (jdk 1.4.1) these two method need to be called in this order.
- chooser.setAcceptAllFileFilterUsed( false );
- chooser.setFileFilter (new ArchiveFileFilter(message,new String[] {"ZIP","JAR"})); //NOI18N
- if (this.currentDir != null) {
- chooser.setCurrentDirectory(this.currentDir);
- }
- if (chooser.showOpenDialog(this)==JFileChooser.APPROVE_OPTION) {
- File[] fs = chooser.getSelectedFiles();
- PathModel model = (PathModel) this.resources.getModel();
- boolean addingFailed = false;
- int firstIndex = this.resources.getModel().getSize();
- for (File f : fs) {
- //XXX: JFileChooser workaround (JDK bug #5075580), double click on folder returns wrong file
- // E.g. for /foo/src it returns /foo/src/src
- // Try to convert it back by removing last invalid name component
- if (!f.exists()) {
- File parent = f.getParentFile();
- if (parent != null && f.getName().equals(parent.getName()) && parent.exists()) {
- f = parent;
- }
- }
- if (f.exists()) {
- addingFailed|=!model.addPath (f);
- }
- }
- if (addingFailed) {
- new NotifyDescriptor.Message (NbBundle.getMessage(J2SEPlatformCustomizer.class,"TXT_CanNotAddResolve"),
- NotifyDescriptor.ERROR_MESSAGE);
- }
- int lastIndex = this.resources.getModel().getSize()-1;
+ final int firstIndex = this.resources.getModel().getSize();
+ final File[] cwd = new File[]{currentDir};
+ if (select((PathModel)this.resources.getModel(),cwd, this)) {
+ final int lastIndex = this.resources.getModel().getSize()-1;
if (firstIndex<=lastIndex) {
int[] toSelect = new int[lastIndex-firstIndex+1];
for (int i = 0; i < toSelect.length; i++) {
@@ -433,7 +442,7 @@
}
this.resources.setSelectedIndices(toSelect);
}
- this.currentDir = FileUtil.normalizeFile(chooser.getCurrentDirectory());
+ this.currentDir = cwd[0];
}
}
@@ -491,7 +500,7 @@
}
- private static class PathModel extends AbstractListModel/**/ {
+ static class PathModel extends AbstractListModel/**/ {
private J2SEPlatformImpl platform;
private int type;
diff --git a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/J2SEPlatformImpl.java b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/J2SEPlatformImpl.java
--- a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/J2SEPlatformImpl.java
+++ b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/J2SEPlatformImpl.java
@@ -476,6 +476,19 @@
}
return Collections.emptyList();
}
+
+ boolean isBroken () {
+ if (getInstallFolders().isEmpty()) {
+ return true;
+ }
+ for (String tool : PlatformConvertor.IMPORTANT_TOOLS) {
+ if (findTool(tool) == null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private static final Map OFFICIAL_JAVADOC = new HashMap();
static {
OFFICIAL_JAVADOC.put("1.0", null); // NOI18N
diff --git a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/J2SEPlatformNode.java b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/J2SEPlatformNode.java
--- a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/J2SEPlatformNode.java
+++ b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/J2SEPlatformNode.java
@@ -67,7 +67,7 @@
}
public String getHtmlDisplayName() {
- if (isBroken()) {
+ if (platform.isBroken()) {
return ""+this.platform.getDisplayName()+"";
}
else {
@@ -103,7 +103,7 @@
}
public java.awt.Component getCustomizer () {
- if (isBroken()) {
+ if (platform.isBroken()) {
return new BrokenPlatformCustomizer (this.platform);
}
else {
@@ -111,16 +111,4 @@
}
}
- private boolean isBroken () {
- if (this.platform.getInstallFolders().size()==0) {
- return true;
- }
- for (String tool : PlatformConvertor.IMPORTANT_TOOLS) {
- if (platform.findTool(tool) == null) {
- return true;
- }
- }
- return false;
- }
-
}
diff --git a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/J2SEPlatformSourceJavadocAttacher.java b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/J2SEPlatformSourceJavadocAttacher.java
new file mode 100644
--- /dev/null
+++ b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/J2SEPlatformSourceJavadocAttacher.java
@@ -0,0 +1,102 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 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 2011 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.java.j2seplatform.platformdefinition;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.platform.JavaPlatform;
+import org.netbeans.api.java.platform.JavaPlatformManager;
+import org.netbeans.api.java.platform.Specification;
+import org.netbeans.spi.java.queries.SourceJavadocAttacherImplementation;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ *
+ * @author Tomas Zezula
+ */
+@ServiceProvider(service=SourceJavadocAttacherImplementation.class,position=150)
+public class J2SEPlatformSourceJavadocAttacher implements SourceJavadocAttacherImplementation {
+
+ @Override
+ public Result attachSources(final URL root) throws IOException {
+ return attach(root, J2SEPlatformCustomizer.SOURCES);
+ }
+
+ @Override
+ public Result attachJavadoc(final URL root) throws IOException {
+ return attach(root, J2SEPlatformCustomizer.JAVADOC);
+ }
+
+ private Result attach(final URL root, int mode) {
+ final J2SEPlatformImpl platform = findOwner(root);
+ if (platform == null) {
+ return Result.UNSUPPORTED;
+ }
+ final J2SEPlatformCustomizer.PathModel model = new J2SEPlatformCustomizer.PathModel(platform, mode);
+ if (J2SEPlatformCustomizer.select(model,new File[1],null)) {
+ return Result.ATTACHED;
+ }
+ return Result.CANCELED;
+ }
+
+ private J2SEPlatformImpl findOwner(final URL root) {
+ for (JavaPlatform p : JavaPlatformManager.getDefault().getPlatforms(null, new Specification(J2SEPlatformImpl.PLATFORM_J2SE, null))) {
+ if (!(p instanceof J2SEPlatformImpl)) {
+ //Cannot handle unknown platform
+ continue;
+ }
+ final J2SEPlatformImpl j2sep = (J2SEPlatformImpl) p;
+ if (j2sep.isBroken()) {
+ continue;
+ }
+ for (ClassPath.Entry entry : j2sep.getBootstrapLibraries().entries()) {
+ if (root.equals(entry.getURL())) {
+ return j2sep;
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/queries/DefaultJavadocForBinaryQuery.java b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/queries/DefaultJavadocForBinaryQuery.java
new file mode 100644
--- /dev/null
+++ b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/queries/DefaultJavadocForBinaryQuery.java
@@ -0,0 +1,64 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 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 2011 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.java.j2seplatform.queries;
+
+import java.net.URL;
+import java.util.Map;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.java.queries.JavadocForBinaryQuery;
+import org.netbeans.api.java.queries.JavadocForBinaryQuery.Result;
+import org.netbeans.spi.java.queries.JavadocForBinaryQueryImplementation;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ *
+ * @author Tomas Zezula
+ */
+@ServiceProvider(service=JavadocForBinaryQueryImplementation.class) //position = last
+public class DefaultJavadocForBinaryQuery implements JavadocForBinaryQueryImplementation {
+
+ @Override
+ public Result findJavadoc(@NonNull final URL binaryRoot) {
+ final Map mapping = QueriesCache.getJavadoc().getRoots();
+ return mapping.get(binaryRoot);
+ }
+}
diff --git a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/queries/DefaultSourceForBinaryQuery.java b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/queries/DefaultSourceForBinaryQuery.java
new file mode 100644
--- /dev/null
+++ b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/queries/DefaultSourceForBinaryQuery.java
@@ -0,0 +1,69 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 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 2011 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.java.j2seplatform.queries;
+
+import java.net.URL;
+import java.util.Map;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.java.queries.SourceForBinaryQuery;
+import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation2;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ *
+ * @author Tomas Zezula
+ */
+@ServiceProvider(service=SourceForBinaryQueryImplementation2.class) //position = last
+public class DefaultSourceForBinaryQuery implements SourceForBinaryQueryImplementation2 {
+
+ @Override
+ public Result findSourceRoots2(@NonNull final URL binaryRoot) {
+ final Map mapping = QueriesCache.getSources().getRoots();
+ return mapping.get(binaryRoot);
+ }
+
+ @Override
+ public SourceForBinaryQuery.Result findSourceRoots(URL binaryRoot) {
+ return findSourceRoots2(binaryRoot);
+ }
+
+}
diff --git a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/queries/DefaultSourceJavadocAttacher.java b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/queries/DefaultSourceJavadocAttacher.java
new file mode 100644
--- /dev/null
+++ b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/queries/DefaultSourceJavadocAttacher.java
@@ -0,0 +1,140 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 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 2011 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.java.j2seplatform.queries;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.JFileChooser;
+import javax.swing.filechooser.FileFilter;
+import org.netbeans.spi.java.project.support.JavadocAndSourceRootDetection;
+import org.netbeans.spi.java.queries.SourceJavadocAttacherImplementation;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileStateInvalidException;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.NbBundle;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ *
+ * @author Tomas Zezula
+ */
+@ServiceProvider(service=SourceJavadocAttacherImplementation.class) //position=last
+public class DefaultSourceJavadocAttacher implements SourceJavadocAttacherImplementation {
+
+ @Override
+ public Result attachSources(URL root) throws IOException {
+ final URL[] sources = selectRoots(0);
+ if (sources != null) {
+ QueriesCache.getSources().updateRoot(root, sources);
+ return Result.ATTACHED;
+ }
+ return Result.CANCELED;
+ }
+
+ @Override
+ public Result attachJavadoc(URL root) throws IOException {
+ final URL[] javadoc = selectRoots(1);
+ if (javadoc != null) {
+ QueriesCache.getSources().updateRoot(root, javadoc);
+ return Result.ATTACHED;
+ }
+ return Result.CANCELED;
+ }
+
+ @NbBundle.Messages({
+ "TXT_Title=Browse ZIP/Folder",
+ "TXT_Javadoc=Library Javadoc (folder, ZIP or JAR file)",
+ "TXT_Sources=Library Sources (folder, ZIP or JAR file)",
+ "TXT_Select=Add ZIP/Folder",
+ "MNE_Select=A"
+ })
+ private static URL[] selectRoots(final int mode) throws MalformedURLException, FileStateInvalidException {
+ final JFileChooser chooser = new JFileChooser();
+ chooser.setMultiSelectionEnabled (true);
+ chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
+ chooser.setDialogTitle(Bundle.TXT_Title());
+ chooser.setFileFilter (new FileFilter() {
+ @Override
+ public boolean accept(File f) {
+ try {
+ return f.isDirectory() ||
+ FileUtil.isArchiveFile(f.toURI().toURL());
+ } catch (MalformedURLException ex) {
+ return false;
+ }
+ }
+
+ @Override
+ public String getDescription() {
+ return mode == 0 ? Bundle.TXT_Sources() : Bundle.TXT_Javadoc();
+ }
+ });
+ chooser.setApproveButtonText(Bundle.TXT_Select());
+ chooser.setApproveButtonMnemonic(Bundle.MNE_Select().charAt(0));
+ if (currentFolder != null) {
+ chooser.setCurrentDirectory(currentFolder);
+ }
+ if (chooser.showOpenDialog(null) == chooser.APPROVE_OPTION) {
+ currentFolder = chooser.getCurrentDirectory();
+ final File[] files = chooser.getSelectedFiles();
+ final List result = new ArrayList(files.length);
+ for (File f : files) {
+ FileObject fo = FileUtil.toFileObject(f);
+ if (fo.isData()) {
+ fo = FileUtil.getArchiveRoot(fo);
+ }
+ fo = mode == 0 ?
+ JavadocAndSourceRootDetection.findSourceRoot(fo) :
+ JavadocAndSourceRootDetection.findJavadocRoot(fo);
+ result.add(fo.getURL());
+ }
+ return result.toArray(new URL[result.size()]);
+ }
+ return null;
+ }
+
+ private static File currentFolder;
+}
diff --git a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/queries/QueriesCache.java b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/queries/QueriesCache.java
new file mode 100644
--- /dev/null
+++ b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/queries/QueriesCache.java
@@ -0,0 +1,268 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 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 2011 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.java.j2seplatform.queries;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.Preferences;
+import javax.swing.event.ChangeListener;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.java.queries.JavadocForBinaryQuery;
+import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation2;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.URLMapper;
+import org.openide.util.ChangeSupport;
+import org.openide.util.Exceptions;
+import org.openide.util.NbPreferences;
+
+/**
+ *
+ * @author Tomas Zezula
+ */
+final class QueriesCache {
+
+ private static QueriesCache javadoc;
+ private static QueriesCache sources;
+ private static final char SEP = '-'; //NOI18N
+
+ private final Object lck = new Object();
+ private final Class clazz;
+ //@GuardedBy("lck")
+ private Map cache;
+
+ private QueriesCache(@NonNull final Class clazz){
+ assert clazz != null;
+ this.clazz = clazz;
+ }
+
+ @NonNull
+ Map getRoots() {
+ return Collections.unmodifiableMap(loadRoots());
+ }
+
+ void updateRoot(final URL binaryRoot, final URL... rootsToAttach) {
+ T currentMapping = null;
+ synchronized (lck) {
+ final Map currentRoots = loadRoots();
+ currentMapping = currentRoots.get(binaryRoot);
+ final Preferences root = NbPreferences.forModule(QueriesCache.class);
+ final Preferences node = root.node(clazz.getSimpleName());
+ final String binaryRootStr = binaryRoot.toExternalForm();
+ try {
+ for (String key : filterKeys(node.keys(),binaryRootStr)) {
+ node.remove(key);
+ }
+ for (int i=0; i < rootsToAttach.length; i++) {
+ node.put(String.format("%s-%d",binaryRootStr,i), rootsToAttach[i].toExternalForm());
+ }
+ node.flush();
+ } catch (BackingStoreException bse) {
+ Exceptions.printStackTrace(bse);
+ }
+ if (currentMapping == null) {
+ try {
+ currentMapping = clazz.newInstance();
+ currentRoots.put(binaryRoot, currentMapping);
+ } catch (InstantiationException ie) {
+ Exceptions.printStackTrace(ie);
+ } catch (IllegalAccessException iae) {
+ Exceptions.printStackTrace(iae);
+ }
+ }
+ }
+ if (currentMapping != null) {
+ currentMapping.update(Arrays.asList(rootsToAttach));
+ }
+ }
+
+ @NonNull
+ private Map loadRoots() {
+ synchronized(lck) {
+ if (cache == null) {
+ Map result = new HashMap();
+ final Preferences root = NbPreferences.forModule(QueriesCache.class);
+ final String folder = clazz.getSimpleName();
+ try {
+ if (root.nodeExists(folder)) {
+ final Preferences node = root.node(folder);
+ Map> bindings = new HashMap>();
+ for (String key : node.keys()) {
+ final String value = node.get(key, null);
+ if (value != null) {
+ final URL binUrl = getURL(key);
+ List binding = bindings.get(binUrl);
+ if(binding == null) {
+ binding = new ArrayList();
+ bindings.put(binUrl,binding);
+ }
+ binding.add(new URL(value));
+ }
+ }
+ for (Map.Entry> e : bindings.entrySet()) {
+ final T instance = clazz.newInstance();
+ instance.update(e.getValue());
+ result.put(e.getKey(), instance);
+ }
+ }
+ } catch (BackingStoreException bse) {
+ Exceptions.printStackTrace(bse);
+ } catch (MalformedURLException mue) {
+ Exceptions.printStackTrace(mue);
+ } catch (InstantiationException ie) {
+ Exceptions.printStackTrace(ie);
+ } catch (IllegalAccessException iae) {
+ Exceptions.printStackTrace(iae);
+ }
+ cache = result;
+ }
+ return cache;
+ }
+ }
+
+ private URL getURL(@NonNull final String pattern) throws MalformedURLException {
+ final int index = pattern.lastIndexOf(SEP); //NOI18N
+ assert index > 0;
+ return new URL(pattern.substring(0, index));
+ }
+
+ private Iterable extends String> filterKeys(
+ final String[] keys,
+ final String binaryRoot) {
+ final List result = new ArrayList();
+ for (int i=0; i getJavadoc() {
+ if (javadoc == null) {
+ javadoc = new QueriesCache(Javadoc.class);
+ }
+ return javadoc;
+ }
+
+ @NonNull
+ static synchronized QueriesCache getSources() {
+ if (sources == null) {
+ sources = new QueriesCache(Sources.class);
+ }
+ return sources;
+ }
+
+ static abstract class ResultBase {
+ private final ChangeSupport cs = new ChangeSupport(this);
+
+ public void addChangeListener(@NonNull final ChangeListener l) {
+ cs.addChangeListener(l);
+ }
+
+ public void removeChangeListener(@NonNull final ChangeListener l) {
+ cs.removeChangeListener(l);
+ }
+
+ public final void update(final Collection extends URL> roots) {
+ updateImpl(roots);
+ cs.fireChange();
+ }
+
+ protected abstract void updateImpl(final Collection extends URL> roots);
+ }
+
+ static class Javadoc extends ResultBase implements JavadocForBinaryQuery.Result {
+ private volatile URL[] roots;
+
+ public URL[] getRoots() {
+ final URL[] tmp = roots;
+ return tmp == null ? new URL[0] : Arrays.copyOf(tmp, tmp.length);
+ }
+
+ @Override
+ protected void updateImpl(final Collection extends URL> roots) {
+ this.roots = roots.toArray(new URL[roots.size()]);
+ }
+ }
+
+ static class Sources extends ResultBase implements SourceForBinaryQueryImplementation2.Result {
+ private volatile FileObject[] roots;
+
+ @Override
+ public boolean preferSources() {
+ return false;
+ }
+
+ @Override
+ public FileObject[] getRoots() {
+ final FileObject[] tmp = roots;
+ return tmp == null ? new FileObject[0]: Arrays.copyOf(tmp, tmp.length);
+ }
+
+ @Override
+ protected void updateImpl(final Collection extends URL> roots) {
+ //Todo: replace by classpath to handle fo listening
+ final List fos = new ArrayList(roots.size());
+ for (URL url : roots) {
+ final FileObject fo = URLMapper.findFileObject(url);
+ if (fo != null) {
+ fos.add(fo);
+ }
+ }
+ this.roots = fos.toArray(new FileObject[fos.size()]);
+ }
+ }
+}
diff --git a/java.source/nbproject/project.xml b/java.source/nbproject/project.xml
--- a/java.source/nbproject/project.xml
+++ b/java.source/nbproject/project.xml
@@ -64,7 +64,7 @@
1
- 1.28
+ 1.35
diff --git a/java.source/src/org/netbeans/modules/java/classfile/AttachSourcePanel.form b/java.source/src/org/netbeans/modules/java/classfile/AttachSourcePanel.form
new file mode 100644
--- /dev/null
+++ b/java.source/src/org/netbeans/modules/java/classfile/AttachSourcePanel.form
@@ -0,0 +1,66 @@
+
+
+
diff --git a/java.source/src/org/netbeans/modules/java/classfile/AttachSourcePanel.java b/java.source/src/org/netbeans/modules/java/classfile/AttachSourcePanel.java
new file mode 100644
--- /dev/null
+++ b/java.source/src/org/netbeans/modules/java/classfile/AttachSourcePanel.java
@@ -0,0 +1,167 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 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 2011 Sun Microsystems, Inc.
+ */
+
+/*
+ * AttachSourcePanel.java
+ *
+ * Created on Aug 1, 2011, 4:54:38 PM
+ */
+package org.netbeans.modules.java.classfile;
+
+import java.net.URL;
+import org.netbeans.api.actions.Openable;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.queries.SourceForBinaryQuery;
+import org.netbeans.api.java.queries.SourceJavadocAttacher;
+import org.netbeans.spi.java.classpath.support.ClassPathSupport;
+import org.openide.cookies.EditorCookie;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.filesystems.URLMapper;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.DataObjectNotFoundException;
+import org.openide.util.Exceptions;
+import org.openide.util.NbBundle;
+
+
+public class AttachSourcePanel extends javax.swing.JPanel {
+
+ private final URL root;
+ private final URL file;
+ private final String binaryName;
+
+ public AttachSourcePanel(
+ @NonNull final URL root,
+ @NonNull final URL file,
+ @NonNull final String binaryName) {
+ assert root != null;
+ assert file != null;
+ assert binaryName != null;
+ this.root = root;
+ this.file = file;
+ this.binaryName = binaryName;
+ initComponents();
+ }
+
+ @NbBundle.Messages({
+ "TXT_UnknownRoot="
+ })
+ private String getFileDisplayName() {
+ final FileObject rootFo = URLMapper.findFileObject(root);
+ return rootFo == null ? Bundle.TXT_UnknownRoot() : FileUtil.getFileDisplayName(rootFo);
+ }
+
+ /** This method is called from within the constructor to
+ * initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is
+ * always regenerated by the Form Editor.
+ */
+ @SuppressWarnings("unchecked")
+ // //GEN-BEGIN:initComponents
+ private void initComponents() {
+
+ jLabel1 = new javax.swing.JLabel();
+ jButton1 = new javax.swing.JButton();
+ jLabel2 = new javax.swing.JLabel();
+
+ jLabel1.setText(org.openide.util.NbBundle.getMessage(AttachSourcePanel.class, "AttachSourcePanel.jLabel1.text")); // NOI18N
+
+ jButton1.setText(org.openide.util.NbBundle.getMessage(AttachSourcePanel.class, "AttachSourcePanel.jButton1.text")); // NOI18N
+ jButton1.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ attachSources(evt);
+ }
+ });
+
+ jLabel2.setText(getFileDisplayName());
+
+ javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+ this.setLayout(layout);
+ layout.setHorizontalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addGap(20, 20, 20)
+ .addComponent(jLabel1)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, 430, Short.MAX_VALUE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jButton1)
+ .addGap(17, 17, 17))
+ );
+ layout.setVerticalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(jLabel1)
+ .addComponent(jLabel2)
+ .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE))
+ );
+ }// //GEN-END:initComponents
+
+private void attachSources(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_attachSources
+ if (SourceJavadocAttacher.attachSources(root)) {
+ final FileObject rootFo = URLMapper.findFileObject(root);
+ final FileObject fileFo = URLMapper.findFileObject(file);
+ if (rootFo != null && fileFo != null) {
+ final FileObject[] fos = SourceForBinaryQuery.findSourceRoots(root).getRoots();
+ if (fos.length > 0) {
+ final ClassPath cp = ClassPathSupport.createClassPath(fos);
+ final FileObject newFileFo = cp.findResource(binaryName + ".java"); //NOI18N
+ if (newFileFo != null) {
+ try {
+ final EditorCookie ec = DataObject.find(fileFo).getLookup().lookup(EditorCookie.class);
+ final Openable open = DataObject.find(newFileFo).getLookup().lookup(Openable.class);
+ if (ec != null && open != null) {
+ ec.close();
+ open.open();
+ }
+ } catch (DataObjectNotFoundException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ }
+ }
+ }
+}//GEN-LAST:event_attachSources
+
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JButton jButton1;
+ private javax.swing.JLabel jLabel1;
+ private javax.swing.JLabel jLabel2;
+ // End of variables declaration//GEN-END:variables
+}
diff --git a/java.source/src/org/netbeans/modules/java/classfile/Bundle.properties b/java.source/src/org/netbeans/modules/java/classfile/Bundle.properties
new file mode 100644
--- /dev/null
+++ b/java.source/src/org/netbeans/modules/java/classfile/Bundle.properties
@@ -0,0 +1,2 @@
+AttachSourcePanel.jLabel1.text=No source associated with:
+AttachSourcePanel.jButton1.text=Associate Source...
diff --git a/java.source/src/org/netbeans/modules/java/classfile/CodeGenerator.java b/java.source/src/org/netbeans/modules/java/classfile/CodeGenerator.java
--- a/java.source/src/org/netbeans/modules/java/classfile/CodeGenerator.java
+++ b/java.source/src/org/netbeans/modules/java/classfile/CodeGenerator.java
@@ -44,6 +44,7 @@
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
+import java.net.URL;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Collections;
@@ -96,8 +97,11 @@
private static final Logger LOG = Logger.getLogger(CodeGenerator.class.getName());
private static final Set UNUSABLE_KINDS = EnumSet.of(ElementKind.PACKAGE);
- private static final String HASH_ATTRIBUTE_NAME = "origin-hash";
- private static final String DISABLE_ERRORS = "disable-java-errors";
+ private static final byte VERSION = 2;
+ private static final String HASH_ATTRIBUTE_NAME = "origin-hash"; //NOI18N
+ private static final String DISABLE_ERRORS = "disable-java-errors"; //NOI18N
+ static final String CLASSFILE_ROOT = "classfile-root"; //NOI18N
+ static final String CLASSFILE_BINNAME = "classfile-binaryName"; //NOI18N
public static FileObject generateCode(final ClasspathInfo cpInfo, final ElementHandle extends Element> toOpenHandle) {
if (UNUSABLE_KINDS.contains(toOpenHandle.getKind())) {
@@ -117,6 +121,8 @@
JavaSource js = JavaSource.create(cpInfo, file);
final FileObject[] result = new FileObject[1];
final boolean[] sourceGenerated = new boolean[1];
+ final URL[] classfileRoot = new URL[1];
+ final String[] binaryName = new String[1];
ModificationResult r = js.runModificationTask(new Task() {
@Override
@@ -135,7 +141,8 @@
return;
}
- final String resourceName = te.getQualifiedName().toString().replace('.', '/') + ".class"; //NOI18N
+ final String binName = te.getQualifiedName().toString().replace('.', '/'); //NOI18N
+ final String resourceName = binName + ".class"; //NOI18N
final FileObject resource = cp.findResource(resourceName);
if (resource == null) {
LOG.info("Cannot find resource: " + resourceName +" on classpath: " + cp.toString()); //NOI18N
@@ -148,6 +155,8 @@
return ;
}
+ classfileRoot[0] = root.getURL();
+ binaryName[0] = binName;
final File sourceRoot = new File (JavaIndex.getIndex(root.getURL()),"gensrc"); //NOI18N
final FileObject sourceRootFO = FileUtil.createFolder(sourceRoot);
if (sourceRootFO == null) {
@@ -155,10 +164,11 @@
return ;
}
- final String path = te.getQualifiedName().toString().replace('.', '/') + ".java"; //NOI18N
+ final String path = binName + ".java"; //NOI18N
final FileObject source = sourceRootFO.getFileObject(path);
MessageDigest md = MessageDigest.getInstance("MD5");
+ md.update(VERSION);
byte[] hashBytes = md.digest(resource.asBytes());
StringBuilder hashBuilder = new StringBuilder();
@@ -207,6 +217,8 @@
if (resultFile != null) {
resultFile.setReadOnly();
result[0].setAttribute(DISABLE_ERRORS, true);
+ result[0].setAttribute(CLASSFILE_ROOT, classfileRoot[0]);
+ result[0].setAttribute(CLASSFILE_BINNAME, binaryName[0]);
}
}
diff --git a/java.source/src/org/netbeans/modules/java/classfile/SideBarFactoryImpl.java b/java.source/src/org/netbeans/modules/java/classfile/SideBarFactoryImpl.java
new file mode 100644
--- /dev/null
+++ b/java.source/src/org/netbeans/modules/java/classfile/SideBarFactoryImpl.java
@@ -0,0 +1,92 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 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 2011 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.java.classfile;
+
+import java.net.URL;
+import javax.swing.JComponent;
+import javax.swing.text.Document;
+import javax.swing.text.JTextComponent;
+import org.netbeans.editor.SideBarFactory;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileStateInvalidException;
+import org.openide.loaders.DataObject;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author lahvac
+ */
+public class SideBarFactoryImpl implements SideBarFactory {
+
+ @Override
+ public JComponent createSideBar(JTextComponent target) {
+ Document doc = target.getDocument();
+ FileObject originFile;
+ Object origin = doc.getProperty(Document.StreamDescriptionProperty);
+
+ if (origin instanceof DataObject) {
+ originFile = ((DataObject) origin).getPrimaryFile();
+ } else if (origin instanceof FileObject) {
+ originFile = (FileObject) origin;
+ } else {
+ originFile = null;
+ }
+
+ Object classFileRoot;
+ Object binaryName;
+ if (originFile != null) {
+ classFileRoot = originFile.getAttribute(CodeGenerator.CLASSFILE_ROOT);
+ binaryName = originFile.getAttribute(CodeGenerator.CLASSFILE_BINNAME);
+ } else {
+ classFileRoot = binaryName = null;
+ }
+
+ if (classFileRoot instanceof URL && binaryName instanceof String) {
+ try {
+ return new AttachSourcePanel(
+ (URL) classFileRoot,
+ originFile.getURL(),
+ (String) binaryName);
+ } catch (FileStateInvalidException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/java.source/src/org/netbeans/modules/java/source/resources/layer.xml b/java.source/src/org/netbeans/modules/java/source/resources/layer.xml
--- a/java.source/src/org/netbeans/modules/java/source/resources/layer.xml
+++ b/java.source/src/org/netbeans/modules/java/source/resources/layer.xml
@@ -285,6 +285,13 @@
+
+
+
+
+
+
+
diff --git a/java.sourceui/nbproject/project.xml b/java.sourceui/nbproject/project.xml
--- a/java.sourceui/nbproject/project.xml
+++ b/java.sourceui/nbproject/project.xml
@@ -11,7 +11,7 @@
1
- 1.18
+ 1.35
diff --git a/java.sourceui/src/org/netbeans/api/java/source/ui/Bundle.properties b/java.sourceui/src/org/netbeans/api/java/source/ui/Bundle.properties
--- a/java.sourceui/src/org/netbeans/api/java/source/ui/Bundle.properties
+++ b/java.sourceui/src/org/netbeans/api/java/source/ui/Bundle.properties
@@ -54,6 +54,8 @@
array_length_field_javadoc=Length of array.
class_constant_javadoc=java.lang.Class constant.
javadoc_content_not_found=Javadoc not found. Either Javadoc documentation for this item does not exist or you have not added specified Javadoc in the Java Platform Manager or the Library Manager.
+javadoc_content_not_found_attach=Javadoc not found. Either Javadoc documentation for this item does not exist or you have not added specified Javadoc in the Java Platform Manager or the Library Manager.\
+ Associate Javadoc to {1}
LBL_HTTPJavadocDownload=Downloading HTTP Javadoc
LBL_CancelAction=Cancel {0}
diff --git a/java.sourceui/src/org/netbeans/api/java/source/ui/ElementJavadoc.java b/java.sourceui/src/org/netbeans/api/java/source/ui/ElementJavadoc.java
--- a/java.sourceui/src/org/netbeans/api/java/source/ui/ElementJavadoc.java
+++ b/java.sourceui/src/org/netbeans/api/java/source/ui/ElementJavadoc.java
@@ -59,6 +59,9 @@
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.queries.JavadocForBinaryQuery;
+import org.netbeans.api.java.queries.SourceJavadocAttacher;
import org.netbeans.api.java.source.ClasspathInfo;
import org.netbeans.api.java.source.CompilationController;
import org.netbeans.api.java.source.CompilationInfo;
@@ -73,8 +76,10 @@
import org.netbeans.modules.java.preprocessorbridge.api.JavaSourceUtil;
import org.netbeans.modules.java.source.JavadocHelper;
import org.netbeans.modules.java.source.usages.Pair;
+import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileStateInvalidException;
+import org.openide.filesystems.FileUtil;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
@@ -85,7 +90,8 @@
* @author Dusan Balek, Petr Hrebejk
*/
public class ElementJavadoc {
-
+
+ private static final String ASSOCIATE_JDOC = "associate-javadoc:"; //NOI18N
private static final String API = "/api"; //NOI18N
private static final Set LANGS;
@@ -100,10 +106,9 @@
LANGS = Collections.unmodifiableSet(locNames);
}
- private ElementJavadoc() {
- }
- private ClasspathInfo cpInfo;
+ private final ClasspathInfo cpInfo;
+ private final ElementHandle extends Element> handle;
//private Doc doc;
private volatile Future content;
private Hashtable> links = new Hashtable>();
@@ -184,6 +189,15 @@
* @return ElementJavadoc describing the javadoc of liked element
*/
public ElementJavadoc resolveLink(final String link) {
+ if (link.startsWith(ASSOCIATE_JDOC)) {
+ final String root = link.substring(ASSOCIATE_JDOC.length());
+ try {
+ SourceJavadocAttacher.attachJavadoc(new URL(root));
+ } catch (MalformedURLException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ return null;
+ }
final ElementJavadoc[] ret = new ElementJavadoc[1];
try {
final ElementHandle extends Element> linkDoc = links.get(link);
@@ -273,6 +287,7 @@
private ElementJavadoc(CompilationInfo compilationInfo, Element element, URL url, final Callable cancel) {
Pair context = Pair.of(compilationInfo.getTrees(), compilationInfo.getElementUtilities());
this.cpInfo = compilationInfo.getClasspathInfo();
+ this.handle = element == null ? null : ElementHandle.create(element);
Doc doc = context.second.javaDocFor(element);
boolean localized = false;
StringBuilder content = new StringBuilder();
@@ -287,7 +302,6 @@
if (!localized) {
final FileObject fo = SourceUtils.getFile(element, compilationInfo.getClasspathInfo());
if (fo != null) {
- final ElementHandle extends Element> handle = ElementHandle.create(element);
goToSource = new AbstractAction() {
public void actionPerformed(ActionEvent evt) {
ElementOpen.open(fo, handle);
@@ -311,7 +325,6 @@
this.content = prepareContent(content, doc,localized, page, cancel, true, context);
} catch (RemoteJavadocException re) {
final FileObject fo = compilationInfo.getFileObject();
- final ElementHandle extends Element> handle = ElementHandle.create(element);
final StringBuilder contentFin = content;
final boolean localizedFin = localized;
this.content = new FutureTask(new Callable(){
@@ -346,6 +359,8 @@
assert url != null;
this.content = null;
this.docURL = url;
+ this.handle = null;
+ this.cpInfo = null;
}
// Private section ---------------------------------------------------------
@@ -635,7 +650,7 @@
if (jdText != null)
sb.append(jdText);
else
- sb.append(NbBundle.getMessage(ElementJavadoc.class, "javadoc_content_not_found")); //NOI18N
+ sb.append(noJavadocFound()); //NOI18N
sb.append("
"); //NOI18N
return sb.toString();
}
@@ -648,14 +663,52 @@
}
return task;
}
- sb.append(NbBundle.getMessage(ElementJavadoc.class, "javadoc_content_not_found")); //NOI18N
+ sb.append(noJavadocFound()); //NOI18N
return new Now (sb.toString());
} finally {
if (page != null)
page.close();
}
}
-
+
+ private String noJavadocFound() {
+ final List cps = new ArrayList(2);
+ ClassPath cp = cpInfo.getClassPath(ClasspathInfo.PathKind.BOOT);
+ if (cp != null) {
+ cps.add(cp);
+ }
+ cp = cpInfo.getClassPath(ClasspathInfo.PathKind.COMPILE);
+ if (cp != null) {
+ cps.add(cp);
+ }
+ cp = ClassPathSupport.createProxyClassPath(cps.toArray(new ClassPath[cps.size()]));
+ String toSearch = SourceUtils.getJVMSignature(handle)[0].replace('.', '/');
+ if (handle.getKind() != ElementKind.PACKAGE) {
+ toSearch = toSearch + ".class"; //NOI18N
+ }
+ final FileObject resource = cp.findResource(toSearch);
+ if (resource != null) {
+ final FileObject root = cp.findOwnerRoot(resource);
+ try {
+ final URL rootURL = root.getURL();
+ if (JavadocForBinaryQuery.findJavadoc(rootURL).getRoots().length == 0) {
+ FileObject userRoot = FileUtil.getArchiveFile(root);
+ if (userRoot == null) {
+ userRoot = root;
+ }
+ return NbBundle.getMessage(
+ ElementJavadoc.class,
+ "javadoc_content_not_found_attach",
+ rootURL.toExternalForm(),
+ FileUtil.getFileDisplayName(userRoot));
+ }
+ } catch (FileStateInvalidException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ return NbBundle.getMessage(ElementJavadoc.class, "javadoc_content_not_found");
+ }
+
private CharSequence getContainingClassOrPackageHeader(ProgramElementDoc peDoc, Pair ctx) {
StringBuilder sb = new StringBuilder();
ClassDoc cls = peDoc.containingClass();
diff --git a/maven.embedder/src/org/netbeans/modules/maven/embedder/EmbedderFactory.java b/maven.embedder/src/org/netbeans/modules/maven/embedder/EmbedderFactory.java
--- a/maven.embedder/src/org/netbeans/modules/maven/embedder/EmbedderFactory.java
+++ b/maven.embedder/src/org/netbeans/modules/maven/embedder/EmbedderFactory.java
@@ -52,7 +52,6 @@
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.UnknownRepositoryLayoutException;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
@@ -61,6 +60,7 @@
import org.codehaus.plexus.classworlds.ClassWorld;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import java.util.prefs.Preferences;
+import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
import org.apache.maven.model.Model;
import org.apache.maven.model.building.DefaultModelBuildingRequest;
import org.apache.maven.model.building.ModelBuilder;
@@ -346,16 +346,11 @@
}
public static ArtifactRepository createRemoteRepository(MavenEmbedder embedder, String url, String id) {
- try {
- ArtifactRepositoryFactory fact = embedder.lookupComponent(ArtifactRepositoryFactory.class);
- assert fact!=null : "ArtifactRepositoryFactory component not found in maven";
- ArtifactRepositoryPolicy snapshotsPolicy = new ArtifactRepositoryPolicy(true, ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS, ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN);
- ArtifactRepositoryPolicy releasesPolicy = new ArtifactRepositoryPolicy(true, ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS, ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN);
- return fact.createArtifactRepository(id, url, ArtifactRepositoryFactory.DEFAULT_LAYOUT_ID, snapshotsPolicy, releasesPolicy);
- } catch (UnknownRepositoryLayoutException ex) {
- Exceptions.printStackTrace(ex);
- }
- return null;
+ ArtifactRepositoryFactory fact = embedder.lookupComponent(ArtifactRepositoryFactory.class);
+ assert fact!=null : "ArtifactRepositoryFactory component not found in maven";
+ ArtifactRepositoryPolicy snapshotsPolicy = new ArtifactRepositoryPolicy(true, ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS, ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN);
+ ArtifactRepositoryPolicy releasesPolicy = new ArtifactRepositoryPolicy(true, ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS, ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN);
+ return fact.createArtifactRepository(id, url, new DefaultRepositoryLayout(), snapshotsPolicy, releasesPolicy);
}
/**
diff --git a/maven/nbproject/project.xml b/maven/nbproject/project.xml
--- a/maven/nbproject/project.xml
+++ b/maven/nbproject/project.xml
@@ -82,7 +82,7 @@
1
- 1.25
+ 1.35
diff --git a/maven/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImpl.java b/maven/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImpl.java
--- a/maven/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImpl.java
+++ b/maven/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImpl.java
@@ -54,6 +54,7 @@
import java.util.prefs.Preferences;
import javax.swing.event.ChangeListener;
import org.apache.maven.project.MavenProject;
+import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.modules.maven.NbMavenProjectImpl;
@@ -149,9 +150,13 @@
}
return null;
}
-
- private Project getOwner(File file) {
- LOG.log(Level.FINER, "Looking for owner of {0}", file);
+
+ /**
+ * Utility method to identify a file which might be an artifact in the local repository.
+ * @param file a putative artifact
+ * @return its coordinates (groupId/artifactId/version), or null if it cannot be identified
+ */
+ static @CheckForNull String[] findCoordinates(File file) {
String nm = file.getName(); // commons-math-2.1.jar
File parentVer = file.getParentFile(); // ~/.m2/repository/org/apache/commons/commons-math/2.1
if (parentVer != null) {
@@ -163,16 +168,14 @@
File parentGroup = parentArt.getParentFile(); // ~/.m2/repository/org/apache/commons
if (parentGroup != null) {
// Split rest into separate method, to avoid linking EmbedderFactory unless and until needed.
- return getArtifactOwner(parentGroup, artifactID, version);
+ return findCoordinates(parentGroup, artifactID, version);
}
}
}
}
return null;
}
-
- private Project getArtifactOwner(File parentGroup, String artifactID, String version) {
- LOG.log(Level.FINER, "Checking {0} / {1} / {2}", new Object[] {parentGroup, artifactID, version});
+ private static @CheckForNull String[] findCoordinates(File parentGroup, String artifactID, String version) {
File repo = new File(EmbedderFactory.getProjectEmbedder().getLocalRepository().getBasedir()); // ~/.m2/repository
String repoS = repo.getAbsolutePath();
if (!repoS.endsWith(File.separator)) {
@@ -184,51 +187,62 @@
}
if (parentGroupS.startsWith(repoS)) {
String groupID = parentGroupS.substring(repoS.length()).replace(File.separatorChar, '.'); // org.apache.commons
- String key = groupID + ':' + artifactID; // org.apache.commons:commons-math
- String ownerURI = prefs().get(key, null);
- if (ownerURI != null) {
- boolean stale = true;
- try {
- FileObject projectDir = URLMapper.findFileObject(new URI(ownerURI).toURL());
- if (projectDir != null && projectDir.isFolder()) {
- Project p = ProjectManager.getDefault().findProject(projectDir);
- if (p != null) {
- NbMavenProjectImpl mp = p.getLookup().lookup(NbMavenProjectImpl.class);
- if (mp != null) {
- MavenProject model = mp.getOriginalMavenProject();
- if (model.getGroupId().equals(groupID) && model.getArtifactId().equals(artifactID)) {
- if (model.getVersion().equals(version)) {
- LOG.log(Level.FINE, "Found match {0}", p);
- return p;
- } else {
- LOG.log(Level.FINE, "Mismatch on version {0} in {1}", new Object[] {model.getVersion(), ownerURI});
- stale = false; // we merely remembered another version
- }
+ return new String[] {groupID, artifactID, version};
+ } else {
+ return null;
+ }
+ }
+
+ private Project getOwner(File file) {
+ LOG.log(Level.FINER, "Looking for owner of {0}", file);
+ String[] coordinates = findCoordinates(file);
+ if (coordinates == null) {
+ LOG.log(Level.FINE, "{0} not an artifact in local repo", file);
+ return null;
+ }
+ LOG.log(Level.FINER, "Checking {0} / {1} / {2}", coordinates);
+ String key = coordinates[0] + ':' + coordinates[1]; // org.apache.commons:commons-math
+ String ownerURI = prefs().get(key, null);
+ if (ownerURI != null) {
+ boolean stale = true;
+ try {
+ FileObject projectDir = URLMapper.findFileObject(new URI(ownerURI).toURL());
+ if (projectDir != null && projectDir.isFolder()) {
+ Project p = ProjectManager.getDefault().findProject(projectDir);
+ if (p != null) {
+ NbMavenProjectImpl mp = p.getLookup().lookup(NbMavenProjectImpl.class);
+ if (mp != null) {
+ MavenProject model = mp.getOriginalMavenProject();
+ if (model.getGroupId().equals(coordinates[0]) && model.getArtifactId().equals(coordinates[1])) {
+ if (model.getVersion().equals(coordinates[2])) {
+ LOG.log(Level.FINE, "Found match {0}", p);
+ return p;
} else {
- LOG.log(Level.FINE, "Mismatch on group and/or artifact ID in {0}", ownerURI);
+ LOG.log(Level.FINE, "Mismatch on version {0} in {1}", new Object[] {model.getVersion(), ownerURI});
+ stale = false; // we merely remembered another version
}
} else {
- LOG.log(Level.FINE, "Not a Maven project {0} in {1}", new Object[] {p, ownerURI});
+ LOG.log(Level.FINE, "Mismatch on group and/or artifact ID in {0}", ownerURI);
}
} else {
- LOG.log(Level.FINE, "No such project in {0}", ownerURI);
+ LOG.log(Level.FINE, "Not a Maven project {0} in {1}", new Object[] {p, ownerURI});
}
} else {
- LOG.log(Level.FINE, "No such folder {0}", ownerURI);
+ LOG.log(Level.FINE, "No such project in {0}", ownerURI);
}
- } catch (IOException x) {
- LOG.log(Level.FINE, "Could not load project in " + ownerURI, x);
- } catch (URISyntaxException x) {
- LOG.log(Level.INFO, null, x);
+ } else {
+ LOG.log(Level.FINE, "No such folder {0}", ownerURI);
}
- if (stale) {
- prefs().remove(key); // stale
- }
- } else {
- LOG.log(Level.FINE, "No known owner for {0}", key);
+ } catch (IOException x) {
+ LOG.log(Level.FINE, "Could not load project in " + ownerURI, x);
+ } catch (URISyntaxException x) {
+ LOG.log(Level.INFO, null, x);
+ }
+ if (stale) {
+ prefs().remove(key); // stale
}
} else {
- LOG.log(Level.FINE, "Not in local repo {0}", repoS);
+ LOG.log(Level.FINE, "No known owner for {0}", key);
}
return null;
}
diff --git a/maven/src/org/netbeans/modules/maven/queries/MavenSourceJavadocAttacher.java b/maven/src/org/netbeans/modules/maven/queries/MavenSourceJavadocAttacher.java
new file mode 100644
--- /dev/null
+++ b/maven/src/org/netbeans/modules/maven/queries/MavenSourceJavadocAttacher.java
@@ -0,0 +1,114 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 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 2011 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.maven.queries;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.AbstractArtifactResolutionException;
+import org.netbeans.api.progress.aggregate.AggregateProgressFactory;
+import org.netbeans.api.progress.aggregate.AggregateProgressHandle;
+import org.netbeans.api.progress.aggregate.ProgressContributor;
+import org.netbeans.modules.maven.embedder.EmbedderFactory;
+import org.netbeans.modules.maven.embedder.MavenEmbedder;
+import org.netbeans.modules.maven.embedder.exec.ProgressTransferListener;
+import org.netbeans.modules.maven.indexer.api.RepositoryInfo;
+import org.netbeans.modules.maven.indexer.api.RepositoryPreferences;
+import org.netbeans.spi.java.queries.SourceJavadocAttacherImplementation;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.NbBundle.Messages;
+import org.openide.util.lookup.ServiceProvider;
+
+@ServiceProvider(service=SourceJavadocAttacherImplementation.class, position=200)
+public class MavenSourceJavadocAttacher implements SourceJavadocAttacherImplementation {
+
+ @Override public Result attachSources(URL root) throws IOException {
+ return attach(root, false);
+ }
+
+ @Override public Result attachJavadoc(URL root) throws IOException {
+ return attach(root, true);
+ }
+
+ @Messages({"# {0} - artifact ID", "attaching=Attaching {0}"})
+ private Result attach(URL root, boolean javadoc) throws IOException {
+ File file = FileUtil.archiveOrDirForURL(root);
+ if (file == null) {
+ return Result.UNSUPPORTED;
+ }
+ String[] coordinates = MavenFileOwnerQueryImpl.findCoordinates(file);
+ if (coordinates == null) {
+ return Result.UNSUPPORTED;
+ }
+ MavenEmbedder online = EmbedderFactory.getOnlineEmbedder();
+ Artifact art = online.createArtifactWithClassifier(coordinates[0], coordinates[1], coordinates[2], "jar", javadoc ? "javadoc" : "sources");
+ AggregateProgressHandle hndl = AggregateProgressFactory.createHandle(Bundle.attaching(art.getId()),
+ new ProgressContributor[] {AggregateProgressFactory.createProgressContributor("attach")},
+ ProgressTransferListener.cancellable(), null);
+ ProgressTransferListener.setAggregateHandle(hndl);
+ try {
+ hndl.start();
+ List repos = new ArrayList();
+ // XXX is there some way to determine from local metadata which remote repo it is from? (i.e. API to read _maven.repositories)
+ for (RepositoryInfo info : RepositoryPreferences.getInstance().getRepositoryInfos()) {
+ if (info.isRemoteDownloadable()) {
+ repos.add(EmbedderFactory.createRemoteRepository(online, info.getRepositoryUrl(), info.getId()));
+ }
+ }
+ online.resolve(art, repos, online.getLocalRepository());
+ if (art.getFile().isFile()) {
+ return Result.ATTACHED;
+ } else {
+ return Result.CANCELED;
+ }
+ } catch (ThreadDeath d) {
+ return Result.CANCELED;
+ } catch (AbstractArtifactResolutionException x) {
+ return Result.CANCELED;
+ } finally {
+ hndl.finish();
+ ProgressTransferListener.clearAggregateHandle();
+ }
+ }
+
+}
diff --git a/maven/test/unit/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImplTest.java b/maven/test/unit/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImplTest.java
--- a/maven/test/unit/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImplTest.java
+++ b/maven/test/unit/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImplTest.java
@@ -43,6 +43,7 @@
package org.netbeans.modules.maven.queries;
import java.io.File;
+import java.util.Arrays;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.junit.NbTestCase;
import org.netbeans.modules.maven.NbMavenProjectImpl;
@@ -60,8 +61,12 @@
clearWorkDir();
}
- protected @Override int timeOut() {
- return 300000;
+ public void testFindCoordinates() throws Exception {
+ File repo = new File(EmbedderFactory.getProjectEmbedder().getLocalRepository().getBasedir());
+ assertEquals("[test, prj, 1.0]", Arrays.toString(MavenFileOwnerQueryImpl.findCoordinates(new File(repo, "test/prj/1.0/prj-1.0.jar"))));
+ assertEquals("[my.test, prj, 1.0-SNAPSHOT]", Arrays.toString(MavenFileOwnerQueryImpl.findCoordinates(new File(repo, "my/test/prj/1.0-SNAPSHOT/prj-1.0-SNAPSHOT.pom"))));
+ assertEquals("null", Arrays.toString(MavenFileOwnerQueryImpl.findCoordinates(new File(repo, "test/prj/1.0"))));
+ assertEquals("null", Arrays.toString(MavenFileOwnerQueryImpl.findCoordinates(getWorkDir())));
}
public void testMultipleVersions() throws Exception {