--- a/maven/nbproject/project.xml +++ a/maven/nbproject/project.xml @@ -162,7 +162,7 @@ 1 - 1.25 + 1.35 --- a/maven/src/org/netbeans/modules/maven/actions/CreateLibraryAction.java +++ a/maven/src/org/netbeans/modules/maven/actions/CreateLibraryAction.java @@ -42,6 +42,10 @@ package org.netbeans.modules.maven.actions; +import java.util.Set; +import org.apache.maven.model.building.ModelBuildingRequest; +import org.apache.maven.model.License; +import org.netbeans.api.annotations.common.NonNull; import org.codehaus.plexus.util.FileUtils; import java.awt.event.ActionEvent; import java.io.File; @@ -51,19 +55,26 @@ import java.net.URL; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractAction; +import javax.swing.JEditorPane; +import javax.swing.JScrollPane; import javax.swing.SwingUtilities; import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy; +import org.apache.maven.artifact.repository.MavenArtifactRepository; +import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout; +import org.apache.maven.project.DefaultProjectBuildingRequest; import org.netbeans.api.annotations.common.SuppressWarnings; import org.netbeans.modules.maven.embedder.MavenEmbedder; import org.apache.maven.project.MavenProject; import org.apache.maven.shared.dependency.tree.DependencyNode; -import org.netbeans.api.annotations.common.CheckForNull; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; import org.netbeans.api.project.libraries.LibrariesCustomizer; @@ -72,13 +83,15 @@ import org.netbeans.modules.maven.api.FileUtilities; import org.netbeans.modules.maven.embedder.EmbedderFactory; 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.project.support.JavadocAndSourceRootDetection; import org.netbeans.spi.project.libraries.support.LibrariesSupport; import org.openide.DialogDescriptor; import org.openide.DialogDisplayer; +import org.openide.NotifyDescriptor; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; -import org.openide.util.Exceptions; import org.openide.util.ImageUtilities; import org.openide.util.Lookup; import org.openide.util.LookupEvent; @@ -123,9 +136,13 @@ if (DialogDisplayer.getDefault().notify(dd) == DialogDescriptor.OK_OPTION) { RequestProcessor.getDefault().post(new Runnable() { public @Override void run() { + try { Library lib = createLibrary(pnl.getLibraryManager(), pnl.getLibraryName(), pnl.getIncludeArtifacts(), pnl.isAllSourceAndJavadoc(), project, pnl.getCopyDirectory()); - if (lib != null) { LibrariesCustomizer.showCustomizer(lib, pnl.getLibraryManager()); + } catch (ThreadDeath d) { + // download canceled; ignore + } catch (Exception x) { + Logger.getLogger(CreateLibraryAction.class.getName()).log(Level.INFO, "could not download " + pnl.getLibraryName(), x); } } }); @@ -140,22 +157,25 @@ }); } + private static final Set acceptedLicenses = new HashSet(); + @Messages({ "MSG_Create_Library=Create Library", + "MSG_Downloading_pom=Maven: downloading POM for {0}", + "MSG_Downloading_license=Maven: downloading license for {0}", + "TITLE_accept_license=Accept License for {0}", "MSG_Downloading=Maven: downloading {0}", "MSG_Downloading_javadoc=Maven: downloading Javadoc {0}", "MSG_Downloading_sources=Maven: downloading sources {0}" }) @SuppressWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE") // baseFolder.mkdirs; will throw IOE later from getJarUri - private static @CheckForNull Library createLibrary(LibraryManager libraryManager, String libraryName, List includeArtifacts, boolean allSourceAndJavadoc, MavenProject project, String copyTo) { + static @NonNull Library createLibrary(LibraryManager libraryManager, String libraryName, List includeArtifacts, boolean allSourceAndJavadoc, MavenProject project, String copyTo) throws Exception { ProgressHandle handle = ProgressHandleFactory.createHandle(MSG_Create_Library(), ProgressTransferListener.cancellable()); - int count = includeArtifacts.size() * (allSourceAndJavadoc ? 3 : 1) + 5; + int count = includeArtifacts.size() * (allSourceAndJavadoc ? 4 : 2) + 1; handle.start(count); try { - MavenEmbedder online = EmbedderFactory.getOnlineEmbedder(); int index = 1; - List failed = new ArrayList(); List classpathVolume = new ArrayList(); List javadocVolume = new ArrayList(); List sourceVolume = new ArrayList(); @@ -167,15 +187,10 @@ URL libRoot = libraryManager.getLocation(); File base = null; if (libRoot != null) { - try { base = new File(libRoot.toURI()); //getLocation() points to a file base = base.getParentFile(); nonDefaultLibBase = base; - } catch (URISyntaxException ex) { - Exceptions.printStackTrace(ex); - base = new File(System.getProperty("netbeans.user"), "libraries"); - } } else { base = new File(System.getProperty("netbeans.user"), "libraries"); } @@ -188,59 +203,82 @@ volumes.put("javadoc", javadocVolume); //NOI18N volumes.put("src", sourceVolume); //NOI18N } + List remoteArtifactRepositories; + if (project != null) { + remoteArtifactRepositories = project.getRemoteArtifactRepositories(); + } else { + remoteArtifactRepositories = new ArrayList(); + for (RepositoryInfo ri : RepositoryPreferences.getInstance().getRepositoryInfos()) { + if (!ri.isLocal()) { + remoteArtifactRepositories.add(new MavenArtifactRepository(ri.getId(), ri.getRepositoryUrl(), new DefaultRepositoryLayout(), new ArtifactRepositoryPolicy(), new ArtifactRepositoryPolicy())); + } + } + } + MavenEmbedder online = EmbedderFactory.getOnlineEmbedder(); + ArtifactRepository localRepository = online.getLocalRepository(); for (Artifact a : includeArtifacts) { - handle.progress(MSG_Downloading(a.getId()), index); - try { - online.resolve(a, project.getRemoteArtifactRepositories(), online.getLocalRepository()); + Artifact pom = online.createArtifact(a.getGroupId(), a.getArtifactId(), a.getVersion(), "pom"); // NOI18N + handle.progress(MSG_Downloading_pom(a.getId()), index++); + online.resolve(pom, remoteArtifactRepositories, localRepository); + if (pom.getFile().exists()) { + DefaultProjectBuildingRequest dpbr = new DefaultProjectBuildingRequest(); + dpbr.setLocalRepository(localRepository); + dpbr.setRemoteRepositories(remoteArtifactRepositories); + dpbr.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL); + dpbr.setSystemProperties(online.getSystemProperties()); + MavenProject pomPrj = online.buildProject(pom, dpbr).getProject(); + List licenses = pomPrj.getLicenses(); + if (!licenses.isEmpty()) { + String licenseURL = licenses.get(0).getUrl(); + if (licenseURL != null && acceptedLicenses.add(licenseURL)) { + handle.progress(MSG_Downloading_license(a.getId()), index); + // XXX looks terrible for http://opensource.org/*.txt licenses; have contacted webmaster + JEditorPane licensePane = new JEditorPane(licenseURL); + licensePane.setEditable(false); + if (DialogDisplayer.getDefault().notify(new NotifyDescriptor.Confirmation(new JScrollPane(licensePane), TITLE_accept_license(pomPrj.getName()), NotifyDescriptor.OK_CANCEL_OPTION)) != NotifyDescriptor.OK_OPTION) { + throw new Exception("license " + licenseURL + " rejected"); + } + } + } + } + index++; // whether or not we got a license + handle.progress(MSG_Downloading(a.getId()), index++); + online.resolve(a, remoteArtifactRepositories, localRepository); classpathVolume.add(getJarUri(a, baseFolder, nonDefaultLibBase, ClassifierType.BINARY)); - try { if (allSourceAndJavadoc) { - handle.progress(MSG_Downloading_javadoc(a.getId()), index + 1); + handle.progress(MSG_Downloading_javadoc(a.getId()), index++); Artifact javadoc = online.createArtifactWithClassifier( a.getGroupId(), a.getArtifactId(), a.getVersion(), a.getType(), "javadoc"); //NOI18N - online.resolve(javadoc, project.getRemoteArtifactRepositories(), online.getLocalRepository()); + online.resolve(javadoc, remoteArtifactRepositories, localRepository); if (javadoc.getFile().exists()) { URI javadocUri = getJarUri(javadoc, baseFolder, nonDefaultLibBase, ClassifierType.JAVADOC); javadocVolume.add(javadocUri); } - handle.progress(MSG_Downloading_sources(a.getId()), index + 2); + handle.progress(MSG_Downloading_sources(a.getId()), index++); Artifact sources = online.createArtifactWithClassifier( a.getGroupId(), a.getArtifactId(), a.getVersion(), a.getType(), "sources"); //NOI18N - online.resolve(sources, project.getRemoteArtifactRepositories(), online.getLocalRepository()); + online.resolve(sources, remoteArtifactRepositories, localRepository); if (sources.getFile().exists()) { sourceVolume.add(getJarUri(sources, baseFolder, nonDefaultLibBase, ClassifierType.SOURCES)); } } - } catch (Exception ex) { - Logger.getLogger(CreateLibraryAction.class.getName()).log(Level.FINE, "Failed to download artifact", ex); - } - } catch (Exception ex) { - failed.add(a); - Logger.getLogger(CreateLibraryAction.class.getName()).log(Level.FINE, "Failed to download artifact", ex); - } - index = index + (allSourceAndJavadoc ? 3 : 1); } - try { - handle.progress("Adding library", index + 4); + handle.progress("Adding library", index++); + // XXX #182388 would allow us to set a display name here (e.g. based on pomPrj.getName(), maybe plus pomPrj.getVersion()) return libraryManager.createURILibrary("j2se", libraryName, volumes); //NOI18N - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - } catch (ThreadDeath d) { // download interrupted } finally { handle.finish(); } - return null; } /** append path to given jar root uri */ --- a/maven/src/org/netbeans/modules/maven/actions/MavenLibraryDefiner.java +++ a/maven/src/org/netbeans/modules/maven/actions/MavenLibraryDefiner.java @@ -0,0 +1,83 @@ +/* + * 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.actions; + +import java.util.Collections; +import java.util.concurrent.Callable; +import org.netbeans.api.project.libraries.Library; +import org.netbeans.api.project.libraries.LibraryManager; +import org.netbeans.modules.maven.api.NbMavenProject; +import org.netbeans.modules.maven.embedder.EmbedderFactory; +import org.netbeans.spi.java.project.support.ui.BrokenReferencesSupport.LibraryDefiner; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.util.lookup.ServiceProvider; + +/** + * Defines missing libraries using {@code org-netbeans-api-project-libraries/Maven/libname} files. + * Prompts to create a library definition based on an artifact in the local repository + * (and associated secondary artifacts - source and Javadoc), + * first downloading that library if necessary. + * Required attributes are {@code groupId}, {@code artifactId}, and {@code version}. + * Currently does not support specifying a remote repository ID; + * currently supports only {@code j2se}-type libraries based on {@code jar} packaging. + */ +@ServiceProvider(service=LibraryDefiner.class) +public class MavenLibraryDefiner implements LibraryDefiner { + + public @Override Callable missingLibrary(final String name) { + final FileObject def = FileUtil.getConfigFile("org-netbeans-api-project-libraries/Maven/" + name); + if (def == null) { + return null; + } + return new Callable() { + public @Override Library call() throws Exception { + return CreateLibraryAction.createLibrary(LibraryManager.getDefault(), name, Collections.singletonList( + EmbedderFactory.getOnlineEmbedder().createArtifact( + (String) def.getAttribute("groupId"), (String) def.getAttribute("artifactId"), (String) def.getAttribute("version"), NbMavenProject.TYPE_JAR) + ), true, null, null); + } + }; + } + +}