diff --git a/apisupport.project/src/org/netbeans/modules/apisupport/project/resources/defaultLookup.png b/apisupport.project/src/org/netbeans/modules/apisupport/project/resources/defaultLookup.png new file mode 100644 index 0000000000000000000000000000000000000000..d59bc91ab49597771ec9f10a7508709dae5a3be6 GIT binary patch literal 552 zc$@(!0@wYCP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ-o=HSORCwBA{Qv(y10?_;fS4F41ONfVf-WG*uJ0zn zrspogqGrX%BCQD$`}F7O^*4WR9eeTX($42UFYZEC4-i0%FfVX13rebTdgQ5cx@EI4 za`J-2;tM^&atr&ngXus2zkj{`eb?mM-*-&<_V@jBkQhJ!fnC7D#LlVD9aX8y>7Kjd zRRqJ=xBnQpg_#(>fBMHztNjq+Tt-fAO)mcm7Df(kpq}zS|9*Z42q176$gx{R!Zd>b zNHYkmD}T@M@}|w!3n9`{sqIcyC2{hkrNU~4@e9kfEdv; q6RAlVAb=Pt&5Zy7L~(8e2rvMK9jAv2IRBLZ0000 files = new HashSet(); List newVisibleFiles = new ArrayList(); + newVisibleFiles.add (this); LayerUtils.LayerHandle handle = LayerUtils.layerForProject(project); FileObject layerFile = handle.getLayerFile(); if (layerFile != null) { diff --git a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/services/Bundle.properties b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/services/Bundle.properties new file mode 100644 --- /dev/null +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/services/Bundle.properties @@ -0,0 +1,38 @@ +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# +# 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. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun 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 2009 Sun Microsystems, Inc. + +SERVICES=Default Lookup diff --git a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/services/ServiceNode.java b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/services/ServiceNode.java new file mode 100644 --- /dev/null +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/services/ServiceNode.java @@ -0,0 +1,141 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 2009 Sun Microsystems, Inc. + */ + +package org.netbeans.modules.apisupport.project.ui.services; + +import java.beans.PropertyChangeEvent; +import javax.swing.Action; +import org.openide.actions.EditAction; +import org.openide.actions.OpenAction; +import org.openide.cookies.EditCookie; +import org.openide.cookies.OpenCookie; +import org.openide.filesystems.FileAttributeEvent; +import org.openide.filesystems.FileChangeListener; +import org.openide.filesystems.FileEvent; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileRenameEvent; +import org.openide.filesystems.FileUtil; +import org.openide.loaders.DataObject; +import org.openide.nodes.FilterNode; +import org.openide.nodes.Node; +import org.openide.nodes.NodeEvent; +import org.openide.nodes.NodeListener; +import org.openide.nodes.NodeMemberEvent; +import org.openide.nodes.NodeReorderEvent; +import org.openide.util.WeakListeners; +import org.openide.util.actions.SystemAction; + +/** + * + * @author Tim Boudreau + */ +final class ServiceNode extends FilterNode implements NodeListener, FileChangeListener { + public ServiceNode(Node nodeDelegate, String fqn) { + super (nodeDelegate); + disableDelegation(DELEGATE_SET_DISPLAY_NAME); + disableDelegation(DELEGATE_GET_DISPLAY_NAME); + setDisplayName(fqn); + nodeDelegate.addNodeListener(WeakListeners.create(NodeListener.class, this, nodeDelegate)); + FileObject file = nodeDelegate.getLookup().lookup(DataObject.class).getPrimaryFile(); + file.addFileChangeListener(FileUtil.weakFileChangeListener(this, file)); + } + + @Override + public Action[] getActions (boolean ignored) { + DataObject dob = getLookup().lookup(DataObject.class); + if (!dob.isValid()) { + return new Action[0]; + } + EditCookie ec = getLookup().lookup(EditCookie.class); + if (ec != null) { + return new Action[] { SystemAction.get(EditAction.class) }; + } else { + OpenCookie oc = getLookup().lookup(OpenCookie.class); + if (oc != null) { + return new Action[] { SystemAction.get(OpenAction.class) }; + } + } + return new Action[0]; } + + public void childrenAdded(NodeMemberEvent ev) { + //do nothing + } + + public void childrenRemoved(NodeMemberEvent ev) { + //do nothing + } + + public void childrenReordered(NodeReorderEvent ev) { + //do nothing + } + + public void nodeDestroyed(NodeEvent ev) { + fireNodeDestroyed(); + } + + public void propertyChange(PropertyChangeEvent evt) { + //do nothing + } + + public void fileFolderCreated(FileEvent fe) { + //do nothing + } + + public void fileDataCreated(FileEvent fe) { + //do nothing + } + + public void fileChanged(FileEvent fe) { + //do nothing + } + + public void fileDeleted(FileEvent fe) { + if (!getLookup().lookup(DataObject.class).isValid()) { + fireNodeDestroyed(); + } + } + + public void fileRenamed(FileRenameEvent fe) { + //do nothing + } + + public void fileAttributeChanged(FileAttributeEvent fe) { + //do nothing + } +} diff --git a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/services/ServicesChildFactory.java b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/services/ServicesChildFactory.java new file mode 100644 --- /dev/null +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/services/ServicesChildFactory.java @@ -0,0 +1,227 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 2009 Sun Microsystems, Inc. + */ +package org.netbeans.modules.apisupport.project.ui.services; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.project.Project; +import org.netbeans.modules.apisupport.project.NbModuleProject; +import org.netbeans.modules.apisupport.project.queries.ClassPathProviderImpl; +import org.netbeans.spi.java.classpath.ClassPathProvider; +import org.openide.filesystems.FileChangeAdapter; +import org.openide.filesystems.FileChangeListener; +import org.openide.filesystems.FileEvent; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileRenameEvent; +import org.openide.filesystems.FileUtil; +import org.openide.loaders.DataObject; +import org.openide.loaders.DataObjectNotFoundException; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.ChildFactory; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.util.Exceptions; +import org.openide.util.NbBundle; +import org.openide.util.lookup.Lookups; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * @author Tim Boudreau + */ +public final class ServicesChildFactory extends ChildFactory.Detachable implements PropertyChangeListener { + private static final String ICON_BASE = + "org/netbeans/modules/apisupport/project/resources/defaultLookup.png"; //NOI18N + private final Project project; + private final Set paths = Collections.synchronizedSet(new HashSet()); + private final FL fl = new FL(); + + public ServicesChildFactory(Project p) { + this.project = p; + } + + public static Node createRoot(Project project) { + AbstractNode result = new AbstractNode(Children.create( + new ServicesChildFactory(project), true), Lookups.singleton(project)); + result.setDisplayName(NbBundle.getMessage(ServicesChildFactory.class, + "SERVICES")); //NOI18N + result.setIconBaseWithExtension(ICON_BASE); + return result; + } + + @Override + protected boolean createKeys(final List toPopulate) { + ClassPathProviderImpl prov = project.getLookup().lookup(ClassPathProviderImpl.class); + TypeFinder.Callback cb = new TypeFinder.Callback() { + public void foundFileObject(FileObject fo, String className) { + toPopulate.add(new ServicesEntry(fo, className)); + paths.add(fo.getPath()); + } + }; + if (prov != null) { + FileChangeListener l = null; + FileObject unitTestRoot = ((NbModuleProject) project).getTestSourceDirectory("unit"); //NOI18N + FileObject funcTestRoot = ((NbModuleProject) project).getTestSourceDirectory("qa-functional"); //NOI18N +outer: for (ClassPath srcPath : prov.getProjectClassPaths(ClassPath.SOURCE)) { + for (FileObject root : srcPath.getRoots()) { + if (root.equals(unitTestRoot) || root.equals(funcTestRoot)) { + continue outer; + } + } + TypeFinder finder = new TypeFinder(ServiceProvider.class.getName(), srcPath); + finder.findTypes(cb); + //Search for legacy META-INF/services entries + for (FileObject root : srcPath.getRoots()) { + FileObject fo = root.getFileObject("META-INF/services"); //NOI18N + if (fo != null) { + if (l == null) { + l = new FileChangeAdapter() { + + @Override + public void fileDataCreated(FileEvent fe) { + refresh(false); + } + + @Override + public void fileDeleted(FileEvent fe) { + refresh(false); + } + + }; + } + + fo.addFileChangeListener(FileUtil.weakFileChangeListener(l, fo)); + for (FileObject file : fo.getChildren()) { + if (file.isData()) { + file.addFileChangeListener(FileUtil.weakFileChangeListener(l, file)); + cb.foundFileObject(file, file.getNameExt()); + } + } + } + } + } + } + return true; + } + + @Override + protected Node createNodeForKey(ServicesEntry key) { + if (key.fo.isValid()) { + try { + return new ServiceNode(DataObject.find(key.fo).getNodeDelegate(), key.fqn); + } catch (DataObjectNotFoundException ex) { + Exceptions.printStackTrace(ex); + } + } + return null; + } + + public void propertyChange(PropertyChangeEvent evt) { + if (ClassPath.PROP_ROOTS.equals(evt.getPropertyName())) { + refresh(true); + } + } + + @Override + protected void addNotify() { + super.addNotify(); + ClassPathProvider prov = project.getLookup().lookup(ClassPathProvider.class); + NbModuleProject m = (NbModuleProject) project; + if (prov != null) { + ClassPath srcPath = prov.findClassPath(m.getSourceDirectory(), ClassPath.SOURCE); + init(srcPath); + } + } + + @Override + protected void removeNotify() { + ClassPathProvider prov = project.getLookup().lookup(ClassPathProvider.class); + NbModuleProject m = (NbModuleProject) project; + if (prov != null) { + ClassPath srcPath = prov.findClassPath(m.getSourceDirectory(), ClassPath.SOURCE); + uninit(srcPath); + } + super.removeNotify(); + } + + private void init(ClassPath srcPath) { + srcPath.addPropertyChangeListener(this); + for (FileObject root : srcPath.getRoots()) { + root.addFileChangeListener(fl); + } + } + + private void uninit(ClassPath srcPath) { + srcPath.removePropertyChangeListener(this); + for (FileObject root : srcPath.getRoots()) { + root.removeFileChangeListener(fl); + } + } + + private class FL extends FileChangeAdapter { + + @Override + public void fileChanged(FileEvent fe) { + FileObject fo = (FileObject) fe.getSource(); + if ("text/x-java".equals(fo.getMIMEType())) { //NOI18N + String path = fo.getPath(); + if (!paths.contains(path)) { + //XXX scan just this file, not everything + refresh(false); + } + } + } + + @Override + public void fileRenamed(FileRenameEvent fe) { + FileObject fo = (FileObject) fe.getSource(); + if ("text/x-java".equals(fo.getMIMEType())) { //NOI18N + String path = fo.getParent().getPath() + "/" + fe.getName() + "." + fe.getExt(); + if (paths.contains(path)) { + refresh(false); + } + } + } + } +} diff --git a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/services/ServicesEntry.java b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/services/ServicesEntry.java new file mode 100644 --- /dev/null +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/services/ServicesEntry.java @@ -0,0 +1,15 @@ +package org.netbeans.modules.apisupport.project.ui.services; + +import org.openide.filesystems.FileObject; + +public final class ServicesEntry { + + FileObject fo; + String fqn; + + public ServicesEntry(FileObject fo, String fqn) { + super(); + this.fo = fo; + this.fqn = fqn; + } +} diff --git a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/services/TypeFinder.java b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/services/TypeFinder.java new file mode 100644 --- /dev/null +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/services/TypeFinder.java @@ -0,0 +1,203 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved. + * + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + * + * 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. + */ +package org.netbeans.modules.apisupport.project.ui.services; + +import com.sun.source.tree.AnnotationTree; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.TreeVisitor; +import com.sun.source.util.SimpleTreeVisitor; +import com.sun.source.util.TreePath; +import com.sun.source.util.Trees; +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.java.source.CancellableTask; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.api.java.source.JavaSource.Phase; +import org.openide.filesystems.FileObject; + +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Types; +import java.awt.*; +import java.io.IOException; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.openide.util.Parameters; + +/** + * Scans a classpath and finds all subtypes of a given type. + * + * @author Tim Boudreau + */ +public class TypeFinder implements CancellableTask { + private volatile boolean cancelled; + private final ClassPath classpath; + private final String fqn; + private Callback callback; + + public TypeFinder(String fqn, ClassPath path) { + this.classpath = path; + this.fqn = fqn; + Parameters.notNull ("Classpath", path); //NOI18N + Parameters.notNull ("AnnotationName", fqn); //NOI18N + } + + public interface Callback { + public void foundFileObject(FileObject fo, String className); + } + + public void findTypes(Callback callback) { + //Don't ever do this kind of IO-heavy work on the event thread + assert !EventQueue.isDispatchThread(); + this.callback = callback; + //recursively iterate all children + for (FileObject fo : classpath.getRoots()) { + analyze(fo); + } + } + + + private void analyze(FileObject fo) { + if (fo.isFolder()) { + for (FileObject child : fo.getChildren()) { + analyze(child); + } + } else if ("java".equals(fo.getExt())) { //NOI18N + JavaSource src = JavaSource.forFileObject(fo); + try { + src.runUserActionTask(this, true); + } catch (IOException ex) { + Logger.getLogger(TypeFinder.class.getName()).log(Level.INFO, + "Problem scanning " + fo.getPath(), ex); //NOI18N + } + } + } + + public void reset() { + cancelled = false; + } + + public void cancel() { + cancelled = true; + } + + public void run(CompilationController compiler) throws Exception { + if (cancelled) { + return; + } + compiler.toPhase(Phase.RESOLVED); + if (cancelled) { + return; + } + List types = + compiler.getCompilationUnit().getTypeDecls(); + for (Tree tree: types) { + if (cancelled) { + return; + } + TypeMirror mirror = compiler.getTrees().getTypeMirror( + TreePath.getPath(compiler.getCompilationUnit(), + tree)); + if (tree instanceof ClassTree && match(compiler, (ClassTree) tree)) { + callback.foundFileObject(compiler.getFileObject(), + mirror.toString()); + } + } + } + + boolean match(CompilationController compiler, ClassTree t) { +// compiler.getTrees(), compiler.getTypes(), compiler.getCompilationUnit()/ +// TypeMirror mirror = trees.getTypeMirror(TreePath.getPath(unit, t)); + V v = new V(compiler); + return t.accept(v, callback); +// return match(mirror, types); + } + + /* + boolean match(TypeMirror mirror, Types types) { + boolean result = false; + if (mirror != null && + !"java.lang.Object".equals(mirror.toString())) { //NOI18N + + result = fqn.equals(mirror.toString()); + if (!result) { + List l = + types.directSupertypes(mirror); + + for (TypeMirror tm : l) { + result = match(tm, types); + if (cancelled) return result; + if (result) break; + } + } + } + return result; + } + */ + + private class V extends SimpleTreeVisitor { + private final CompilationController compiler; + V (CompilationController compiler) { + this.compiler = compiler; + } + + @Override + public Boolean visitAnnotation(AnnotationTree node, Callback p) { + TypeMirror mirror = compiler.getTrees().getTypeMirror(TreePath.getPath(compiler.getCompilationUnit(), node)); + return fqn.equals (mirror.toString()); + } + + @Override + public Boolean visitClass(ClassTree node, Callback p) { + boolean result = false; + for (AnnotationTree t : node.getModifiers().getAnnotations()) { + result = visitAnnotation(t, p); + if (result) { + break; + } + } + return result; + } + + } +}