diff -r 04d674b90c8a api.debugger/apichanges.xml --- a/api.debugger/apichanges.xml Mon Sep 06 11:55:18 2010 +0200 +++ b/api.debugger/apichanges.xml Tue Sep 07 15:41:25 2010 +0200 @@ -424,6 +424,27 @@ + + + Allow multiple debugger service registrations and position order + + + + + +

+ Allow to specify the order of the debugger service registry. + For the need of being able to define multiple different + registrations for a single instance, @DebuggerServiceRegistrations + and ActionsProvider.Registrations annotations are introduced. +

+
+ + + + +
+ diff -r 04d674b90c8a api.debugger/manifest.mf --- a/api.debugger/manifest.mf Mon Sep 06 11:55:18 2010 +0200 +++ b/api.debugger/manifest.mf Tue Sep 07 15:41:25 2010 +0200 @@ -1,5 +1,5 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.api.debugger/1 OpenIDE-Module-Localizing-Bundle: org/netbeans/api/debugger/Bundle.properties -OpenIDE-Module-Specification-Version: 1.27 +OpenIDE-Module-Specification-Version: 1.28 OpenIDE-Module-Layer: org/netbeans/api/debugger/layer.xml diff -r 04d674b90c8a api.debugger/src/org/netbeans/debugger/registry/DebuggerProcessor.java --- a/api.debugger/src/org/netbeans/debugger/registry/DebuggerProcessor.java Mon Sep 06 11:55:18 2010 +0200 +++ b/api.debugger/src/org/netbeans/debugger/registry/DebuggerProcessor.java Tue Sep 07 15:41:25 2010 +0200 @@ -44,8 +44,12 @@ package org.netbeans.debugger.registry; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -59,16 +63,22 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.MirroredTypeException; +import javax.lang.model.type.MirroredTypesException; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementFilter; import org.netbeans.api.debugger.LazyActionsManagerListener; import org.netbeans.spi.debugger.ActionsProvider; +import org.netbeans.spi.debugger.ContextProvider; import org.netbeans.spi.debugger.DebuggerEngineProvider; import org.netbeans.spi.debugger.DebuggerServiceRegistration; +import org.netbeans.spi.debugger.DebuggerServiceRegistrations; import org.netbeans.spi.debugger.SessionProvider; +import org.openide.filesystems.annotations.LayerBuilder; import org.openide.filesystems.annotations.LayerBuilder.File; import org.openide.filesystems.annotations.LayerGeneratingProcessor; import org.openide.filesystems.annotations.LayerGenerationException; @@ -116,6 +126,16 @@ // write(); cnt++; } + for (Element e : env.getElementsAnnotatedWith(ActionsProvider.Registrations.class)) { + ActionsProvider.Registrations regs = e.getAnnotation(ActionsProvider.Registrations.class); + for (ActionsProvider.Registration reg : regs.value()) { + final String path = reg.path(); + final String[] actions = reg.actions(); + final String[] mimeTypes = reg.activateForMIMETypes(); + handleProviderRegistrationInner(e, ActionsProvider.class, path, actions, mimeTypes); + } + cnt++; + } for (Element e : env.getElementsAnnotatedWith(LazyActionsManagerListener.Registration.class)) { LazyActionsManagerListener.Registration reg = e.getAnnotation(LazyActionsManagerListener.Registration.class); @@ -139,58 +159,146 @@ } for (Element e : env.getElementsAnnotatedWith(DebuggerServiceRegistration.class)) { DebuggerServiceRegistration reg = e.getAnnotation(DebuggerServiceRegistration.class); - - // Class[] classes = reg.types(); - Cant NOT do that, classes are not created at compile time. - // e.getAnnotationMirrors() - use this not to generate MirroredTypeException - String classNames = null; - for (AnnotationMirror am : e.getAnnotationMirrors()) { - if (am.getAnnotationType().toString().equals(DebuggerServiceRegistration.class.getName())) { - Map elementValues = - am.getElementValues(); - //System.err.println("am:\n elementValues = "+elementValues); - for (ExecutableElement ee : elementValues.keySet()) { - if (ee.getSimpleName().contentEquals("types")) { // NOI18N - classNames = elementValues.get(ee).getValue().toString(); - } - } + // TODO: Get rid of AnnotationMirror after http://bugs.sun.com/view_bug.do?bug_id=6519115 is fixed. + AnnotationMirror am = null; + for (AnnotationMirror am_ : e.getAnnotationMirrors()) { + if (am_.getAnnotationType().toString().equals(DebuggerServiceRegistration.class.getName())) { + am = am_; + break; } } - //System.err.println("classNames before translation = "+classNames); - classNames = translateClassNames(classNames); - if (!implementsInterfaces(e, classNames)) { - throw new IllegalArgumentException("Annotated element "+e+" does not implement all interfaces " + classNames); + + handleServiceRegistration(e, reg, am); + cnt++; + } + for (Element e : env.getElementsAnnotatedWith(DebuggerServiceRegistrations.class)) { + DebuggerServiceRegistrations regs = e.getAnnotation(DebuggerServiceRegistrations.class); + // TODO: Get rid of AnnotationMirror after http://bugs.sun.com/view_bug.do?bug_id=6519115 is fixed. + AnnotationMirror amregs = null; + for (AnnotationMirror am_ : e.getAnnotationMirrors()) { + if (am_.getAnnotationType().toString().equals(DebuggerServiceRegistrations.class.getName())) { + amregs = am_; + break; + } } - //System.err.println("classNames after translation = "+classNames); - /* - Class[] classes; - String classNames; - try { - classes = reg.types(); - //className = clazz.getName(); - classNames = null; - } catch (MirroredTypeException mtex) { - TypeMirror tm = mtex.getTypeMirror(); - classes = null; - classNames = tm.toString(); + + DebuggerServiceRegistration[] regsv = regs.value(); + if (regsv == null || regsv.length == 0) { + throw new IllegalArgumentException("No service registration for element "+e); } - */ - String path = reg.path(); - if (path != null && path.length() > 0) { - path = "Debugger/"+path; - } else { - path = "Debugger"; + AnnotationMirror[] ams = new AnnotationMirror[regsv.length]; + Map annElementValues = amregs.getElementValues(); + for (AnnotationValue av : annElementValues.values()) { + Object value = av.getValue(); + if (value instanceof Collection) { + ams = (AnnotationMirror[]) ((Collection) value).toArray(ams); + } } - layer(e).instanceFile(path, null, null). - stringvalue(ContextAwareServiceHandler.SERVICE_NAME, instantiableClassOrMethod(e)). - //stringvalue(ContextAwareServiceHandler.SERVICE_CLASSES, classNames). - taken from instanceOf so that we do not have to provide it twice - stringvalue("instanceOf", classNames). - methodvalue("instanceCreate", "org.netbeans.spi.debugger.ContextAwareSupport", "createService"). - write(); + for (int i = 0; i < regsv.length; i++) { + handleServiceRegistration(e, regsv[i], ams[i]); + } cnt++; } return cnt == annotations.size(); } + private List getTypeMirrors(DebuggerServiceRegistration reg, AnnotationMirror am) { + + /* TODO uncomment this after http://bugs.sun.com/view_bug.do?bug_id=6519115 is fixed. + List typeMirrors = null; + try { + reg.types(); + throw new IllegalStateException("No type mirros obtained from element "+e); + } catch (MirroredTypeException mte) { + typeMirrors = Collections.singletonList(mte.getTypeMirror()); + System.err.println("Have one "+typeMirrors.get(0)+" type mirror for element "+e); + } catch (MirroredTypesException mte) { + typeMirrors = mte.getTypeMirrors(); + System.err.println("Have "+typeMirrors.size()+" type mirrors for element "+e); + System.err.println(" mirrors = "+typeMirrors); + } + */ + + // TODO: Delete the rest of this method after http://bugs.sun.com/view_bug.do?bug_id=6519115 is fixed. + List typeMirrors = null; + Map elementValues = + am.getElementValues(); + //System.err.println("am:\n elementValues = "+elementValues); + String classNames = null; + for (ExecutableElement ee : elementValues.keySet()) { + if (ee.getSimpleName().contentEquals("types")) { // NOI18N + classNames = elementValues.get(ee).getValue().toString(); + } + } + if (classNames == null) { + throw new IllegalArgumentException("Annotation "+am+" does not provide types"); + } + //System.err.println("classNames before translation = "+classNames); + typeMirrors = new ArrayList(); + int i1 = 0; + int i2; + while ((i2 = classNames.indexOf(',', i1)) > 0 || i1 < classNames.length()) { + if (i2 < 0) i2 = classNames.length(); + String className = classNames.substring(i1, i2).trim(); + if (className.endsWith(".class")) { + className = className.substring(0, className.length() - ".class".length()); + } + TypeElement type = processingEnv.getElementUtils().getTypeElement(className); + typeMirrors.add(type.asType()); + i1 = i2 + 1; + } + //System.err.println("=> type mirrors = "+typeMirrors); + + return typeMirrors; + } + + private void handleServiceRegistration(Element e, DebuggerServiceRegistration reg, AnnotationMirror am) throws LayerGenerationException { + // Class[] classes = reg.types(); - Cant NOT do that, classes are not created at compile time. + // e.getAnnotationMirrors() - use this not to generate MirroredTypeException + List typeMirrors = getTypeMirrors(reg, am); + + List notImplTypeMirrors = implementsInterfaces(e, typeMirrors); + if (!notImplTypeMirrors.isEmpty()) { + throw new IllegalArgumentException("Annotated element "+e+" does not implement all interfaces " + notImplTypeMirrors); + } + + String path = reg.path(); + LayerBuilder lb = layer(e); + String className = instantiableClassOrMethod(e); + //System.err.println("icm = "+className); + + StringBuilder classNamesBuilder = new StringBuilder(); + for (TypeMirror tm : typeMirrors) { + TypeElement te = (TypeElement) processingEnv.getTypeUtils().asElement(tm); + String cn; + if (te != null) { + cn = processingEnv.getElementUtils().getBinaryName(te).toString(); + } else { + cn = tm.toString(); + } + if (classNamesBuilder.length() > 0) { + classNamesBuilder.append(", "); + } + classNamesBuilder.append(cn); + } + + if (path != null && path.length() > 0) { + path = "Debugger/"+path; + } else { + path = "Debugger"; + } + //System.err.println("path = "+path); + String basename = className.replace('.', '-'); + LayerBuilder.File f = lb.file(path + "/" + basename + ".instance"); + //LayerBuilder.File f = lb.instanceFile(path, null, Evaluator.class); + f.stringvalue(ContextAwareServiceHandler.SERVICE_NAME, className). + //stringvalue("serviceClass", Evaluator.class.getName()). + stringvalue("instanceOf", classNamesBuilder.toString()). + methodvalue("instanceCreate", "org.netbeans.spi.debugger.ContextAwareSupport", "createService"). + position(reg.position()). + write(); + } + private void handleProviderRegistrationInner(Element e, Class providerClass, String path) throws IllegalArgumentException, LayerGenerationException { handleProviderRegistrationInner(e, providerClass, path, null, null); } @@ -207,9 +315,11 @@ } else { path = "Debugger"; } - File f = layer(e).instanceFile(path, null, providerClass). - stringvalue(ContextAwareServiceHandler.SERVICE_NAME, className). - stringvalue("serviceClass", providerClass.getName()); + LayerBuilder lb = layer(e); + String basename = className.replace('.', '-'); + LayerBuilder.File f = lb.file(path + "/" + basename + ".instance"); + f.stringvalue(ContextAwareServiceHandler.SERVICE_NAME, className). + stringvalue("serviceClass", providerClass.getName()); if (actions != null && actions.length > 0) { f.stringvalue(ContextAwareServiceHandler.SERVICE_ACTIONS, Arrays.toString(actions)); } @@ -267,6 +377,8 @@ case CLASS: case INTERFACE: { TypeElement te = (TypeElement) e; + removeImplementingInterfaces(te.asType(), interfaces); + /* List interfs = te.getInterfaces(); for (TypeMirror tm : interfs) { e = ((DeclaredType) tm).asElement(); @@ -276,6 +388,7 @@ implementsInterfaces(e, interfaces); } } + */ break; } case METHOD: { @@ -299,23 +412,118 @@ return interfaces.isEmpty(); } + private void removeImplementingInterfaces(TypeMirror tm, Set interfaces) { + for (Iterator i = interfaces.iterator(); i.hasNext(); ) { + String type = i.next(); + TypeMirror typeMirror = + processingEnv.getTypeUtils().getDeclaredType( + processingEnv.getElementUtils().getTypeElement(type.replace('$', '.'))); + + if (processingEnv.getTypeUtils().isAssignable(tm, typeMirror)) { + i.remove(); + } + } + } + + private List implementsInterfaces(Element e, List typeMirrors) { + List notImplementedMirrors = Collections.emptyList(); + switch (e.getKind()) { + case CLASS: + case INTERFACE: { + TypeElement te = (TypeElement) e; + TypeMirror tm = te.asType(); + for (TypeMirror typeMirror : typeMirrors) { + if (!processingEnv.getTypeUtils().isAssignable(tm, typeMirror)) { + if (notImplementedMirrors == Collections.EMPTY_LIST) { + notImplementedMirrors = new ArrayList(); + } + notImplementedMirrors.add(typeMirror); + } + } + /* + TypeMirror typeMirror = type != null ? + processingEnv.getTypeUtils().getDeclaredType( + processingEnv.getElementUtils().getTypeElement(type.getName().replace('$', '.'))) : + null; + + processingEnv.getTypeUtils().isAssignable(te.asType(), null); + */ + //removeImplementingInterfaces(te.asType(), interfaces); + /* + List interfs = te.getInterfaces(); + for (TypeMirror tm : interfs) { + e = ((DeclaredType) tm).asElement(); + String clazz = processingEnv.getElementUtils().getBinaryName((TypeElement) e).toString(); + boolean contains = interfaces.remove(clazz); + if (!contains) { + implementsInterfaces(e, interfaces); + } + } + */ + break; + } + case METHOD: { + TypeMirror retType = ((ExecutableElement) e).getReturnType(); + if (retType.getKind().equals(TypeKind.NONE)) { + return typeMirrors; + } else { + TypeElement te = (TypeElement) ((DeclaredType) retType).asElement(); + TypeMirror tm = te.asType(); + for (TypeMirror typeMirror : typeMirrors) { + if (!processingEnv.getTypeUtils().isAssignable(tm, typeMirror)) { + if (notImplementedMirrors == Collections.EMPTY_LIST) { + notImplementedMirrors = new ArrayList(); + } + notImplementedMirrors.add(typeMirror); + } + } + + /* + List interfs = te.getInterfaces(); + for (TypeMirror tm : interfs) { + e = ((DeclaredType) tm).asElement(); + String clazz = processingEnv.getElementUtils().getBinaryName((TypeElement) e).toString(); + interfaces.remove(clazz); + } + */ + } + break; + } + default: + throw new IllegalArgumentException("Annotated element is not loadable as an instance: " + e); + } + return notImplementedMirrors; + } + private String instantiableClassOrMethod(Element e) throws IllegalArgumentException, LayerGenerationException { switch (e.getKind()) { case CLASS: { String clazz = processingEnv.getElementUtils().getBinaryName((TypeElement) e).toString(); + //System.err.println("instantiableClassOrMethod(): class = "+clazz); if (e.getModifiers().contains(Modifier.ABSTRACT)) { throw new LayerGenerationException(clazz + " must not be abstract", e); } { boolean hasDefaultCtor = false; + boolean hasContextCtor = false; for (ExecutableElement constructor : ElementFilter.constructorsIn(e.getEnclosedElements())) { - if (constructor.getParameters().isEmpty()) { + List parameters = constructor.getParameters(); + //System.err.println(" parameters = "+parameters+", size = "+parameters.size()); + if (parameters.isEmpty()) { hasDefaultCtor = true; break; } + if (parameters.size() == 1) { + String type = parameters.get(0).asType().toString(); + //System.err.println("Param type = "+type); + if (ContextProvider.class.getName().equals(type)) { + hasContextCtor = true; + break; + } + } } - if (!hasDefaultCtor) { - throw new LayerGenerationException(clazz + " must have a no-argument constructor", e); + if (!(hasDefaultCtor || hasContextCtor)) { + throw new LayerGenerationException(clazz + " must have a no-argument constructor or constuctor taking "+ContextProvider.class.getName()+" as a parameter.", e); } } /*propType = processingEnv.getElementUtils().getTypeElement("java.util.Properties").asType(); diff -r 04d674b90c8a api.debugger/src/org/netbeans/spi/debugger/ActionsProvider.java --- a/api.debugger/src/org/netbeans/spi/debugger/ActionsProvider.java Mon Sep 06 11:55:18 2010 +0200 +++ b/api.debugger/src/org/netbeans/spi/debugger/ActionsProvider.java Tue Sep 07 15:41:25 2010 +0200 @@ -174,6 +174,16 @@ } + /** + * Allows registration of multiple {@link Registration} annotations. + * @since 1.28 + */ + @Retention(RetentionPolicy.SOURCE) + @Target({ElementType.TYPE}) + public @interface Registrations { + Registration[] value(); + } + static class ContextAware extends ActionsProvider implements ContextAwareService { private static final String ERROR = "error in getting MIMEType"; // NOI18N diff -r 04d674b90c8a api.debugger/src/org/netbeans/spi/debugger/DebuggerServiceRegistration.java --- a/api.debugger/src/org/netbeans/spi/debugger/DebuggerServiceRegistration.java Mon Sep 06 11:55:18 2010 +0200 +++ b/api.debugger/src/org/netbeans/spi/debugger/DebuggerServiceRegistration.java Tue Sep 07 15:41:25 2010 +0200 @@ -72,4 +72,10 @@ * The list of interfaces that this class implements and wish to register for. */ Class[] types(); + + /** + * Position of this service within its path. + * @since 1.28 + */ + int position() default Integer.MAX_VALUE; } diff -r 04d674b90c8a api.debugger/src/org/netbeans/spi/debugger/DebuggerServiceRegistrations.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/api.debugger/src/org/netbeans/spi/debugger/DebuggerServiceRegistrations.java Tue Sep 07 15:41:25 2010 +0200 @@ -0,0 +1,60 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2009 Sun Microsystems, Inc. + */ + +package org.netbeans.spi.debugger; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Allows registration of multiple {@link DebuggerServiceRegistration} annotations. + * @since 1.28 + * + * @author Martin Entlicher + */ +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.TYPE}) +public @interface DebuggerServiceRegistrations { + DebuggerServiceRegistration[] value(); +} diff -r 04d674b90c8a spi.debugger.ui/manifest.mf --- a/spi.debugger.ui/manifest.mf Mon Sep 06 11:55:18 2010 +0200 +++ b/spi.debugger.ui/manifest.mf Tue Sep 07 15:41:25 2010 +0200 @@ -2,6 +2,6 @@ OpenIDE-Module: org.netbeans.spi.debugger.ui/1 OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/debugger/ui/Bundle.properties OpenIDE-Module-Layer: org/netbeans/modules/debugger/resources/mf-layer.xml -OpenIDE-Module-Specification-Version: 2.24 +OpenIDE-Module-Specification-Version: 2.25 OpenIDE-Module-Provides: org.netbeans.spi.debugger.ui OpenIDE-Module-Install: org/netbeans/modules/debugger/ui/DebuggerModule.class diff -r 04d674b90c8a spi.debugger.ui/src/org/netbeans/modules/debugger/ui/registry/DebuggerProcessor.java --- a/spi.debugger.ui/src/org/netbeans/modules/debugger/ui/registry/DebuggerProcessor.java Mon Sep 06 11:55:18 2010 +0200 +++ b/spi.debugger.ui/src/org/netbeans/modules/debugger/ui/registry/DebuggerProcessor.java Tue Sep 07 15:41:25 2010 +0200 @@ -46,6 +46,7 @@ import java.util.Arrays; import java.util.HashSet; +import java.util.List; import java.util.Set; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; @@ -55,15 +56,19 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementFilter; +import org.netbeans.spi.debugger.ContextProvider; import org.netbeans.spi.debugger.ui.AttachType; import org.netbeans.spi.debugger.ui.BreakpointType; import org.netbeans.spi.debugger.ui.ColumnModelRegistration; +import org.netbeans.spi.debugger.ui.ColumnModelRegistrations; import org.netbeans.spi.viewmodel.ColumnModel; +import org.openide.filesystems.annotations.LayerBuilder; import org.openide.filesystems.annotations.LayerGeneratingProcessor; import org.openide.filesystems.annotations.LayerGenerationException; @@ -123,6 +128,15 @@ handleProviderRegistration(e, ColumnModel.class, path, position); cnt++; } + for (Element e : env.getElementsAnnotatedWith(ColumnModelRegistrations.class)) { + ColumnModelRegistrations regs = e.getAnnotation(ColumnModelRegistrations.class); + for (ColumnModelRegistration reg : regs.value()) { + final String path = reg.path(); + final int position = reg.position(); + handleProviderRegistration(e, ColumnModel.class, path, position); + } + cnt++; + } return cnt == annotations.size(); } @@ -136,14 +150,16 @@ } else { path = "Debugger"; } - layer(e).instanceFile(path, null, providerClass). - stringvalue(SERVICE_NAME, className). - stringvalue("serviceClass", providerClass.getName()). - stringvalue("instanceOf", providerClass.getName()). - //methodvalue("instanceCreate", providerClass.getName()+"$ContextAware", "createService"). - methodvalue("instanceCreate", "org.netbeans.modules.debugger.ui.registry."+providerClass.getSimpleName()+"ContextAware", "createService"). - position(position). - write(); + LayerBuilder lb = layer(e); + String basename = className.replace('.', '-'); + LayerBuilder.File f = lb.file(path + "/" + basename + ".instance"); + f.stringvalue(SERVICE_NAME, className). + stringvalue("serviceClass", providerClass.getName()). + stringvalue("instanceOf", providerClass.getName()). + //methodvalue("instanceCreate", providerClass.getName()+"$ContextAware", "createService"). + methodvalue("instanceCreate", "org.netbeans.modules.debugger.ui.registry."+providerClass.getSimpleName()+"ContextAware", "createService"). + position(position). + write(); } private void handleProviderRegistrationDisplayName(Element e, Class providerClass, String displayName, String path, int position) throws IllegalArgumentException, LayerGenerationException { @@ -156,14 +172,16 @@ } else { path = "Debugger"; } - layer(e).instanceFile(path, null, providerClass). - stringvalue(SERVICE_NAME, className). - stringvalue("serviceClass", providerClass.getName()). - stringvalue("instanceOf", providerClass.getName()). - bundlevalue("displayName", displayName). - methodvalue("instanceCreate", providerClass.getName()+"$ContextAware", "createService"). - position(position). - write(); + LayerBuilder lb = layer(e); + String basename = className.replace('.', '-'); + LayerBuilder.File f = lb.file(path + "/" + basename + ".instance"); + f.stringvalue(SERVICE_NAME, className). + stringvalue("serviceClass", providerClass.getName()). + stringvalue("instanceOf", providerClass.getName()). + bundlevalue("displayName", displayName). + methodvalue("instanceCreate", providerClass.getName()+"$ContextAware", "createService"). + position(position). + write(); } private boolean isClassOf(Element e, Class providerClass) { @@ -211,14 +229,24 @@ } { boolean hasDefaultCtor = false; + boolean hasContextCtor = false; for (ExecutableElement constructor : ElementFilter.constructorsIn(e.getEnclosedElements())) { - if (constructor.getParameters().isEmpty()) { + List parameters = constructor.getParameters(); + if (parameters.isEmpty()) { hasDefaultCtor = true; break; } + if (parameters.size() == 1) { + String type = parameters.get(0).asType().toString(); + //System.err.println("Param type = "+type); + if (ContextProvider.class.getName().equals(type)) { + hasContextCtor = true; + break; + } + } } - if (!hasDefaultCtor) { - throw new LayerGenerationException(clazz + " must have a no-argument constructor", e); + if (!(hasDefaultCtor || hasContextCtor)) { + throw new LayerGenerationException(clazz + " must have a no-argument constructor or constuctor taking "+ContextProvider.class.getName()+" as a parameter.", e); } } /*propType = processingEnv.getElementUtils().getTypeElement("java.util.Properties").asType(); diff -r 04d674b90c8a spi.debugger.ui/src/org/netbeans/spi/debugger/ui/ColumnModelRegistrations.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spi.debugger.ui/src/org/netbeans/spi/debugger/ui/ColumnModelRegistrations.java Tue Sep 07 15:41:25 2010 +0200 @@ -0,0 +1,60 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2009 Sun Microsystems, Inc. + */ + +package org.netbeans.spi.debugger.ui; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Allows registration of multiple {@link ColumnModelRegistration} annotations. + * + * @author Martin Entlicher + * @since 2.25 + */ +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.TYPE, ElementType.METHOD}) +public @interface ColumnModelRegistrations { + ColumnModelRegistration[] value(); +} diff -r 04d674b90c8a spi.debugger.ui/test/unit/src/org/netbeans/api/debugger/ProvidersAnnotationTest.java --- a/spi.debugger.ui/test/unit/src/org/netbeans/api/debugger/ProvidersAnnotationTest.java Mon Sep 06 11:55:18 2010 +0200 +++ b/spi.debugger.ui/test/unit/src/org/netbeans/api/debugger/ProvidersAnnotationTest.java Tue Sep 07 15:41:25 2010 +0200 @@ -58,6 +58,7 @@ import org.netbeans.api.debugger.providers.TestLazyActionsManagerListenerAnnotated; import org.netbeans.api.debugger.providers.TestLazyDebuggerManagerListenerAnnotated; import org.netbeans.api.debugger.providers.TestMIMETypeSensitiveActionProvider; +import org.netbeans.api.debugger.providers.TestMultiModelRegistrations; import org.netbeans.api.debugger.providers.TestThreeModels; import org.netbeans.modules.debugger.ui.models.ColumnModels; import org.netbeans.spi.debugger.ActionsProvider; @@ -206,6 +207,47 @@ } } + public void testMultiModelRegistrations() throws Exception { + Lookup.MetaInf l = new Lookup.MetaInf("unittest"); + Object instance; + { + List list = l.lookup("annotated1", TreeModel.class); + assertEquals("Wrong looked up object", 1, list.size()); + instance = ((TestMultiModelRegistrations) list.get(0)).INSTANCES.iterator().next(); + assertEquals("One provider instance should be created!", 1, TestMultiModelRegistrations.INSTANCES.size()); + List list2 = l.lookup("annotated1", NodeModel.class); + assertEquals("Wrong looked up object", 0, list2.size()); + List list3 = l.lookup("annotated1", TableModel.class); + assertEquals("Wrong looked up object", 0, list3.size()); + } + + { + List list = l.lookup("annotated2", TreeModel.class); + assertEquals("Wrong looked up object", 0, list.size()); + List list2 = l.lookup("annotated2", NodeModel.class); + assertEquals("Wrong looked up object", 1, list2.size()); + List list3 = l.lookup("annotated2", TableModel.class); + assertEquals("Wrong looked up object", 1, list3.size()); + list2.get(0); + assertEquals("One provider instance should be created!", 1, TestMultiModelRegistrations.INSTANCES.size()); + list3.get(0); + assertEquals("One provider instance should be created!", 1, TestMultiModelRegistrations.INSTANCES.size()); + } + + { + List list = l.lookup("annotated3", TreeModel.class); + assertEquals("Wrong looked up object", 0, list.size()); + List list2 = l.lookup("annotated3", NodeModel.class); + assertEquals("Wrong looked up object", 1, list2.size()); + List list3 = l.lookup("annotated3", TableModel.class); + assertEquals("Wrong looked up object", 1, list3.size()); + list2.get(0); + assertEquals("One provider instance should be created!", 1, TestMultiModelRegistrations.INSTANCES.size()); + assertEquals("Wrong instance", instance, list3.get(0)); + assertEquals("One provider instance should be created!", 1, TestMultiModelRegistrations.INSTANCES.size()); + } + } + public void testColumnProviders() throws Exception { Lookup.MetaInf l = new Lookup.MetaInf("unittest/annotated"); diff -r 04d674b90c8a spi.debugger.ui/test/unit/src/org/netbeans/api/debugger/providers/TestMultiModelRegistrations.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spi.debugger.ui/test/unit/src/org/netbeans/api/debugger/providers/TestMultiModelRegistrations.java Tue Sep 07 15:41:25 2010 +0200 @@ -0,0 +1,120 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2009 Sun Microsystems, Inc. + */ + +package org.netbeans.api.debugger.providers; + +import java.util.HashSet; +import java.util.Set; +import org.netbeans.spi.debugger.DebuggerServiceRegistration; +import org.netbeans.spi.debugger.DebuggerServiceRegistrations; +import org.netbeans.spi.viewmodel.ModelListener; +import org.netbeans.spi.viewmodel.NodeModel; +import org.netbeans.spi.viewmodel.TableModel; +import org.netbeans.spi.viewmodel.TreeModel; +import org.netbeans.spi.viewmodel.UnknownTypeException; + +/** + * + * @author Martin Entlicher + */ +@DebuggerServiceRegistrations({ + @DebuggerServiceRegistration(path="unittest/annotated1", types=TreeModel.class), + @DebuggerServiceRegistration(path="unittest/annotated2", types={NodeModel.class, TableModel.class}), + @DebuggerServiceRegistration(path="unittest/annotated3", types={NodeModel.class, TableModel.class}) +}) +public class TestMultiModelRegistrations implements TreeModel, NodeModel, TableModel { + + public static Set INSTANCES = new HashSet(); + + public TestMultiModelRegistrations() { + INSTANCES.add(this); + } + + public Object getRoot() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public Object[] getChildren(Object parent, int from, int to) throws UnknownTypeException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public boolean isLeaf(Object node) throws UnknownTypeException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public int getChildrenCount(Object node) throws UnknownTypeException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void addModelListener(ModelListener l) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void removeModelListener(ModelListener l) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public String getDisplayName(Object node) throws UnknownTypeException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public String getIconBase(Object node) throws UnknownTypeException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public String getShortDescription(Object node) throws UnknownTypeException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public Object getValueAt(Object node, String columnID) throws UnknownTypeException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public boolean isReadOnly(Object node, String columnID) throws UnknownTypeException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void setValueAt(Object node, String columnID, Object value) throws UnknownTypeException { + throw new UnsupportedOperationException("Not supported yet."); + } + +}