This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 150447
Collapse All | Expand All

(-)a/openide.modules/nbproject/project.properties (+1 lines)
Lines 39-44 Link Here
39
39
40
javac.compilerargs=-Xlint:unchecked
40
javac.compilerargs=-Xlint:unchecked
41
javac.source=1.5
41
javac.source=1.5
42
cp.extra=${nb_all}/libs.javacapi/external/javac-api-nb-7.0-b07.jar
42
module.jar.dir=lib
43
module.jar.dir=lib
43
javadoc.main.page=org/openide/modules/doc-files/api.html
44
javadoc.main.page=org/openide/modules/doc-files/api.html
44
javadoc.arch=${basedir}/arch.xml
45
javadoc.arch=${basedir}/arch.xml
(-)a/openide.modules/src/META-INF/services/javax.annotation.processing.Processor (+1 lines)
Line 0 Link Here
1
org.netbeans.modules.openide.modules.ServiceProcessor
(-)a/openide.modules/src/org/netbeans/modules/openide/modules/ServiceProcessor.java (+211 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2008 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.modules.openide.modules;
41
42
import java.io.BufferedReader;
43
import java.io.FileNotFoundException;
44
import java.io.IOException;
45
import java.io.InputStream;
46
import java.io.InputStreamReader;
47
import java.io.OutputStream;
48
import java.io.OutputStreamWriter;
49
import java.io.PrintWriter;
50
import java.util.ArrayList;
51
import java.util.HashMap;
52
import java.util.List;
53
import java.util.Map;
54
import java.util.Set;
55
import javax.annotation.processing.AbstractProcessor;
56
import javax.annotation.processing.RoundEnvironment;
57
import javax.annotation.processing.SupportedAnnotationTypes;
58
import javax.annotation.processing.SupportedSourceVersion;
59
import javax.lang.model.SourceVersion;
60
import javax.lang.model.element.AnnotationMirror;
61
import javax.lang.model.element.AnnotationValue;
62
import javax.lang.model.element.Element;
63
import javax.lang.model.element.ExecutableElement;
64
import javax.lang.model.element.Modifier;
65
import javax.lang.model.element.TypeElement;
66
import javax.lang.model.type.TypeMirror;
67
import javax.lang.model.util.ElementFilter;
68
import javax.tools.Diagnostic.Kind;
69
import javax.tools.FileObject;
70
import javax.tools.StandardLocation;
71
import org.openide.modules.Service;
72
73
@SupportedSourceVersion(SourceVersion.RELEASE_6)
74
@SupportedAnnotationTypes("org.openide.modules.Service")
75
public class ServiceProcessor extends AbstractProcessor {
76
77
    /** public for ServiceLoader */
78
    public ServiceProcessor() {}
79
80
    @Override
81
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
82
        if (roundEnv.processingOver()) {
83
            return false;
84
        }
85
        Map<String,List<String>> outputFiles = new HashMap<String,List<String>>();
86
        Map<String,List<Element>> originatingElements = new HashMap<String,List<Element>>();
87
        for (Element el : roundEnv.getElementsAnnotatedWith(Service.class)) {
88
            TypeElement clazz = (TypeElement) el;
89
            if (!clazz.getModifiers().contains(Modifier.PUBLIC)) {
90
                processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must be public");
91
                continue;
92
            }
93
            if (clazz.getModifiers().contains(Modifier.ABSTRACT)) {
94
                processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must not be abstract");
95
                continue;
96
            }
97
            {
98
                boolean hasDefaultCtor = false;
99
                for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) {
100
                    if (constructor.getModifiers().contains(Modifier.PUBLIC) && constructor.getParameters().isEmpty()) {
101
                        hasDefaultCtor = true;
102
                        break;
103
                    }
104
                }
105
                if (!hasDefaultCtor) {
106
                    processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must have a public no-argument constructor");
107
                    continue;
108
                }
109
            }
110
            for (AnnotationMirror ann : clazz.getAnnotationMirrors()) {
111
                if (ann.getAnnotationType().asElement().equals(processingEnv.getElementUtils().getTypeElement(Service.class.getName()))) {
112
                    for (Map.Entry<? extends ExecutableElement,? extends AnnotationValue> entry : ann.getElementValues().entrySet()) {
113
                        if (entry.getKey().getSimpleName().contentEquals("value")) {
114
                            for (Object val : (List) entry.getValue().getValue()) {
115
                                register(clazz, (TypeMirror) ((AnnotationValue) val).getValue(), outputFiles, originatingElements);
116
                            }
117
                        }
118
                    }
119
                }
120
            }
121
        }
122
        for (Map.Entry<String,List<String>> entry : outputFiles.entrySet()) {
123
            try {
124
                FileObject out = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", entry.getKey(),
125
                        originatingElements.get(entry.getKey()).toArray(new Element[0]));
126
                OutputStream os = out.openOutputStream();
127
                try {
128
                    PrintWriter w = new PrintWriter(new OutputStreamWriter(os, "UTF-8"));
129
                    for (String line : entry.getValue()) {
130
                        w.println(line);
131
                    }
132
                    w.flush();
133
                    w.close();
134
                } finally {
135
                    os.close();
136
                }
137
            } catch (IOException x) {
138
                processingEnv.getMessager().printMessage(Kind.ERROR, "Failed to write to " + entry.getKey() + ": " + x.toString());
139
            }
140
        }
141
        return true;
142
    }
