Moving also ServiceProviderProcessor to openide.util.lookup separate-lookup-170056
authorJaroslav Tulach <jtulach@netbeans.org>
Sat, 31 Oct 2009 16:33:02 +0100
branchseparate-lookup-170056
changeset 8436277b30a163f
parent 842 2e54b07fbdbb
child 844 e7e81aa73f1c
Moving also ServiceProviderProcessor to openide.util.lookup
openide.util.lookup/src/META-INF/services/javax.annotation.processing.Processor
openide.util.lookup/src/org/netbeans/modules/openide/util/ServiceProviderProcessor.java
openide.util.lookup/test/unit/src/org/netbeans/modules/openide/util/ServiceProviderProcessorTest.java
openide.util.lookup/test/unit/src/org/openide/util/lookup/MetaInfServicesLookupTest.java
openide.util.lookup/test/unit/src/org/openide/util/test/AnnotationProcessorTestUtils.java
openide.util/src/META-INF/services/javax.annotation.processing.Processor
openide.util/src/org/netbeans/modules/openide/util/ServiceProviderProcessor.java
openide.util/test/unit/src/org/netbeans/modules/openide/util/ServiceProviderProcessorTest.java
openide.util/test/unit/src/org/openide/util/test/AnnotationProcessorTestUtils.java
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/openide.util.lookup/src/META-INF/services/javax.annotation.processing.Processor	Sat Oct 31 16:33:02 2009 +0100
     1.3 @@ -0,0 +1,1 @@
     1.4 +org.netbeans.modules.openide.util.ServiceProviderProcessor
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/openide.util.lookup/src/org/netbeans/modules/openide/util/ServiceProviderProcessor.java	Sat Oct 31 16:33:02 2009 +0100
     2.3 @@ -0,0 +1,348 @@
     2.4 +/*
     2.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     2.6 + *
     2.7 + * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
     2.8 + *
     2.9 + * The contents of this file are subject to the terms of either the GNU
    2.10 + * General Public License Version 2 only ("GPL") or the Common
    2.11 + * Development and Distribution License("CDDL") (collectively, the
    2.12 + * "License"). You may not use this file except in compliance with the
    2.13 + * License. You can obtain a copy of the License at
    2.14 + * http://www.netbeans.org/cddl-gplv2.html
    2.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    2.16 + * specific language governing permissions and limitations under the
    2.17 + * License.  When distributing the software, include this License Header
    2.18 + * Notice in each file and include the License file at
    2.19 + * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
    2.20 + * particular file as subject to the "Classpath" exception as provided
    2.21 + * by Sun in the GPL Version 2 section of the License file that
    2.22 + * accompanied this code. If applicable, add the following below the
    2.23 + * License Header, with the fields enclosed by brackets [] replaced by
    2.24 + * your own identifying information:
    2.25 + * "Portions Copyrighted [year] [name of copyright owner]"
    2.26 + *
    2.27 + * If you wish your version of this file to be governed by only the CDDL
    2.28 + * or only the GPL Version 2, indicate your decision by adding
    2.29 + * "[Contributor] elects to include this software in this distribution
    2.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    2.31 + * single choice of license, a recipient has the option to distribute
    2.32 + * your version of this file under either the CDDL, the GPL Version 2 or
    2.33 + * to extend the choice of license to its licensees as provided above.
    2.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    2.35 + * Version 2 license, then the option applies only if the new code is
    2.36 + * made subject to such option by the copyright holder.
    2.37 + *
    2.38 + * Contributor(s):
    2.39 + *
    2.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
    2.41 + */
    2.42 +
    2.43 +package org.netbeans.modules.openide.util;
    2.44 +
    2.45 +import java.io.BufferedReader;
    2.46 +import java.io.FileNotFoundException;
    2.47 +import java.io.IOException;
    2.48 +import java.io.InputStream;
    2.49 +import java.io.InputStreamReader;
    2.50 +import java.io.OutputStream;
    2.51 +import java.io.OutputStreamWriter;
    2.52 +import java.io.PrintWriter;
    2.53 +import java.lang.annotation.Annotation;
    2.54 +import java.util.ArrayList;
    2.55 +import java.util.Collection;
    2.56 +import java.util.Collections;
    2.57 +import java.util.HashMap;
    2.58 +import java.util.LinkedList;
    2.59 +import java.util.List;
    2.60 +import java.util.Map;
    2.61 +import java.util.Set;
    2.62 +import javax.annotation.processing.AbstractProcessor;
    2.63 +import javax.annotation.processing.Completion;
    2.64 +import javax.annotation.processing.RoundEnvironment;
    2.65 +import javax.annotation.processing.SupportedAnnotationTypes;
    2.66 +import javax.annotation.processing.SupportedSourceVersion;
    2.67 +import javax.lang.model.SourceVersion;
    2.68 +import javax.lang.model.element.AnnotationMirror;
    2.69 +import javax.lang.model.element.AnnotationValue;
    2.70 +import javax.lang.model.element.Element;
    2.71 +import javax.lang.model.element.ExecutableElement;
    2.72 +import javax.lang.model.element.Modifier;
    2.73 +import javax.lang.model.element.TypeElement;
    2.74 +import javax.lang.model.type.MirroredTypeException;
    2.75 +import javax.lang.model.type.TypeKind;
    2.76 +import javax.lang.model.type.TypeMirror;
    2.77 +import javax.lang.model.util.ElementFilter;
    2.78 +import javax.tools.Diagnostic.Kind;
    2.79 +import javax.tools.FileObject;
    2.80 +import javax.tools.StandardLocation;
    2.81 +import org.openide.util.lookup.ServiceProvider;
    2.82 +import org.openide.util.lookup.ServiceProviders;
    2.83 +
    2.84 +@SupportedSourceVersion(SourceVersion.RELEASE_6)
    2.85 +@SupportedAnnotationTypes({"org.openide.util.lookup.ServiceProvider", "org.openide.util.lookup.ServiceProviders"})
    2.86 +public class ServiceProviderProcessor extends AbstractProcessor {
    2.87 +
    2.88 +    /** public for ServiceLoader */
    2.89 +    public ServiceProviderProcessor() {}
    2.90 +
    2.91 +    private final Map<String, List<String>> outputFiles = new HashMap<String,List<String>>();
    2.92 +    private final Map<String, List<Element>> originatingElements = new HashMap<String,List<Element>>();
    2.93 +
    2.94 +    @Override
    2.95 +    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    2.96 +        if (roundEnv.errorRaised()) {
    2.97 +            return false;
    2.98 +        }
    2.99 +        if (roundEnv.processingOver()) {
   2.100 +            writeServices();
   2.101 +            return false;
   2.102 +        } else {
   2.103 +            for (Element el : roundEnv.getElementsAnnotatedWith(ServiceProvider.class)) {
   2.104 +                TypeElement clazz = (TypeElement) el;
   2.105 +                if (!verifyServiceProviderSignature(clazz)) {
   2.106 +                    continue;
   2.107 +                }
   2.108 +                ServiceProvider sp = clazz.getAnnotation(ServiceProvider.class);
   2.109 +                register(clazz, sp);
   2.110 +            }
   2.111 +            for (Element el : roundEnv.getElementsAnnotatedWith(ServiceProviders.class)) {
   2.112 +                TypeElement clazz = (TypeElement) el;
   2.113 +                if (!verifyServiceProviderSignature(clazz)) {
   2.114 +                    continue;
   2.115 +                }
   2.116 +                ServiceProviders spp = clazz.getAnnotation(ServiceProviders.class);
   2.117 +                for (ServiceProvider sp : spp.value()) {
   2.118 +                    register(clazz, sp);
   2.119 +                }
   2.120 +            }
   2.121 +            return true;
   2.122 +        }
   2.123 +    }
   2.124 +
   2.125 +    private void register(TypeElement clazz, ServiceProvider svc) {
   2.126 +        TypeMirror type;
   2.127 +        try {
   2.128 +            svc.service();
   2.129 +            assert false;
   2.130 +            return;
   2.131 +        } catch (MirroredTypeException e) {
   2.132 +            type = e.getTypeMirror();
   2.133 +        }
   2.134 +        String impl = processingEnv.getElementUtils().getBinaryName(clazz).toString();
   2.135 +        String xface = processingEnv.getElementUtils().getBinaryName((TypeElement) processingEnv.getTypeUtils().asElement(type)).toString();
   2.136 +        if (!processingEnv.getTypeUtils().isAssignable(clazz.asType(), type)) {
   2.137 +            AnnotationMirror ann = findAnnotationMirror(clazz, ServiceProvider.class);
   2.138 +            processingEnv.getMessager().printMessage(Kind.ERROR, impl + " is not assignable to " + xface,
   2.139 +                    clazz, ann, findAnnotationValue(ann, "service"));
   2.140 +            return;
   2.141 +        }
   2.142 +        processingEnv.getMessager().printMessage(Kind.NOTE, impl + " to be registered as a " + xface);
   2.143 +        String rsrc = (svc.path().length() > 0 ? "META-INF/namedservices/" + svc.path() + "/" : "META-INF/services/") + xface;
   2.144 +        {
   2.145 +            List<Element> origEls = originatingElements.get(rsrc);
   2.146 +            if (origEls == null) {
   2.147 +                origEls = new ArrayList<Element>();
   2.148 +                originatingElements.put(rsrc, origEls);
   2.149 +            }
   2.150 +            origEls.add(clazz);
   2.151 +        }
   2.152 +        List<String> lines = outputFiles.get(rsrc);
   2.153 +        if (lines == null) {
   2.154 +            lines = new ArrayList<String>();
   2.155 +            try {
   2.156 +                try {
   2.157 +                    FileObject in = processingEnv.getFiler().getResource(StandardLocation.SOURCE_PATH, "", rsrc);
   2.158 +                    in.openInputStream().close();
   2.159 +                    processingEnv.getMessager().printMessage(Kind.ERROR,
   2.160 +                            "Cannot generate " + rsrc + " because it already exists in sources: " + in.toUri());
   2.161 +                    return;
   2.162 +                } catch (FileNotFoundException x) {
   2.163 +                    // Good.
   2.164 +                }
   2.165 +                try {
   2.166 +                    FileObject in = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", rsrc);
   2.167 +                    InputStream is = in.openInputStream();
   2.168 +                    try {
   2.169 +                        BufferedReader r = new BufferedReader(new InputStreamReader(is, "UTF-8"));
   2.170 +                        String line;
   2.171 +                        while ((line = r.readLine()) != null) {
   2.172 +                            lines.add(line);
   2.173 +                        }
   2.174 +                    } finally {
   2.175 +                        is.close();
   2.176 +                    }
   2.177 +                } catch (FileNotFoundException x) {
   2.178 +                    // OK, created for the first time
   2.179 +                }
   2.180 +            } catch (IOException x) {
   2.181 +                processingEnv.getMessager().printMessage(Kind.ERROR, x.toString());
   2.182 +                return;
   2.183 +            }
   2.184 +            outputFiles.put(rsrc, lines);
   2.185 +        }
   2.186 +        int idx = lines.indexOf(impl);
   2.187 +        if (idx != -1) {
   2.188 +            lines.remove(idx);
   2.189 +            while (lines.size() > idx && lines.get(idx).matches("#position=.+|#-.+")) {
   2.190 +                lines.remove(idx);
   2.191 +            }
   2.192 +        }
   2.193 +        lines.add(impl);
   2.194 +        if (svc.position() != Integer.MAX_VALUE) {
   2.195 +            lines.add("#position=" + svc.position());
   2.196 +        }
   2.197 +        for (String exclude : svc.supersedes()) {
   2.198 +            lines.add("#-" + exclude);
   2.199 +        }
   2.200 +    }
   2.201 +
   2.202 +    private boolean verifyServiceProviderSignature(TypeElement clazz) {
   2.203 +        AnnotationMirror ann = findAnnotationMirror(clazz, ServiceProvider.class);
   2.204 +        if (!clazz.getModifiers().contains(Modifier.PUBLIC)) {
   2.205 +            processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must be public", clazz, ann);
   2.206 +            return false;
   2.207 +        }
   2.208 +        if (clazz.getModifiers().contains(Modifier.ABSTRACT)) {
   2.209 +            processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must not be abstract", clazz, ann);
   2.210 +            return false;
   2.211 +        }
   2.212 +        {
   2.213 +            boolean hasDefaultCtor = false;
   2.214 +            for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) {
   2.215 +                if (constructor.getModifiers().contains(Modifier.PUBLIC) && constructor.getParameters().isEmpty()) {
   2.216 +                    hasDefaultCtor = true;
   2.217 +                    break;
   2.218 +                }
   2.219 +            }
   2.220 +            if (!hasDefaultCtor) {
   2.221 +                processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must have a public no-argument constructor", clazz, ann);
   2.222 +                return false;
   2.223 +            }
   2.224 +        }
   2.225 +        return true;
   2.226 +    }
   2.227 +
   2.228 +    private void writeServices() {
   2.229 +        for (Map.Entry<String, List<String>> entry : outputFiles.entrySet()) {
   2.230 +            try {
   2.231 +                FileObject out = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", entry.getKey(),
   2.232 +                        originatingElements.get(entry.getKey()).toArray(new Element[0]));
   2.233 +                OutputStream os = out.openOutputStream();
   2.234 +                try {
   2.235 +                    PrintWriter w = new PrintWriter(new OutputStreamWriter(os, "UTF-8"));
   2.236 +                    for (String line : entry.getValue()) {
   2.237 +                        w.println(line);
   2.238 +                    }
   2.239 +                    w.flush();
   2.240 +                    w.close();
   2.241 +                } finally {
   2.242 +                    os.close();
   2.243 +                }
   2.244 +            } catch (IOException x) {
   2.245 +                processingEnv.getMessager().printMessage(Kind.ERROR, "Failed to write to " + entry.getKey() + ": " + x.toString());
   2.246 +            }
   2.247 +        }
   2.248 +    }
   2.249 +
   2.250 +    /**
   2.251 +     * @param element a source element
   2.252 +     * @param annotation a type of annotation
   2.253 +     * @return the instance of that annotation on the element, or null if not found
   2.254 +     */
   2.255 +    private AnnotationMirror findAnnotationMirror(Element element, Class<? extends Annotation> annotation) {
   2.256 +        for (AnnotationMirror ann : element.getAnnotationMirrors()) {
   2.257 +            if (processingEnv.getElementUtils().getBinaryName((TypeElement) ann.getAnnotationType().asElement()).
   2.258 +                    contentEquals(annotation.getName())) {
   2.259 +                return ann;
   2.260 +            }
   2.261 +        }
   2.262 +        return null;
   2.263 +    }
   2.264 +
   2.265 +    /**
   2.266 +     * @param annotation an annotation instance (null permitted)
   2.267 +     * @param name the name of an attribute of that annotation
   2.268 +     * @return the corresponding value if found
   2.269 +     */
   2.270 +    private AnnotationValue findAnnotationValue(AnnotationMirror annotation, String name) {
   2.271 +        if (annotation != null) {
   2.272 +            for (Map.Entry<? extends ExecutableElement,? extends AnnotationValue> entry : annotation.getElementValues().entrySet()) {
   2.273 +                if (entry.getKey().getSimpleName().contentEquals(name)) {
   2.274 +                    return entry.getValue();
   2.275 +                }
   2.276 +            }
   2.277 +        }
   2.278 +        return null;
   2.279 +    }
   2.280 +
   2.281 +    @Override
   2.282 +    public Iterable<? extends Completion> getCompletions(Element annotated, AnnotationMirror annotation, ExecutableElement attr, String userText) {
   2.283 +        if (processingEnv == null || annotated == null || !annotated.getKind().isClass()) {
   2.284 +            return Collections.emptyList();
   2.285 +        }
   2.286 +
   2.287 +        if (   annotation == null
   2.288 +            || !"org.openide.util.lookup.ServiceProvider".contentEquals(((TypeElement) annotation.getAnnotationType().asElement()).getQualifiedName())) {
   2.289 +            return Collections.emptyList();
   2.290 +        }
   2.291 +
   2.292 +        if (!"service".contentEquals(attr.getSimpleName())) {
   2.293 +            return Collections.emptyList();
   2.294 +        }
   2.295 +
   2.296 +        TypeElement jlObject = processingEnv.getElementUtils().getTypeElement("java.lang.Object");
   2.297 +
   2.298 +        if (jlObject == null) {
   2.299 +            return Collections.emptyList();
   2.300 +        }
   2.301 +        
   2.302 +        Collection<Completion> result = new LinkedList<Completion>();
   2.303 +        List<TypeElement> toProcess = new LinkedList<TypeElement>();
   2.304 +
   2.305 +        toProcess.add((TypeElement) annotated);
   2.306 +
   2.307 +        while (!toProcess.isEmpty()) {
   2.308 +            TypeElement c = toProcess.remove(0);
   2.309 +
   2.310 +            result.add(new TypeCompletion(c.getQualifiedName().toString() + ".class"));
   2.311 +
   2.312 +            List<TypeMirror> parents = new LinkedList<TypeMirror>();
   2.313 +
   2.314 +            parents.add(c.getSuperclass());
   2.315 +            parents.addAll(c.getInterfaces());
   2.316 +
   2.317 +            for (TypeMirror tm : parents) {
   2.318 +                if (tm == null || tm.getKind() != TypeKind.DECLARED) {
   2.319 +                    continue;
   2.320 +                }
   2.321 +
   2.322 +                TypeElement type = (TypeElement) processingEnv.getTypeUtils().asElement(tm);
   2.323 +
   2.324 +                if (!jlObject.equals(type)) {
   2.325 +                    toProcess.add(type);
   2.326 +                }
   2.327 +            }
   2.328 +        }
   2.329 +
   2.330 +        return result;
   2.331 +    }
   2.332 +
   2.333 +    private static final class TypeCompletion implements Completion {
   2.334 +
   2.335 +        private final String type;
   2.336 +
   2.337 +        public TypeCompletion(String type) {
   2.338 +            this.type = type;
   2.339 +        }
   2.340 +
   2.341 +        public String getValue() {
   2.342 +            return type;
   2.343 +        }
   2.344 +
   2.345 +        public String getMessage() {
   2.346 +            return null;
   2.347 +        }
   2.348 +        
   2.349 +    }
   2.350 +
   2.351 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/openide.util.lookup/test/unit/src/org/netbeans/modules/openide/util/ServiceProviderProcessorTest.java	Sat Oct 31 16:33:02 2009 +0100
     3.3 @@ -0,0 +1,180 @@
     3.4 +/*
     3.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3.6 + *
     3.7 + * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
     3.8 + *
     3.9 + * The contents of this file are subject to the terms of either the GNU
    3.10 + * General Public License Version 2 only ("GPL") or the Common
    3.11 + * Development and Distribution License("CDDL") (collectively, the
    3.12 + * "License"). You may not use this file except in compliance with the
    3.13 + * License. You can obtain a copy of the License at
    3.14 + * http://www.netbeans.org/cddl-gplv2.html
    3.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    3.16 + * specific language governing permissions and limitations under the
    3.17 + * License.  When distributing the software, include this License Header
    3.18 + * Notice in each file and include the License file at
    3.19 + * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
    3.20 + * particular file as subject to the "Classpath" exception as provided
    3.21 + * by Sun in the GPL Version 2 section of the License file that
    3.22 + * accompanied this code. If applicable, add the following below the
    3.23 + * License Header, with the fields enclosed by brackets [] replaced by
    3.24 + * your own identifying information:
    3.25 + * "Portions Copyrighted [year] [name of copyright owner]"
    3.26 + *
    3.27 + * If you wish your version of this file to be governed by only the CDDL
    3.28 + * or only the GPL Version 2, indicate your decision by adding
    3.29 + * "[Contributor] elects to include this software in this distribution
    3.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    3.31 + * single choice of license, a recipient has the option to distribute
    3.32 + * your version of this file under either the CDDL, the GPL Version 2 or
    3.33 + * to extend the choice of license to its licensees as provided above.
    3.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    3.35 + * Version 2 license, then the option applies only if the new code is
    3.36 + * made subject to such option by the copyright holder.
    3.37 + *
    3.38 + * Contributor(s):
    3.39 + *
    3.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
    3.41 + */
    3.42 +
    3.43 +package org.netbeans.modules.openide.util;
    3.44 +
    3.45 +import java.io.ByteArrayOutputStream;
    3.46 +import java.io.File;
    3.47 +import java.util.ArrayList;
    3.48 +import java.util.Arrays;
    3.49 +import java.util.Collections;
    3.50 +import java.util.Comparator;
    3.51 +import java.util.List;
    3.52 +import org.netbeans.junit.NbTestCase;
    3.53 +import org.openide.util.Lookup;
    3.54 +import org.openide.util.lookup.Lookups;
    3.55 +import org.openide.util.lookup.ServiceProvider;
    3.56 +import org.openide.util.lookup.ServiceProviders;
    3.57 +import org.openide.util.test.AnnotationProcessorTestUtils;
    3.58 +
    3.59 +public class ServiceProviderProcessorTest extends NbTestCase {
    3.60 +
    3.61 +    public ServiceProviderProcessorTest(String n) {
    3.62 +        super(n);
    3.63 +    }
    3.64 +
    3.65 +    private static List<Class<?>> classesOf(Iterable<?> objects) {
    3.66 +        List<Class<?>> cs = new ArrayList<Class<?>>();
    3.67 +        for (Object o : objects) {
    3.68 +            cs.add(o.getClass());
    3.69 +        }
    3.70 +        return cs;
    3.71 +    }
    3.72 +
    3.73 +    private static List<Class<?>> classesOfLookup(Class<?> xface) {
    3.74 +        return classesOf(Lookup.getDefault().lookupAll(xface));
    3.75 +    }
    3.76 +
    3.77 +    private static List<Class<?>> sortClassList(List<Class<?>> classes) {
    3.78 +        List<Class<?>> sorted = new ArrayList<Class<?>>(classes);
    3.79 +        Collections.sort(sorted, new Comparator<Class<?>>() {
    3.80 +            public int compare(Class<?> c1, Class<?> c2) {
    3.81 +                return c1.getName().compareTo(c2.getName());
    3.82 +            }
    3.83 +        });
    3.84 +        return sorted;
    3.85 +    }
    3.86 +
    3.87 +    public void testBasicUsage() throws Exception {
    3.88 +        assertEquals(Collections.singletonList(Implementation.class), classesOfLookup(Interface.class));
    3.89 +    }
    3.90 +    public interface Interface {}
    3.91 +    @ServiceProvider(service=Interface.class)
    3.92 +    public static class Implementation implements Interface {}
    3.93 +
    3.94 +    public void testPosition() throws Exception {
    3.95 +        assertEquals(Arrays.<Class<?>>asList(OrderedImpl3.class, OrderedImpl2.class, OrderedImpl1.class), classesOfLookup(OrderedInterface.class));
    3.96 +    }
    3.97 +    public interface OrderedInterface {}
    3.98 +    @ServiceProvider(service=OrderedInterface.class)
    3.99 +    public static class OrderedImpl1 implements OrderedInterface {}
   3.100 +    @ServiceProvider(service=OrderedInterface.class, position=200)
   3.101 +    public static class OrderedImpl2 implements OrderedInterface {}
   3.102 +    @ServiceProvider(service=OrderedInterface.class, position=100)
   3.103 +    public static class OrderedImpl3 implements OrderedInterface {}
   3.104 +
   3.105 +    public void testPath() throws Exception {
   3.106 +        assertEquals(Collections.singletonList(PathImplementation.class), classesOf(Lookups.forPath("some/path").lookupAll(Interface.class)));
   3.107 +    }
   3.108 +    @ServiceProvider(service=Interface.class, path="some/path")
   3.109 +    public static class PathImplementation implements Interface {}
   3.110 +
   3.111 +    public void testSupersedes() throws Exception {
   3.112 +        assertEquals(Arrays.<Class<?>>asList(Overrider.class, Unrelated.class), sortClassList(classesOfLookup(CancellableInterface.class)));
   3.113 +    }
   3.114 +    public interface CancellableInterface {}
   3.115 +    @ServiceProvider(service=CancellableInterface.class)
   3.116 +    public static class Overridden implements CancellableInterface {}
   3.117 +    @ServiceProvider(service=CancellableInterface.class, supersedes="org.netbeans.modules.openide.util.ServiceProviderProcessorTest$Overridden")
   3.118 +    public static class Overrider implements CancellableInterface {}
   3.119 +    @ServiceProvider(service=CancellableInterface.class)
   3.120 +    public static class Unrelated implements CancellableInterface {}
   3.121 +
   3.122 +    public void testMultipleRegistrations() throws Exception {
   3.123 +        assertEquals(Collections.singletonList(Multitasking.class), classesOfLookup(Interface1.class));
   3.124 +        assertEquals(Collections.singletonList(Multitasking.class), classesOfLookup(Interface2.class));
   3.125 +    }
   3.126 +    public interface Interface1 {}
   3.127 +    public interface Interface2 {}
   3.128 +    @ServiceProviders({@ServiceProvider(service=Interface1.class), @ServiceProvider(service=Interface2.class)})
   3.129 +    public static class Multitasking implements Interface1, Interface2 {}
   3.130 +
   3.131 +    public void testErrorReporting() throws Exception {
   3.132 +        clearWorkDir();
   3.133 +        File src = new File(getWorkDir(), "src");
   3.134 +        File dest = new File(getWorkDir(), "classes");
   3.135 +        String xfaceName = Interface.class.getCanonicalName();
   3.136 +
   3.137 +        AnnotationProcessorTestUtils.makeSource(src, "p.C1",
   3.138 +                "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
   3.139 +                "public class C1 implements " + xfaceName + " {}");
   3.140 +        ByteArrayOutputStream baos = new ByteArrayOutputStream();
   3.141 +        assertTrue(AnnotationProcessorTestUtils.runJavac(src, "C1", dest, null, baos));
   3.142 +
   3.143 +        AnnotationProcessorTestUtils.makeSource(src, "p.C2",
   3.144 +                "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
   3.145 +                "class C2 implements " + xfaceName + " {}");
   3.146 +        baos = new ByteArrayOutputStream();
   3.147 +        assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C2", dest, null, baos));
   3.148 +        assertTrue(baos.toString(), baos.toString().contains("public"));
   3.149 +
   3.150 +        AnnotationProcessorTestUtils.makeSource(src, "p.C3",
   3.151 +                "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
   3.152 +                "public class C3 implements " + xfaceName + " {",
   3.153 +                "public C3(boolean x) {}",
   3.154 +                "}");
   3.155 +        baos = new ByteArrayOutputStream();
   3.156 +        assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C3", dest, null, baos));
   3.157 +        assertTrue(baos.toString(), baos.toString().contains("constructor"));
   3.158 +
   3.159 +        AnnotationProcessorTestUtils.makeSource(src, "p.C4",
   3.160 +                "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
   3.161 +                "public class C4 implements " + xfaceName + " {",
   3.162 +                "C4() {}",
   3.163 +                "}");
   3.164 +        baos = new ByteArrayOutputStream();
   3.165 +        assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C4", dest, null, baos));
   3.166 +        assertTrue(baos.toString(), baos.toString().contains("constructor"));
   3.167 +
   3.168 +        AnnotationProcessorTestUtils.makeSource(src, "p.C5",
   3.169 +                "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
   3.170 +                "public abstract class C5 implements " + xfaceName + " {}");
   3.171 +        baos = new ByteArrayOutputStream();
   3.172 +        assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C5", dest, null, baos));
   3.173 +        assertTrue(baos.toString(), baos.toString().contains("abstract"));
   3.174 +
   3.175 +        AnnotationProcessorTestUtils.makeSource(src, "p.C6",
   3.176 +                "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
   3.177 +                "public class C6 {}");
   3.178 +        baos = new ByteArrayOutputStream();
   3.179 +        assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C6", dest, null, baos));
   3.180 +        assertTrue(baos.toString(), baos.toString().contains("assignable"));
   3.181 +    }
   3.182 +
   3.183 +}
     4.1 --- a/openide.util.lookup/test/unit/src/org/openide/util/lookup/MetaInfServicesLookupTest.java	Sat Oct 31 15:30:02 2009 +0100
     4.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/MetaInfServicesLookupTest.java	Sat Oct 31 16:33:02 2009 +0100
     4.3 @@ -75,8 +75,6 @@
     4.4  import org.bar.Comparator2;
     4.5  import org.netbeans.junit.MockServices;
     4.6  import org.netbeans.junit.NbTestCase;
     4.7 -import org.openide.util.Enumerations;
     4.8 -import org.openide.util.Exceptions;
     4.9  import org.openide.util.Lookup;
    4.10  import org.openide.util.LookupEvent;
    4.11  import org.openide.util.LookupListener;
    4.12 @@ -485,7 +483,7 @@
    4.13                      try {
    4.14                          wait();
    4.15                      } catch (InterruptedException ex) {
    4.16 -                        Exceptions.printStackTrace(ex);
    4.17 +                        Logger.getLogger("global").log(Level.WARNING, "", ex);
    4.18                      }
    4.19                  }
    4.20              }
    4.21 @@ -518,7 +516,7 @@
    4.22          assertNull(Lookups.metaInfServices(new ClassLoader() {
    4.23              protected @Override Enumeration<URL> findResources(String name) throws IOException {
    4.24                  if (name.equals("META-INF/services/java.lang.Object")) {
    4.25 -                    return Enumerations.singleton(new URL(null, "dummy:stuff", new URLStreamHandler() {
    4.26 +                    return singleton(new URL(null, "dummy:stuff", new URLStreamHandler() {
    4.27                          protected URLConnection openConnection(URL u) throws IOException {
    4.28                              return new URLConnection(u) {
    4.29                                  public void connect() throws IOException {}
    4.30 @@ -529,9 +527,10 @@
    4.31                          }
    4.32                      }));
    4.33                  } else {
    4.34 -                    return Enumerations.empty();
    4.35 +                    return Collections.enumeration(Collections.<URL>emptyList());
    4.36                  }
    4.37              }
    4.38 +
    4.39          }).lookup(Object.class));
    4.40      }
    4.41      public static class Broken1 {
    4.42 @@ -547,4 +546,7 @@
    4.43          }
    4.44      }
    4.45  
    4.46 +    static <T> Enumeration<T> singleton(T t) {
    4.47 +        return Collections.enumeration(Collections.singleton(t));
    4.48 +    }
    4.49  }
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/test/AnnotationProcessorTestUtils.java	Sat Oct 31 16:33:02 2009 +0100
     5.3 @@ -0,0 +1,139 @@
     5.4 +/*
     5.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     5.6 + *
     5.7 + * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
     5.8 + *
     5.9 + * The contents of this file are subject to the terms of either the GNU
    5.10 + * General Public License Version 2 only ("GPL") or the Common
    5.11 + * Development and Distribution License("CDDL") (collectively, the
    5.12 + * "License"). You may not use this file except in compliance with the
    5.13 + * License. You can obtain a copy of the License at
    5.14 + * http://www.netbeans.org/cddl-gplv2.html
    5.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    5.16 + * specific language governing permissions and limitations under the
    5.17 + * License.  When distributing the software, include this License Header
    5.18 + * Notice in each file and include the License file at
    5.19 + * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
    5.20 + * particular file as subject to the "Classpath" exception as provided
    5.21 + * by Sun in the GPL Version 2 section of the License file that
    5.22 + * accompanied this code. If applicable, add the following below the
    5.23 + * License Header, with the fields enclosed by brackets [] replaced by
    5.24 + * your own identifying information:
    5.25 + * "Portions Copyrighted [year] [name of copyright owner]"
    5.26 + *
    5.27 + * If you wish your version of this file to be governed by only the CDDL
    5.28 + * or only the GPL Version 2, indicate your decision by adding
    5.29 + * "[Contributor] elects to include this software in this distribution
    5.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    5.31 + * single choice of license, a recipient has the option to distribute
    5.32 + * your version of this file under either the CDDL, the GPL Version 2 or
    5.33 + * to extend the choice of license to its licensees as provided above.
    5.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    5.35 + * Version 2 license, then the option applies only if the new code is
    5.36 + * made subject to such option by the copyright holder.
    5.37 + *
    5.38 + * Contributor(s):
    5.39 + *
    5.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
    5.41 + */
    5.42 +
    5.43 +package org.openide.util.test;
    5.44 +
    5.45 +import java.io.File;
    5.46 +import java.io.FileWriter;
    5.47 +import java.io.IOException;
    5.48 +import java.io.OutputStream;
    5.49 +import java.io.PrintWriter;
    5.50 +import java.io.Writer;
    5.51 +import java.util.ArrayList;
    5.52 +import java.util.List;
    5.53 +import java.util.regex.Pattern;
    5.54 +import javax.tools.JavaCompiler;
    5.55 +import javax.tools.ToolProvider;
    5.56 +import junit.framework.Assert;
    5.57 +
    5.58 +/**
    5.59 + * Utilities useful to those testing JSR 269 annotation processors.
    5.60 + * <p>If you just want to test that the output of the processor is correct,
    5.61 + * you do not need to do anything special:
    5.62 + * just use the annotation on some sample classes nested inside your unit test.
    5.63 + * They will be processed, and you check that your SPI loads them correctly.
    5.64 + * These utilities are useful mainly in case you want to check that the processor
    5.65 + * rejects erroneous sources, and that any messages it prints are reasonable;
    5.66 + * that it behaves correctly on incremental compilations; etc.
    5.67 + */
    5.68 +public class AnnotationProcessorTestUtils {
    5.69 +
    5.70 +    private AnnotationProcessorTestUtils() {}
    5.71 +
    5.72 +    /**
    5.73 +     * Create a source file.
    5.74 +     * @param dir source root
    5.75 +     * @param clazz a fully-qualified class name
    5.76 +     * @param content lines of text (skip package decl)
    5.77 +     */
    5.78 +    public static void makeSource(File dir, String clazz, String... content) throws IOException {
    5.79 +        File f = new File(dir, clazz.replace('.', File.separatorChar) + ".java");
    5.80 +        f.getParentFile().mkdirs();
    5.81 +        Writer w = new FileWriter(f);
    5.82 +        try {
    5.83 +            PrintWriter pw = new PrintWriter(w);
    5.84 +            String pkg = clazz.replaceFirst("\\.[^.]+$", "");
    5.85 +            if (!pkg.equals(clazz)) {
    5.86 +                pw.println("package " + pkg + ";");
    5.87 +            }
    5.88 +            for (String line : content) {
    5.89 +                pw.println(line);
    5.90 +            }
    5.91 +            pw.flush();
    5.92 +        } finally {
    5.93 +            w.close();
    5.94 +        }
    5.95 +    }
    5.96 +
    5.97 +    /**
    5.98 +     * Run the Java compiler.
    5.99 +     * (A JSR 199 implementation must be available.)
   5.100 +     * @param src a source root (runs javac on all *.java it finds matching {@code srcIncludes})
   5.101 +     * @param srcIncludes a pattern of source files names without path to compile (useful for testing incremental compiles), or null for all
   5.102 +     * @param dest a dest dir to compile classes to
   5.103 +     * @param cp classpath entries; if null, use Java classpath of test
   5.104 +     * @param stderr output stream to print messages to, or null for test console (i.e. do not capture)
   5.105 +     * @return true if compilation succeeded, false if it failed
   5.106 +     */
   5.107 +    public static boolean runJavac(File src, String srcIncludes, File dest, File[] cp, OutputStream stderr) {
   5.108 +        List<String> args = new ArrayList<String>();
   5.109 +        args.add("-classpath");
   5.110 +        if (cp != null) {
   5.111 +            StringBuffer b = new StringBuffer();
   5.112 +            for (File entry : cp) {
   5.113 +                b.append(File.pathSeparatorChar);
   5.114 +                b.append(entry.getAbsolutePath());
   5.115 +            }
   5.116 +            args.add(b.toString());
   5.117 +        } else {
   5.118 +            args.add(System.getProperty("java.class.path"));
   5.119 +        }
   5.120 +        args.add("-d");
   5.121 +        args.add(dest.getAbsolutePath());
   5.122 +        args.add("-sourcepath");
   5.123 +        args.add(src.getAbsolutePath());
   5.124 +        dest.mkdirs();
   5.125 +        scan(args, src, srcIncludes);
   5.126 +        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
   5.127 +        Assert.assertNotNull("no JSR 199 compiler impl found; try e.g.: " +
   5.128 +                "test.unit.run.cp.extra=${nb_all}/apisupport.harness/external/openjdk-javac-6-b12.jar", compiler);
   5.129 +        //System.err.println("running javac with args: " + args);
   5.130 +        return compiler.run(null, null, stderr, args.toArray(new String[args.size()])) == 0;
   5.131 +    }
   5.132 +    private static void scan(List<String> names, File f, String includes) {
   5.133 +        if (f.isDirectory()) {
   5.134 +            for (File kid : f.listFiles()) {
   5.135 +                scan(names, kid, includes);
   5.136 +            }
   5.137 +        } else if (f.getName().endsWith(".java") && (includes == null || Pattern.compile(includes).matcher(f.getName()).find())) {
   5.138 +            names.add(f.getAbsolutePath());
   5.139 +        }
   5.140 +    }
   5.141 +
   5.142 +}
     6.1 --- a/openide.util/src/META-INF/services/javax.annotation.processing.Processor	Sat Oct 31 15:30:02 2009 +0100
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,1 +0,0 @@
     6.4 -org.netbeans.modules.openide.util.ServiceProviderProcessor
     7.1 --- a/openide.util/src/org/netbeans/modules/openide/util/ServiceProviderProcessor.java	Sat Oct 31 15:30:02 2009 +0100
     7.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.3 @@ -1,348 +0,0 @@
     7.4 -/*
     7.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     7.6 - *
     7.7 - * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
     7.8 - *
     7.9 - * The contents of this file are subject to the terms of either the GNU
    7.10 - * General Public License Version 2 only ("GPL") or the Common
    7.11 - * Development and Distribution License("CDDL") (collectively, the
    7.12 - * "License"). You may not use this file except in compliance with the
    7.13 - * License. You can obtain a copy of the License at
    7.14 - * http://www.netbeans.org/cddl-gplv2.html
    7.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    7.16 - * specific language governing permissions and limitations under the
    7.17 - * License.  When distributing the software, include this License Header
    7.18 - * Notice in each file and include the License file at
    7.19 - * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
    7.20 - * particular file as subject to the "Classpath" exception as provided
    7.21 - * by Sun in the GPL Version 2 section of the License file that
    7.22 - * accompanied this code. If applicable, add the following below the
    7.23 - * License Header, with the fields enclosed by brackets [] replaced by
    7.24 - * your own identifying information:
    7.25 - * "Portions Copyrighted [year] [name of copyright owner]"
    7.26 - *
    7.27 - * If you wish your version of this file to be governed by only the CDDL
    7.28 - * or only the GPL Version 2, indicate your decision by adding
    7.29 - * "[Contributor] elects to include this software in this distribution
    7.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
    7.31 - * single choice of license, a recipient has the option to distribute
    7.32 - * your version of this file under either the CDDL, the GPL Version 2 or
    7.33 - * to extend the choice of license to its licensees as provided above.
    7.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
    7.35 - * Version 2 license, then the option applies only if the new code is
    7.36 - * made subject to such option by the copyright holder.
    7.37 - *
    7.38 - * Contributor(s):
    7.39 - *
    7.40 - * Portions Copyrighted 2008 Sun Microsystems, Inc.
    7.41 - */
    7.42 -
    7.43 -package org.netbeans.modules.openide.util;
    7.44 -
    7.45 -import java.io.BufferedReader;
    7.46 -import java.io.FileNotFoundException;
    7.47 -import java.io.IOException;
    7.48 -import java.io.InputStream;
    7.49 -import java.io.InputStreamReader;
    7.50 -import java.io.OutputStream;
    7.51 -import java.io.OutputStreamWriter;
    7.52 -import java.io.PrintWriter;
    7.53 -import java.lang.annotation.Annotation;
    7.54 -import java.util.ArrayList;
    7.55 -import java.util.Collection;
    7.56 -import java.util.Collections;
    7.57 -import java.util.HashMap;
    7.58 -import java.util.LinkedList;
    7.59 -import java.util.List;
    7.60 -import java.util.Map;
    7.61 -import java.util.Set;
    7.62 -import javax.annotation.processing.AbstractProcessor;
    7.63 -import javax.annotation.processing.Completion;
    7.64 -import javax.annotation.processing.RoundEnvironment;
    7.65 -import javax.annotation.processing.SupportedAnnotationTypes;
    7.66 -import javax.annotation.processing.SupportedSourceVersion;
    7.67 -import javax.lang.model.SourceVersion;
    7.68 -import javax.lang.model.element.AnnotationMirror;
    7.69 -import javax.lang.model.element.AnnotationValue;
    7.70 -import javax.lang.model.element.Element;
    7.71 -import javax.lang.model.element.ExecutableElement;
    7.72 -import javax.lang.model.element.Modifier;
    7.73 -import javax.lang.model.element.TypeElement;
    7.74 -import javax.lang.model.type.MirroredTypeException;
    7.75 -import javax.lang.model.type.TypeKind;
    7.76 -import javax.lang.model.type.TypeMirror;
    7.77 -import javax.lang.model.util.ElementFilter;
    7.78 -import javax.tools.Diagnostic.Kind;
    7.79 -import javax.tools.FileObject;
    7.80 -import javax.tools.StandardLocation;
    7.81 -import org.openide.util.lookup.ServiceProvider;
    7.82 -import org.openide.util.lookup.ServiceProviders;
    7.83 -
    7.84 -@SupportedSourceVersion(SourceVersion.RELEASE_6)
    7.85 -@SupportedAnnotationTypes({"org.openide.util.lookup.ServiceProvider", "org.openide.util.lookup.ServiceProviders"})
    7.86 -public class ServiceProviderProcessor extends AbstractProcessor {
    7.87 -
    7.88 -    /** public for ServiceLoader */
    7.89 -    public ServiceProviderProcessor() {}
    7.90 -
    7.91 -    private final Map<String, List<String>> outputFiles = new HashMap<String,List<String>>();
    7.92 -    private final Map<String, List<Element>> originatingElements = new HashMap<String,List<Element>>();
    7.93 -
    7.94 -    @Override
    7.95 -    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    7.96 -        if (roundEnv.errorRaised()) {
    7.97 -            return false;
    7.98 -        }
    7.99 -        if (roundEnv.processingOver()) {
   7.100 -            writeServices();
   7.101 -            return false;
   7.102 -        } else {
   7.103 -            for (Element el : roundEnv.getElementsAnnotatedWith(ServiceProvider.class)) {
   7.104 -                TypeElement clazz = (TypeElement) el;
   7.105 -                if (!verifyServiceProviderSignature(clazz)) {
   7.106 -                    continue;
   7.107 -                }
   7.108 -                ServiceProvider sp = clazz.getAnnotation(ServiceProvider.class);
   7.109 -                register(clazz, sp);
   7.110 -            }
   7.111 -            for (Element el : roundEnv.getElementsAnnotatedWith(ServiceProviders.class)) {
   7.112 -                TypeElement clazz = (TypeElement) el;
   7.113 -                if (!verifyServiceProviderSignature(clazz)) {
   7.114 -                    continue;
   7.115 -                }
   7.116 -                ServiceProviders spp = clazz.getAnnotation(ServiceProviders.class);
   7.117 -                for (ServiceProvider sp : spp.value()) {
   7.118 -                    register(clazz, sp);
   7.119 -                }
   7.120 -            }
   7.121 -            return true;
   7.122 -        }
   7.123 -    }
   7.124 -
   7.125 -    private void register(TypeElement clazz, ServiceProvider svc) {
   7.126 -        TypeMirror type;
   7.127 -        try {
   7.128 -            svc.service();
   7.129 -            assert false;
   7.130 -            return;
   7.131 -        } catch (MirroredTypeException e) {
   7.132 -            type = e.getTypeMirror();
   7.133 -        }
   7.134 -        String impl = processingEnv.getElementUtils().getBinaryName(clazz).toString();
   7.135 -        String xface = processingEnv.getElementUtils().getBinaryName((TypeElement) processingEnv.getTypeUtils().asElement(type)).toString();
   7.136 -        if (!processingEnv.getTypeUtils().isAssignable(clazz.asType(), type)) {
   7.137 -            AnnotationMirror ann = findAnnotationMirror(clazz, ServiceProvider.class);
   7.138 -            processingEnv.getMessager().printMessage(Kind.ERROR, impl + " is not assignable to " + xface,
   7.139 -                    clazz, ann, findAnnotationValue(ann, "service"));
   7.140 -            return;
   7.141 -        }
   7.142 -        processingEnv.getMessager().printMessage(Kind.NOTE, impl + " to be registered as a " + xface);
   7.143 -        String rsrc = (svc.path().length() > 0 ? "META-INF/namedservices/" + svc.path() + "/" : "META-INF/services/") + xface;
   7.144 -        {
   7.145 -            List<Element> origEls = originatingElements.get(rsrc);
   7.146 -            if (origEls == null) {
   7.147 -                origEls = new ArrayList<Element>();
   7.148 -                originatingElements.put(rsrc, origEls);
   7.149 -            }
   7.150 -            origEls.add(clazz);
   7.151 -        }
   7.152 -        List<String> lines = outputFiles.get(rsrc);
   7.153 -        if (lines == null) {
   7.154 -            lines = new ArrayList<String>();
   7.155 -            try {
   7.156 -                try {
   7.157 -                    FileObject in = processingEnv.getFiler().getResource(StandardLocation.SOURCE_PATH, "", rsrc);
   7.158 -                    in.openInputStream().close();
   7.159 -                    processingEnv.getMessager().printMessage(Kind.ERROR,
   7.160 -                            "Cannot generate " + rsrc + " because it already exists in sources: " + in.toUri());
   7.161 -                    return;
   7.162 -                } catch (FileNotFoundException x) {
   7.163 -                    // Good.
   7.164 -                }
   7.165 -                try {
   7.166 -                    FileObject in = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", rsrc);
   7.167 -                    InputStream is = in.openInputStream();
   7.168 -                    try {
   7.169 -                        BufferedReader r = new BufferedReader(new InputStreamReader(is, "UTF-8"));
   7.170 -                        String line;
   7.171 -                        while ((line = r.readLine()) != null) {
   7.172 -                            lines.add(line);
   7.173 -                        }
   7.174 -                    } finally {
   7.175 -                        is.close();
   7.176 -                    }
   7.177 -                } catch (FileNotFoundException x) {
   7.178 -                    // OK, created for the first time
   7.179 -                }
   7.180 -            } catch (IOException x) {
   7.181 -                processingEnv.getMessager().printMessage(Kind.ERROR, x.toString());
   7.182 -                return;
   7.183 -            }
   7.184 -            outputFiles.put(rsrc, lines);
   7.185 -        }
   7.186 -        int idx = lines.indexOf(impl);
   7.187 -        if (idx != -1) {
   7.188 -            lines.remove(idx);
   7.189 -            while (lines.size() > idx && lines.get(idx).matches("#position=.+|#-.+")) {
   7.190 -                lines.remove(idx);
   7.191 -            }
   7.192 -        }
   7.193 -        lines.add(impl);
   7.194 -        if (svc.position() != Integer.MAX_VALUE) {
   7.195 -            lines.add("#position=" + svc.position());
   7.196 -        }
   7.197 -        for (String exclude : svc.supersedes()) {
   7.198 -            lines.add("#-" + exclude);
   7.199 -        }
   7.200 -    }
   7.201 -
   7.202 -    private boolean verifyServiceProviderSignature(TypeElement clazz) {
   7.203 -        AnnotationMirror ann = findAnnotationMirror(clazz, ServiceProvider.class);
   7.204 -        if (!clazz.getModifiers().contains(Modifier.PUBLIC)) {
   7.205 -            processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must be public", clazz, ann);
   7.206 -            return false;
   7.207 -        }
   7.208 -        if (clazz.getModifiers().contains(Modifier.ABSTRACT)) {
   7.209 -            processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must not be abstract", clazz, ann);
   7.210 -            return false;
   7.211 -        }
   7.212 -        {
   7.213 -            boolean hasDefaultCtor = false;
   7.214 -            for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) {
   7.215 -                if (constructor.getModifiers().contains(Modifier.PUBLIC) && constructor.getParameters().isEmpty()) {
   7.216 -                    hasDefaultCtor = true;
   7.217 -                    break;
   7.218 -                }
   7.219 -            }
   7.220 -            if (!hasDefaultCtor) {
   7.221 -                processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must have a public no-argument constructor", clazz, ann);
   7.222 -                return false;
   7.223 -            }
   7.224 -        }
   7.225 -        return true;
   7.226 -    }
   7.227 -
   7.228 -    private void writeServices() {
   7.229 -        for (Map.Entry<String, List<String>> entry : outputFiles.entrySet()) {
   7.230 -            try {
   7.231 -                FileObject out = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", entry.getKey(),
   7.232 -                        originatingElements.get(entry.getKey()).toArray(new Element[0]));
   7.233 -                OutputStream os = out.openOutputStream();
   7.234 -                try {
   7.235 -                    PrintWriter w = new PrintWriter(new OutputStreamWriter(os, "UTF-8"));
   7.236 -                    for (String line : entry.getValue()) {
   7.237 -                        w.println(line);
   7.238 -                    }
   7.239 -                    w.flush();
   7.240 -                    w.close();
   7.241 -                } finally {
   7.242 -                    os.close();
   7.243 -                }
   7.244 -            } catch (IOException x) {
   7.245 -                processingEnv.getMessager().printMessage(Kind.ERROR, "Failed to write to " + entry.getKey() + ": " + x.toString());
   7.246 -            }
   7.247 -        }
   7.248 -    }
   7.249 -
   7.250 -    /**
   7.251 -     * @param element a source element
   7.252 -     * @param annotation a type of annotation
   7.253 -     * @return the instance of that annotation on the element, or null if not found
   7.254 -     */
   7.255 -    private AnnotationMirror findAnnotationMirror(Element element, Class<? extends Annotation> annotation) {
   7.256 -        for (AnnotationMirror ann : element.getAnnotationMirrors()) {
   7.257 -            if (processingEnv.getElementUtils().getBinaryName((TypeElement) ann.getAnnotationType().asElement()).
   7.258 -                    contentEquals(annotation.getName())) {
   7.259 -                return ann;
   7.260 -            }
   7.261 -        }
   7.262 -        return null;
   7.263 -    }
   7.264 -
   7.265 -    /**
   7.266 -     * @param annotation an annotation instance (null permitted)
   7.267 -     * @param name the name of an attribute of that annotation
   7.268 -     * @return the corresponding value if found
   7.269 -     */
   7.270 -    private AnnotationValue findAnnotationValue(AnnotationMirror annotation, String name) {
   7.271 -        if (annotation != null) {
   7.272 -            for (Map.Entry<? extends ExecutableElement,? extends AnnotationValue> entry : annotation.getElementValues().entrySet()) {
   7.273 -                if (entry.getKey().getSimpleName().contentEquals(name)) {
   7.274 -                    return entry.getValue();
   7.275 -                }
   7.276 -            }
   7.277 -        }
   7.278 -        return null;
   7.279 -    }
   7.280 -
   7.281 -    @Override
   7.282 -    public Iterable<? extends Completion> getCompletions(Element annotated, AnnotationMirror annotation, ExecutableElement attr, String userText) {
   7.283 -        if (processingEnv == null || annotated == null || !annotated.getKind().isClass()) {
   7.284 -            return Collections.emptyList();
   7.285 -        }
   7.286 -
   7.287 -        if (   annotation == null
   7.288 -            || !"org.openide.util.lookup.ServiceProvider".contentEquals(((TypeElement) annotation.getAnnotationType().asElement()).getQualifiedName())) {
   7.289 -            return Collections.emptyList();
   7.290 -        }
   7.291 -
   7.292 -        if (!"service".contentEquals(attr.getSimpleName())) {
   7.293 -            return Collections.emptyList();
   7.294 -        }
   7.295 -
   7.296 -        TypeElement jlObject = processingEnv.getElementUtils().getTypeElement("java.lang.Object");
   7.297 -
   7.298 -        if (jlObject == null) {
   7.299 -            return Collections.emptyList();
   7.300 -        }
   7.301 -        
   7.302 -        Collection<Completion> result = new LinkedList<Completion>();
   7.303 -        List<TypeElement> toProcess = new LinkedList<TypeElement>();
   7.304 -
   7.305 -        toProcess.add((TypeElement) annotated);
   7.306 -
   7.307 -        while (!toProcess.isEmpty()) {
   7.308 -            TypeElement c = toProcess.remove(0);
   7.309 -
   7.310 -            result.add(new TypeCompletion(c.getQualifiedName().toString() + ".class"));
   7.311 -
   7.312 -            List<TypeMirror> parents = new LinkedList<TypeMirror>();
   7.313 -
   7.314 -            parents.add(c.getSuperclass());
   7.315 -            parents.addAll(c.getInterfaces());
   7.316 -
   7.317 -            for (TypeMirror tm : parents) {
   7.318 -                if (tm == null || tm.getKind() != TypeKind.DECLARED) {
   7.319 -                    continue;
   7.320 -                }
   7.321 -
   7.322 -                TypeElement type = (TypeElement) processingEnv.getTypeUtils().asElement(tm);
   7.323 -
   7.324 -                if (!jlObject.equals(type)) {
   7.325 -                    toProcess.add(type);
   7.326 -                }
   7.327 -            }
   7.328 -        }
   7.329 -
   7.330 -        return result;
   7.331 -    }
   7.332 -
   7.333 -    private static final class TypeCompletion implements Completion {
   7.334 -
   7.335 -        private final String type;
   7.336 -
   7.337 -        public TypeCompletion(String type) {
   7.338 -            this.type = type;
   7.339 -        }
   7.340 -
   7.341 -        public String getValue() {
   7.342 -            return type;
   7.343 -        }
   7.344 -
   7.345 -        public String getMessage() {
   7.346 -            return null;
   7.347 -        }
   7.348 -        
   7.349 -    }
   7.350 -
   7.351 -}
     8.1 --- a/openide.util/test/unit/src/org/netbeans/modules/openide/util/ServiceProviderProcessorTest.java	Sat Oct 31 15:30:02 2009 +0100
     8.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.3 @@ -1,180 +0,0 @@
     8.4 -/*
     8.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     8.6 - *
     8.7 - * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
     8.8 - *
     8.9 - * The contents of this file are subject to the terms of either the GNU
    8.10 - * General Public License Version 2 only ("GPL") or the Common
    8.11 - * Development and Distribution License("CDDL") (collectively, the
    8.12 - * "License"). You may not use this file except in compliance with the
    8.13 - * License. You can obtain a copy of the License at
    8.14 - * http://www.netbeans.org/cddl-gplv2.html
    8.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    8.16 - * specific language governing permissions and limitations under the
    8.17 - * License.  When distributing the software, include this License Header
    8.18 - * Notice in each file and include the License file at
    8.19 - * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
    8.20 - * particular file as subject to the "Classpath" exception as provided
    8.21 - * by Sun in the GPL Version 2 section of the License file that
    8.22 - * accompanied this code. If applicable, add the following below the
    8.23 - * License Header, with the fields enclosed by brackets [] replaced by
    8.24 - * your own identifying information:
    8.25 - * "Portions Copyrighted [year] [name of copyright owner]"
    8.26 - *
    8.27 - * If you wish your version of this file to be governed by only the CDDL
    8.28 - * or only the GPL Version 2, indicate your decision by adding
    8.29 - * "[Contributor] elects to include this software in this distribution
    8.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
    8.31 - * single choice of license, a recipient has the option to distribute
    8.32 - * your version of this file under either the CDDL, the GPL Version 2 or
    8.33 - * to extend the choice of license to its licensees as provided above.
    8.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
    8.35 - * Version 2 license, then the option applies only if the new code is
    8.36 - * made subject to such option by the copyright holder.
    8.37 - *
    8.38 - * Contributor(s):
    8.39 - *
    8.40 - * Portions Copyrighted 2008 Sun Microsystems, Inc.
    8.41 - */
    8.42 -
    8.43 -package org.netbeans.modules.openide.util;
    8.44 -
    8.45 -import java.io.ByteArrayOutputStream;
    8.46 -import java.io.File;
    8.47 -import java.util.ArrayList;
    8.48 -import java.util.Arrays;
    8.49 -import java.util.Collections;
    8.50 -import java.util.Comparator;
    8.51 -import java.util.List;
    8.52 -import org.netbeans.junit.NbTestCase;
    8.53 -import org.openide.util.Lookup;
    8.54 -import org.openide.util.lookup.Lookups;
    8.55 -import org.openide.util.lookup.ServiceProvider;
    8.56 -import org.openide.util.lookup.ServiceProviders;
    8.57 -import org.openide.util.test.AnnotationProcessorTestUtils;
    8.58 -
    8.59 -public class ServiceProviderProcessorTest extends NbTestCase {
    8.60 -
    8.61 -    public ServiceProviderProcessorTest(String n) {
    8.62 -        super(n);
    8.63 -    }
    8.64 -
    8.65 -    private static List<Class<?>> classesOf(Iterable<?> objects) {
    8.66 -        List<Class<?>> cs = new ArrayList<Class<?>>();
    8.67 -        for (Object o : objects) {
    8.68 -            cs.add(o.getClass());
    8.69 -        }
    8.70 -        return cs;
    8.71 -    }
    8.72 -
    8.73 -    private static List<Class<?>> classesOfLookup(Class<?> xface) {
    8.74 -        return classesOf(Lookup.getDefault().lookupAll(xface));
    8.75 -    }
    8.76 -
    8.77 -    private static List<Class<?>> sortClassList(List<Class<?>> classes) {
    8.78 -        List<Class<?>> sorted = new ArrayList<Class<?>>(classes);
    8.79 -        Collections.sort(sorted, new Comparator<Class<?>>() {
    8.80 -            public int compare(Class<?> c1, Class<?> c2) {
    8.81 -                return c1.getName().compareTo(c2.getName());
    8.82 -            }
    8.83 -        });
    8.84 -        return sorted;
    8.85 -    }
    8.86 -
    8.87 -    public void testBasicUsage() throws Exception {
    8.88 -        assertEquals(Collections.singletonList(Implementation.class), classesOfLookup(Interface.class));
    8.89 -    }
    8.90 -    public interface Interface {}
    8.91 -    @ServiceProvider(service=Interface.class)
    8.92 -    public static class Implementation implements Interface {}
    8.93 -
    8.94 -    public void testPosition() throws Exception {
    8.95 -        assertEquals(Arrays.<Class<?>>asList(OrderedImpl3.class, OrderedImpl2.class, OrderedImpl1.class), classesOfLookup(OrderedInterface.class));
    8.96 -    }
    8.97 -    public interface OrderedInterface {}
    8.98 -    @ServiceProvider(service=OrderedInterface.class)
    8.99 -    public static class OrderedImpl1 implements OrderedInterface {}
   8.100 -    @ServiceProvider(service=OrderedInterface.class, position=200)
   8.101 -    public static class OrderedImpl2 implements OrderedInterface {}
   8.102 -    @ServiceProvider(service=OrderedInterface.class, position=100)
   8.103 -    public static class OrderedImpl3 implements OrderedInterface {}
   8.104 -
   8.105 -    public void testPath() throws Exception {
   8.106 -        assertEquals(Collections.singletonList(PathImplementation.class), classesOf(Lookups.forPath("some/path").lookupAll(Interface.class)));
   8.107 -    }
   8.108 -    @ServiceProvider(service=Interface.class, path="some/path")
   8.109 -    public static class PathImplementation implements Interface {}
   8.110 -
   8.111 -    public void testSupersedes() throws Exception {
   8.112 -        assertEquals(Arrays.<Class<?>>asList(Overrider.class, Unrelated.class), sortClassList(classesOfLookup(CancellableInterface.class)));
   8.113 -    }
   8.114 -    public interface CancellableInterface {}
   8.115 -    @ServiceProvider(service=CancellableInterface.class)
   8.116 -    public static class Overridden implements CancellableInterface {}
   8.117 -    @ServiceProvider(service=CancellableInterface.class, supersedes="org.netbeans.modules.openide.util.ServiceProviderProcessorTest$Overridden")
   8.118 -    public static class Overrider implements CancellableInterface {}
   8.119 -    @ServiceProvider(service=CancellableInterface.class)
   8.120 -    public static class Unrelated implements CancellableInterface {}
   8.121 -
   8.122 -    public void testMultipleRegistrations() throws Exception {
   8.123 -        assertEquals(Collections.singletonList(Multitasking.class), classesOfLookup(Interface1.class));
   8.124 -        assertEquals(Collections.singletonList(Multitasking.class), classesOfLookup(Interface2.class));
   8.125 -    }
   8.126 -    public interface Interface1 {}
   8.127 -    public interface Interface2 {}
   8.128 -    @ServiceProviders({@ServiceProvider(service=Interface1.class), @ServiceProvider(service=Interface2.class)})
   8.129 -    public static class Multitasking implements Interface1, Interface2 {}
   8.130 -
   8.131 -    public void testErrorReporting() throws Exception {
   8.132 -        clearWorkDir();
   8.133 -        File src = new File(getWorkDir(), "src");
   8.134 -        File dest = new File(getWorkDir(), "classes");
   8.135 -        String xfaceName = Interface.class.getCanonicalName();
   8.136 -
   8.137 -        AnnotationProcessorTestUtils.makeSource(src, "p.C1",
   8.138 -                "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
   8.139 -                "public class C1 implements " + xfaceName + " {}");
   8.140 -        ByteArrayOutputStream baos = new ByteArrayOutputStream();
   8.141 -        assertTrue(AnnotationProcessorTestUtils.runJavac(src, "C1", dest, null, baos));
   8.142 -
   8.143 -        AnnotationProcessorTestUtils.makeSource(src, "p.C2",
   8.144 -                "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
   8.145 -                "class C2 implements " + xfaceName + " {}");
   8.146 -        baos = new ByteArrayOutputStream();
   8.147 -        assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C2", dest, null, baos));
   8.148 -        assertTrue(baos.toString(), baos.toString().contains("public"));
   8.149 -
   8.150 -        AnnotationProcessorTestUtils.makeSource(src, "p.C3",
   8.151 -                "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
   8.152 -                "public class C3 implements " + xfaceName + " {",
   8.153 -                "public C3(boolean x) {}",
   8.154 -                "}");
   8.155 -        baos = new ByteArrayOutputStream();
   8.156 -        assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C3", dest, null, baos));
   8.157 -        assertTrue(baos.toString(), baos.toString().contains("constructor"));
   8.158 -
   8.159 -        AnnotationProcessorTestUtils.makeSource(src, "p.C4",
   8.160 -                "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
   8.161 -                "public class C4 implements " + xfaceName + " {",
   8.162 -                "C4() {}",
   8.163 -                "}");
   8.164 -        baos = new ByteArrayOutputStream();
   8.165 -        assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C4", dest, null, baos));
   8.166 -        assertTrue(baos.toString(), baos.toString().contains("constructor"));
   8.167 -
   8.168 -        AnnotationProcessorTestUtils.makeSource(src, "p.C5",
   8.169 -                "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
   8.170 -                "public abstract class C5 implements " + xfaceName + " {}");
   8.171 -        baos = new ByteArrayOutputStream();
   8.172 -        assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C5", dest, null, baos));
   8.173 -        assertTrue(baos.toString(), baos.toString().contains("abstract"));
   8.174 -
   8.175 -        AnnotationProcessorTestUtils.makeSource(src, "p.C6",
   8.176 -                "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
   8.177 -                "public class C6 {}");
   8.178 -        baos = new ByteArrayOutputStream();
   8.179 -        assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C6", dest, null, baos));
   8.180 -        assertTrue(baos.toString(), baos.toString().contains("assignable"));
   8.181 -    }
   8.182 -
   8.183 -}
     9.1 --- a/openide.util/test/unit/src/org/openide/util/test/AnnotationProcessorTestUtils.java	Sat Oct 31 15:30:02 2009 +0100
     9.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.3 @@ -1,139 +0,0 @@
     9.4 -/*
     9.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     9.6 - *
     9.7 - * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
     9.8 - *
     9.9 - * The contents of this file are subject to the terms of either the GNU
    9.10 - * General Public License Version 2 only ("GPL") or the Common
    9.11 - * Development and Distribution License("CDDL") (collectively, the
    9.12 - * "License"). You may not use this file except in compliance with the
    9.13 - * License. You can obtain a copy of the License at
    9.14 - * http://www.netbeans.org/cddl-gplv2.html
    9.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    9.16 - * specific language governing permissions and limitations under the
    9.17 - * License.  When distributing the software, include this License Header
    9.18 - * Notice in each file and include the License file at
    9.19 - * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
    9.20 - * particular file as subject to the "Classpath" exception as provided
    9.21 - * by Sun in the GPL Version 2 section of the License file that
    9.22 - * accompanied this code. If applicable, add the following below the
    9.23 - * License Header, with the fields enclosed by brackets [] replaced by
    9.24 - * your own identifying information:
    9.25 - * "Portions Copyrighted [year] [name of copyright owner]"
    9.26 - *
    9.27 - * If you wish your version of this file to be governed by only the CDDL
    9.28 - * or only the GPL Version 2, indicate your decision by adding
    9.29 - * "[Contributor] elects to include this software in this distribution
    9.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
    9.31 - * single choice of license, a recipient has the option to distribute
    9.32 - * your version of this file under either the CDDL, the GPL Version 2 or
    9.33 - * to extend the choice of license to its licensees as provided above.
    9.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
    9.35 - * Version 2 license, then the option applies only if the new code is
    9.36 - * made subject to such option by the copyright holder.
    9.37 - *
    9.38 - * Contributor(s):
    9.39 - *
    9.40 - * Portions Copyrighted 2008 Sun Microsystems, Inc.
    9.41 - */
    9.42 -
    9.43 -package org.openide.util.test;
    9.44 -
    9.45 -import java.io.File;
    9.46 -import java.io.FileWriter;
    9.47 -import java.io.IOException;
    9.48 -import java.io.OutputStream;
    9.49 -import java.io.PrintWriter;
    9.50 -import java.io.Writer;
    9.51 -import java.util.ArrayList;
    9.52 -import java.util.List;
    9.53 -import java.util.regex.Pattern;
    9.54 -import javax.tools.JavaCompiler;
    9.55 -import javax.tools.ToolProvider;
    9.56 -import junit.framework.Assert;
    9.57 -
    9.58 -/**
    9.59 - * Utilities useful to those testing JSR 269 annotation processors.
    9.60 - * <p>If you just want to test that the output of the processor is correct,
    9.61 - * you do not need to do anything special:
    9.62 - * just use the annotation on some sample classes nested inside your unit test.
    9.63 - * They will be processed, and you check that your SPI loads them correctly.
    9.64 - * These utilities are useful mainly in case you want to check that the processor
    9.65 - * rejects erroneous sources, and that any messages it prints are reasonable;
    9.66 - * that it behaves correctly on incremental compilations; etc.
    9.67 - */
    9.68 -public class AnnotationProcessorTestUtils {
    9.69 -
    9.70 -    private AnnotationProcessorTestUtils() {}
    9.71 -
    9.72 -    /**
    9.73 -     * Create a source file.
    9.74 -     * @param dir source root
    9.75 -     * @param clazz a fully-qualified class name
    9.76 -     * @param content lines of text (skip package decl)
    9.77 -     */
    9.78 -    public static void makeSource(File dir, String clazz, String... content) throws IOException {
    9.79 -        File f = new File(dir, clazz.replace('.', File.separatorChar) + ".java");
    9.80 -        f.getParentFile().mkdirs();
    9.81 -        Writer w = new FileWriter(f);
    9.82 -        try {
    9.83 -            PrintWriter pw = new PrintWriter(w);
    9.84 -            String pkg = clazz.replaceFirst("\\.[^.]+$", "");
    9.85 -            if (!pkg.equals(clazz)) {
    9.86 -                pw.println("package " + pkg + ";");
    9.87 -            }
    9.88 -            for (String line : content) {
    9.89 -                pw.println(line);
    9.90 -            }
    9.91 -            pw.flush();
    9.92 -        } finally {
    9.93 -            w.close();
    9.94 -        }
    9.95 -    }
    9.96 -
    9.97 -    /**
    9.98 -     * Run the Java compiler.
    9.99 -     * (A JSR 199 implementation must be available.)
   9.100 -     * @param src a source root (runs javac on all *.java it finds matching {@code srcIncludes})
   9.101 -     * @param srcIncludes a pattern of source files names without path to compile (useful for testing incremental compiles), or null for all
   9.102 -     * @param dest a dest dir to compile classes to
   9.103 -     * @param cp classpath entries; if null, use Java classpath of test
   9.104 -     * @param stderr output stream to print messages to, or null for test console (i.e. do not capture)
   9.105 -     * @return true if compilation succeeded, false if it failed
   9.106 -     */
   9.107 -    public static boolean runJavac(File src, String srcIncludes, File dest, File[] cp, OutputStream stderr) {
   9.108 -        List<String> args = new ArrayList<String>();
   9.109 -        args.add("-classpath");
   9.110 -        if (cp != null) {
   9.111 -            StringBuffer b = new StringBuffer();
   9.112 -            for (File entry : cp) {
   9.113 -                b.append(File.pathSeparatorChar);
   9.114 -                b.append(entry.getAbsolutePath());
   9.115 -            }
   9.116 -            args.add(b.toString());
   9.117 -        } else {
   9.118 -            args.add(System.getProperty("java.class.path"));
   9.119 -        }
   9.120 -        args.add("-d");
   9.121 -        args.add(dest.getAbsolutePath());
   9.122 -        args.add("-sourcepath");
   9.123 -        args.add(src.getAbsolutePath());
   9.124 -        dest.mkdirs();
   9.125 -        scan(args, src, srcIncludes);
   9.126 -        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
   9.127 -        Assert.assertNotNull("no JSR 199 compiler impl found; try e.g.: " +
   9.128 -                "test.unit.run.cp.extra=${nb_all}/apisupport.harness/external/openjdk-javac-6-b12.jar", compiler);
   9.129 -        //System.err.println("running javac with args: " + args);
   9.130 -        return compiler.run(null, null, stderr, args.toArray(new String[args.size()])) == 0;
   9.131 -    }
   9.132 -    private static void scan(List<String> names, File f, String includes) {
   9.133 -        if (f.isDirectory()) {
   9.134 -            for (File kid : f.listFiles()) {
   9.135 -                scan(names, kid, includes);
   9.136 -            }
   9.137 -        } else if (f.getName().endsWith(".java") && (includes == null || Pattern.compile(includes).matcher(f.getName()).find())) {
   9.138 -            names.add(f.getAbsolutePath());
   9.139 -        }
   9.140 -    }
   9.141 -
   9.142 -}