# HG changeset patch # Parent 1c5e0dca4ba6a17d3fa66d10ff5945554dbc1692 # User Jesse Glick Implements definition of missing libraries by downloading a module from the update center. diff --git a/java.project/nbproject/project.xml b/java.project/nbproject/project.xml --- a/java.project/nbproject/project.xml +++ b/java.project/nbproject/project.xml @@ -95,6 +95,14 @@ + org.netbeans.modules.autoupdate.services + + + + 1.23 + + + org.netbeans.modules.classfile diff --git a/java.project/src/org/netbeans/modules/java/project/ModuleDownloadLibraryDefiner.java b/java.project/src/org/netbeans/modules/java/project/ModuleDownloadLibraryDefiner.java new file mode 100644 --- /dev/null +++ b/java.project/src/org/netbeans/modules/java/project/ModuleDownloadLibraryDefiner.java @@ -0,0 +1,138 @@ +/* + * 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.project; + +import java.util.List; +import java.util.concurrent.Callable; +import org.netbeans.api.autoupdate.InstallSupport; +import org.netbeans.api.autoupdate.InstallSupport.Installer; +import org.netbeans.api.autoupdate.InstallSupport.Validator; +import org.netbeans.api.autoupdate.OperationContainer; +import org.netbeans.api.autoupdate.OperationSupport.Restarter; +import org.netbeans.api.autoupdate.UpdateElement; +import org.netbeans.api.autoupdate.UpdateManager; +import org.netbeans.api.autoupdate.UpdateUnit; +import org.netbeans.api.progress.ProgressHandle; +import org.netbeans.api.progress.ProgressHandleFactory; +import org.netbeans.api.project.libraries.Library; +import org.netbeans.api.project.libraries.LibraryManager; +import org.netbeans.spi.java.project.support.ui.BrokenReferencesSupport.LibraryDefiner; +import org.openide.DialogDisplayer; +import org.openide.NotifyDescriptor; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.util.NbBundle.Messages; +import static org.netbeans.modules.java.project.Bundle.*; + +/** + * Defines a library by downloading a module definition. + */ +public class ModuleDownloadLibraryDefiner implements LibraryDefiner { + + @Messages({ + "# {0} - display name of module", "ModuleDownloadLibraryDefiner.downloading=Downloading {0}", + "# {0} - display name of module", "ModuleDownloadLibraryDefiner.accept_license=Accept License for {0}" + }) + public @Override Callable missingLibrary(final String name) { + FileObject f = FileUtil.getConfigFile("org-netbeans-api-project-libraries/Downloads/" + name); // NOI18N + if (f != null) { + final String module = (String) f.getAttribute("module"); // NOI18N + assert module != null; + return new Callable() { + public @Override Library call() throws Exception { + return download(name, module); + } + }; + } else { + return null; + } + } + + @SuppressWarnings("SleepWhileInLoop") + private Library download(String name, String module) throws Exception { + for (UpdateUnit unit : UpdateManager.getDefault().getUpdateUnits(UpdateManager.TYPE.MODULE)) { + if (unit.getCodeName().equals(module)) { + List updates = unit.getAvailableUpdates(); + if (updates.isEmpty()) { + throw new Exception("no updates for " + unit); + } + OperationContainer oc = OperationContainer.createForInstall(); + UpdateElement element = updates.get(0); + if (!oc.canBeAdded(unit, element)) { + throw new Exception("could not add " + element + " to updates"); + } + for (UpdateElement req : oc.add(element).getRequiredElements()) { + oc.add(req); + } + String license = element.getLicence(); + String moduleLabel = element.getDisplayName(); + if (license != null) { + if (DialogDisplayer.getDefault().notify(new NotifyDescriptor.Confirmation(license, ModuleDownloadLibraryDefiner_accept_license(moduleLabel), NotifyDescriptor.OK_CANCEL_OPTION)) != NotifyDescriptor.OK_OPTION) { + throw new Exception("license for " + element + " was rejected"); + } + } + // XXX any benefit in marking handle cancelable? + ProgressHandle handle = ProgressHandleFactory.createHandle(ModuleDownloadLibraryDefiner_downloading(moduleLabel)); + InstallSupport is = oc.getSupport(); + Validator validator = is.doDownload(handle, false); + Installer installer = is.doValidate(validator, null); + Restarter restarter = is.doInstall(installer, null); + if (restarter != null) { + is.doRestart(restarter, null); + } else { + // XXX new library & build.properties apparently do not show up immediately... how to listen properly? + for (int i = 0; i < 10; i++) { + Library lib = LibraryManager.getDefault().getLibrary(name); + if (lib != null) { + return lib; + } + Thread.sleep(1000); + } + throw new Exception(module + " failed to install properly"); + } + } + } + throw new Exception("could not find " + module + " on any update site"); + } + +} diff --git a/java.project/src/org/netbeans/spi/java/project/support/ui/BrokenReferencesSupport.java b/java.project/src/org/netbeans/spi/java/project/support/ui/BrokenReferencesSupport.java --- a/java.project/src/org/netbeans/spi/java/project/support/ui/BrokenReferencesSupport.java +++ b/java.project/src/org/netbeans/spi/java/project/support/ui/BrokenReferencesSupport.java @@ -246,6 +246,11 @@ /** * Service which may be {@linkplain ServiceProvider registered} to download remote libraries or otherwise define them. + *

A predefined implementation allows broken library references to be fixed by downloading a module + * with a library definition. For a library referred to by {@code libs.foo.classpath}, + * just define a layer file {@code org-netbeans-api-project-libraries/Downloads/foo} + * with the {@code module} attribute set to {@code org.netbeans.modules.foo} + * or whatever the code name base of the module defining the library should be. * @since org.netbeans.modules.java.project/1 1.35 */ public interface LibraryDefiner {