143
144
    private void register(TypeElement clazz, TypeMirror type, Map<String,List<String>> outputFiles, Map<String,List<Element>> originatingElements) {
145
        String impl = processingEnv.getElementUtils().getBinaryName(clazz).toString();
146
        String xface = processingEnv.getElementUtils().getBinaryName((TypeElement) processingEnv.getTypeUtils().asElement(type)).toString();
147
        if (!processingEnv.getTypeUtils().isAssignable(clazz.asType(), type)) {
148
            processingEnv.getMessager().printMessage(Kind.ERROR, impl + " is not assignable to " + xface);
149
            return;
150
        }
151
        processingEnv.getMessager().printMessage(Kind.NOTE, impl + " to be registered as a " + xface);
152
        Service svc = clazz.getAnnotation(Service.class);
153
        String rsrc = (svc.path().length() > 0 ? "META-INF/namedservices/" + svc.path() + "/" : "META-INF/services/") + xface;
154
        {
155
            List<Element> origEls = originatingElements.get(rsrc);
156
            if (origEls == null) {
157
                origEls = new ArrayList<Element>();
158
                originatingElements.put(rsrc, origEls);
159
            }
160
            origEls.add(clazz);
161
        }
162
        List<String> lines = outputFiles.get(rsrc);
163
        if (lines == null) {
164
            lines = new ArrayList<String>();
165
            try {
166
                try {
167
                    FileObject in = processingEnv.getFiler().getResource(StandardLocation.SOURCE_PATH, "", rsrc);
168
                    in.openInputStream().close();
169
                    processingEnv.getMessager().printMessage(Kind.ERROR, "Cannot generate " + rsrc + " because it already exists in sources: " + in.toUri());
170
                    return;
171
                } catch (FileNotFoundException x) {
172
                    // Good.
173
                }
174
                try {
175
                    FileObject in = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", rsrc);
176
                    InputStream is = in.openInputStream();
177
                    try {
178
                        BufferedReader r = new BufferedReader(new InputStreamReader(is, "UTF-8"));
179
                        String line;
180
                        while ((line = r.readLine()) != null) {
181
                            lines.add(line);
182
                        }
183
                    } finally {
184
                        is.close();
185
                    }
186
                } catch (FileNotFoundException x) {
187
                    // OK, created for the first time
188
                }
189
            } catch (IOException x) {
190
                processingEnv.getMessager().printMessage(Kind.ERROR, x.toString());
191
                return;
192
            }
193
            outputFiles.put(rsrc, lines);
194
        }
195
        int idx = lines.indexOf(impl);
196
        if (idx != -1) {
197
            lines.remove(idx);
198
            while (lines.size() > idx && lines.get(idx).matches("#position=.+|#-.+")) {
199
                lines.remove(idx);
200
            }
201
        }
202
        lines.add(impl);
203
        if (svc.position() != Integer.MAX_VALUE) {
204
            lines.add("#position=" + svc.position());
205
        }
206
        for (String exclude : svc.supersedes()) {
207
            lines.add("#-" + exclude);
208
        }
209
    }
210
211
}
(-)a/openide.modules/src/org/openide/modules/Service.java (+102 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2008 Sun Microsystems, Inc.
38
 */
39
40
package org.openide.modules;
41
42
import java.lang.annotation.ElementType;
43
import java.lang.annotation.Retention;
44
import java.lang.annotation.RetentionPolicy;
45
import java.lang.annotation.Target;
46
import org.openide.util.Lookup;
47
import org.openide.util.lookup.Lookups;
48
49
/**
50
 * Declarative registration of a singleton service.
51
 * By marking an implementation class with this annotation,
52
 * you automatically register that implementation, normally in {@link Lookup#getDefault}.
53
 * The class must be public and have a public no-argument constructor.
54
 * <p>Example of usage:
55
 * <pre>
56
 * package my.module;
57
 * import org.netbeans.spi.whatever.Thing;
58
 * &#64;Service(Thing.class)
59
 * public class MyThing implements Thing {...}
60
 * </pre>
61
 * <p>would result in a resource file <code>META-INF/services/org.netbeans.spi.whatever.Thing</code>
62
 * containing the single line of text: <code>my.module.MyThing</code>
63
 * @see Lookups#metaInfServices(ClassLoader)
64
 * @since XXX #150447
65
 */
66
@Retention(RetentionPolicy.SOURCE)
67
@Target(ElementType.TYPE)
68
public @interface Service {
69
70
    /**
71
     * The interface to register this implementation under.
72
     * You must supply at least one interface (or abstract class); rarely you might want more than one.
73
     * It is an error if the implementation class is not in fact assignable to the interface.
74
     * <p>Requests to look up the specified interface should result in this implementation.
75
     * Requests for any other types may or may not result in this implementation even if the
76
     * implementation is assignable to those types.
77
     */
78
    Class[] value();
79
80
    /**
81
     * An optional position in which to register this service relative to others.
82
     * Lower-numbered services are returned in the lookup result first.
83
     * Services with no specified position are returned last.
84
     */
85
    int position() default Integer.MAX_VALUE;
86
87
    /**
88
     * An optional list of implementations (given as fully-qualified class names) which this implementation supersedes.
89
     * If specified, those implementations will not be loaded even if they were registered.
90
     * Useful on occasion to cancel a generic implementation and replace it with a more advanced one.
91
     */
92
    String[] supersedes() default {};
93
94
    /**
95
     * An optional path to register this implementation in.
96
     * For example, <code>Projects/sometype/Nodes</code> could be used.
97
     * This style of registration would be recognized by {@link Lookups#forPath}
98
     * rather than {@link Lookup#getDefault}.
99
     */
100
    String path() default "";
101
102
}

Return to bug 150447