en = NamedServiceProcessor.class.getClassLoader().getResources(PATH);
+ while (en.hasMoreElements()) {
+ URL url = en.nextElement();
+ InputStream is = url.openStream();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); // NOI18N
+
+ // XXX consider using ServiceLoaderLine instead
+ while (true) {
+ String line = reader.readLine();
+
+ if (line == null) {
+ break;
+ }
+ line = line.trim();
+ if (line.startsWith("#")) { // NOI18N
+ continue;
+ }
+ if (canonicalName) {
+ line = line.replace('$', '.');
+ }
+ found.add(line);
+ }
+ }
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ private static String substitute(String path, Matcher m, String obj) {
+ return path.substring(0, m.start(0)) + obj + path.substring(m.end(0));
+ }
+}
diff -r 9e26a4666530 openide.util.lookup/src/org/openide/util/lookup/NamedServiceDefinition.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/openide.util.lookup/src/org/openide/util/lookup/NamedServiceDefinition.java Tue Mar 20 10:58:38 2012 +0100
@@ -0,0 +1,95 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 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 2012 Sun Microsystems, Inc.
+ */
+package org.openide.util.lookup;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Annotation to simplify creation and add robustness to usage of
+ * various named service registration annotations. For example
+ * the {@code @}
+ * URLStreamHandlerRegistration annotation uses the {@link NamedServiceDefinition}
+ * as:
+ * {@code @NamedServiceDefinition(path="URLStreamHandler/@protocol()", serviceType=URLStreamHandler.class)}
+ *
+ * The above instructs the annotation processor that handles {@link NamedServiceDefinition}s
+ * to verify the annotated type is subclass of URLStreamHandler
and
+ * if so, register it into URLStreamHandler/@protocol
where the
+ * value of @protocol()
is replaced by the value of annotation's
+ *
+ * protocol attribute. The registration can later be found by using
+ * {@link Lookups#forPath(java.lang.String) Lookups.forPath("URLStreamHandler/ftp")}
+ * (in case the protocol was ftp).
+ *
+ * @author Jaroslav Tulach
+ * @since 8.14
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+public @interface NamedServiceDefinition {
+ /** Type, or array of types that the registered type
+ * has to implement.
+ */
+ public Class>[] serviceType();
+ /** Path to register the annotation to, so it can later be found by
+ * using {@link Lookups#forPath(java.lang.String) Lookups.forPath(theSamePath)}.
+ * The path may reference attributes of the annotated annotation by prefixing
+ * them with {@code @}. To reuse attribute named location
one
+ * can for example use "how/to/get/to/@location/please"
+ * These attributes must be of type String
+ * or array of String
s.
+ */
+ public String path();
+ /** Name of attribute that specifies position. By default the system tries
+ * to find int position()
attribute in the defined annotation
+ * and use it to specify the order of registrations. In case a different
+ * attribute should be used to specify position, can be provide its
+ * name by specifying non-default here. Should the position be ignored,
+ * specify empty string.
+ *
+ * @param name of attribute in the annotated annotation to use for defining
+ * position of the registration. The attribute should return int value.
+ */
+ public String position() default "\u0000";
+}
diff -r 9e26a4666530 openide.util.lookup/src/org/openide/util/lookup/implspi/AbstractServiceProviderProcessor.java
--- a/openide.util.lookup/src/org/openide/util/lookup/implspi/AbstractServiceProviderProcessor.java Mon Mar 19 16:35:39 2012 +0100
+++ b/openide.util.lookup/src/org/openide/util/lookup/implspi/AbstractServiceProviderProcessor.java Tue Mar 20 10:58:38 2012 +0100
@@ -97,9 +97,13 @@
// OK subclass
return;
}
+ if (getClass().getName().equals("org.netbeans.modules.openide.util.NamedServiceProcessor")) { // NOI18N
+ // OK subclass
+ return;
+ }
throw new IllegalStateException();
}
-
+
public @Override final boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (roundEnv.errorRaised()) {
return false;
@@ -135,13 +139,24 @@
* @param supersedes possibly empty list of implementation to supersede
* @since 8.8
*/
- protected final void register(Element el, Class extends Annotation> annotation,
- TypeMirror type, String path, int position, String[] supersedes) {
+ protected final void register(
+ Element el, Class extends Annotation> annotation,
+ TypeMirror type, String path, int position, String... supersedes
+ ) {
if (el.getKind() != ElementKind.CLASS) {
processingEnv.getMessager().printMessage(Kind.ERROR, annotation.getName() + " is not applicable to a " + el.getKind(), el);
return;
}
TypeElement clazz = (TypeElement) el;
+ String impl = processingEnv.getElementUtils().getBinaryName(clazz).toString();
+ String xface = processingEnv.getElementUtils().getBinaryName((TypeElement) processingEnv.getTypeUtils().asElement(type)).toString();
+ if (!processingEnv.getTypeUtils().isAssignable(clazz.asType(), type)) {
+ AnnotationMirror ann = findAnnotationMirror(clazz, annotation);
+ processingEnv.getMessager().printMessage(Kind.ERROR, impl + " is not assignable to " + xface,
+ clazz, ann, findAnnotationValue(ann, "service"));
+ return;
+ }
+ String rsrc = (path.length() > 0 ? "META-INF/namedservices/" + path + "/" : "META-INF/services/") + xface;
Boolean verify = verifiedClasses.get(clazz);
if (verify == null) {
verify = verifyServiceProviderSignature(clazz, annotation);
@@ -150,19 +165,22 @@
if (!verify) {
return;
}
+ registerImpl(clazz, impl, rsrc, position, supersedes);
+ }
+
+ protected final void register(Element el, String path) {
+ TypeElement clazz = (TypeElement)el;
String impl = processingEnv.getElementUtils().getBinaryName(clazz).toString();
- String xface = processingEnv.getElementUtils().getBinaryName((TypeElement) processingEnv.getTypeUtils().asElement(type)).toString();
- if (!processingEnv.getTypeUtils().isAssignable(clazz.asType(), type)) {
- AnnotationMirror ann = findAnnotationMirror(clazz, annotation);
- processingEnv.getMessager().printMessage(Kind.ERROR, impl + " is not assignable to " + xface,
- clazz, ann, findAnnotationValue(ann, "service"));
- return;
- }
+ registerImpl(clazz, impl, path, Integer.MAX_VALUE);
+ }
+
+ private void registerImpl(
+ TypeElement clazz, String impl, String rsrc, int position, String... supersedes
+ ) {
/*
processingEnv.getMessager().printMessage(Kind.NOTE,
impl + " to be registered as a " + xface + (path.length() > 0 ? " under " + path : ""));
*/
- String rsrc = (path.length() > 0 ? "META-INF/namedservices/" + path + "/" : "META-INF/services/") + xface;
Filer filer = processingEnv.getFiler();
{
Map> originatingElements = originatingElementsByProcessor.get(filer);
diff -r 9e26a4666530 openide.util.lookup/test/unit/src/org/openide/util/lookup/NamedServiceDefinitionTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/NamedServiceDefinitionTest.java Tue Mar 20 10:58:38 2012 +0100
@@ -0,0 +1,132 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 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 2012 Sun Microsystems, Inc.
+ */
+package org.openide.util.lookup;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.concurrent.Callable;
+import org.netbeans.junit.NbTestCase;
+import org.openide.util.Lookup;
+import org.openide.util.test.AnnotationProcessorTestUtils;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class NamedServiceDefinitionTest extends NbTestCase {
+
+ public NamedServiceDefinitionTest(String n) {
+ super(n);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ clearWorkDir();
+ }
+
+ public void testNamedDefinition() throws Exception {
+ System.setProperty("executed", "false");
+ String content = "import org.openide.util.lookup.NamedServiceDefinitionTest.RunTestReg;\n"
+ + "@RunTestReg(position=10,when=\"now\")\n"
+ + "public class Test implements Runnable {\n"
+ + " public void run() { System.setProperty(\"executed\", \"true\"); }\n"
+ + "}\n";
+ AnnotationProcessorTestUtils.makeSource(getWorkDir(), "x.Test", content);
+ assertTrue("Compiles OK",
+ AnnotationProcessorTestUtils.runJavac(getWorkDir(), null, getWorkDir(), null, System.err)
+ );
+
+ URLClassLoader l = new URLClassLoader(new URL[] { getWorkDir().toURI().toURL() }, NamedServiceDefinitionTest.class.getClassLoader());
+ Lookup lkp = Lookups.metaInfServices(l, "META-INF/namedservices/runtest/now/below/");
+ for (Runnable r : lkp.lookupAll(Runnable.class)) {
+ r.run();
+ }
+ assertEquals("Our runnable was executed", "true", System.getProperty("executed"));
+ }
+
+ public void testNamedDefinitionWithArray() throws Exception {
+ System.setProperty("executed", "false");
+ String content = "import org.openide.util.lookup.NamedServiceDefinitionTest.RunTestArray;\n"
+ + "@RunTestArray(position=10,array={\"now\", \"then\" })\n"
+ + "public class Test implements Runnable {\n"
+ + " public void run() { System.setProperty(\"executed\", \"true\"); }\n"
+ + "}\n";
+ AnnotationProcessorTestUtils.makeSource(getWorkDir(), "x.Test", content);
+ assertTrue("Compiles OK",
+ AnnotationProcessorTestUtils.runJavac(getWorkDir(), null, getWorkDir(), null, System.err)
+ );
+
+ URLClassLoader l = new URLClassLoader(new URL[] { getWorkDir().toURI().toURL() }, NamedServiceDefinitionTest.class.getClassLoader());
+ Lookup lkp = Lookups.metaInfServices(l, "META-INF/namedservices/runtest/now/");
+ for (Runnable r : lkp.lookupAll(Runnable.class)) {
+ r.run();
+ }
+ assertEquals("Our runnable was executed", "true", System.getProperty("executed"));
+ System.setProperty("executed", "false");
+ Lookup lkp2 = Lookups.metaInfServices(l, "META-INF/namedservices/runtest/then/");
+ for (Runnable r : lkp2.lookupAll(Runnable.class)) {
+ r.run();
+ }
+ assertEquals("Our runnable was executed again", "true", System.getProperty("executed"));
+ }
+
+ @NamedServiceDefinition(
+ path="runtest/@when()/below",
+ serviceType={ Runnable.class, Callable.class }
+ )
+ @Retention(RetentionPolicy.SOURCE)
+ public static @interface RunTestReg {
+ public int position();
+ public String when();
+ }
+ @NamedServiceDefinition(
+ path="runtest/@array()",
+ serviceType={ Runnable.class, Callable.class }
+ )
+ @Retention(RetentionPolicy.SOURCE)
+ public static @interface RunTestArray {
+ public int position();
+ public String[] array();
+ }
+}
diff -r 9e26a4666530 openide.util/nbproject/project.xml
--- a/openide.util/nbproject/project.xml Mon Mar 19 16:35:39 2012 +0100
+++ b/openide.util/nbproject/project.xml Tue Mar 20 10:58:38 2012 +0100
@@ -54,7 +54,7 @@
- 8.8
+ 8.14
diff -r 9e26a4666530 openide.util/src/org/netbeans/modules/openide/util/ProxyURLStreamHandlerFactory.java
--- a/openide.util/src/org/netbeans/modules/openide/util/ProxyURLStreamHandlerFactory.java Mon Mar 19 16:35:39 2012 +0100
+++ b/openide.util/src/org/netbeans/modules/openide/util/ProxyURLStreamHandlerFactory.java Tue Mar 20 10:58:38 2012 +0100
@@ -62,7 +62,6 @@
*/
@ServiceProvider(service=URLStreamHandlerFactory.class)
public final class ProxyURLStreamHandlerFactory implements URLStreamHandlerFactory {
-
/** prevents GC only */
private final Map> results = new HashMap>();
private final Map handlers = new HashMap();
@@ -74,7 +73,7 @@
return null;
}
if (!results.containsKey(protocol)) {
- final Lookup.Result result = Lookups.forPath(URLStreamHandlerRegistrationProcessor.REGISTRATION_PREFIX + protocol).lookupResult(URLStreamHandler.class);
+ final Lookup.Result result = Lookups.forPath("URLStreamHandler/" + protocol).lookupResult(URLStreamHandler.class);
LookupListener listener = new LookupListener() {
public @Override void resultChanged(LookupEvent ev) {
synchronized (ProxyURLStreamHandlerFactory.this) {
diff -r 9e26a4666530 openide.util/src/org/netbeans/modules/openide/util/URLStreamHandlerRegistrationProcessor.java
--- a/openide.util/src/org/netbeans/modules/openide/util/URLStreamHandlerRegistrationProcessor.java Mon Mar 19 16:35:39 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * 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.modules.openide.util;
-
-import java.net.URLStreamHandler;
-import java.util.Collections;
-import java.util.Set;
-import javax.annotation.processing.Processor;
-import javax.annotation.processing.RoundEnvironment;
-import javax.annotation.processing.SupportedSourceVersion;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
-import org.openide.util.URLStreamHandlerRegistration;
-import org.openide.util.lookup.ServiceProvider;
-import org.openide.util.lookup.implspi.AbstractServiceProviderProcessor;
-
-@ServiceProvider(service=Processor.class)
-@SupportedSourceVersion(SourceVersion.RELEASE_6)
-public class URLStreamHandlerRegistrationProcessor extends AbstractServiceProviderProcessor {
-
- public @Override Set getSupportedAnnotationTypes() {
- return Collections.singleton(URLStreamHandlerRegistration.class.getCanonicalName());
- }
-
- public static final String REGISTRATION_PREFIX = "URLStreamHandler/"; // NOI18N
-
- protected @Override boolean handleProcess(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
- for (Element el : roundEnv.getElementsAnnotatedWith(URLStreamHandlerRegistration.class)) {
- URLStreamHandlerRegistration r = el.getAnnotation(URLStreamHandlerRegistration.class);
- TypeMirror type = processingEnv.getTypeUtils().getDeclaredType(
- processingEnv.getElementUtils().getTypeElement(URLStreamHandler.class.getName()));
- for (String protocol : r.protocol()) {
- register(el, URLStreamHandlerRegistration.class, type,
- REGISTRATION_PREFIX + protocol, r.position(), new String[0]);
- }
- }
- return true;
- }
-
-}
diff -r 9e26a4666530 openide.util/src/org/openide/util/URLStreamHandlerRegistration.java
--- a/openide.util/src/org/openide/util/URLStreamHandlerRegistration.java Mon Mar 19 16:35:39 2012 +0100
+++ b/openide.util/src/org/openide/util/URLStreamHandlerRegistration.java Tue Mar 20 10:58:38 2012 +0100
@@ -49,6 +49,7 @@
import java.net.URL;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
+import org.openide.util.lookup.NamedServiceDefinition;
/**
* Replacement for {@link URLStreamHandlerFactory} within the NetBeans platform.
@@ -62,6 +63,7 @@
* from a unit test or otherwise without the module system active.
* @since org.openide.util 7.31
*/
+@NamedServiceDefinition(path="URLStreamHandler/@protocol()", serviceType=URLStreamHandler.class)
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface URLStreamHandlerRegistration {