pax_global_header00006660000000000000000000000064120451705120014507gustar00rootroot0000000000000052 comment=1892b69521717ec472ec1c990ecb3fe8ab02655d libspi-java-0.2.4/000077500000000000000000000000001204517051200137135ustar00rootroot00000000000000libspi-java-0.2.4/src/000077500000000000000000000000001204517051200145025ustar00rootroot00000000000000libspi-java-0.2.4/src/META-INF/000077500000000000000000000000001204517051200156425ustar00rootroot00000000000000libspi-java-0.2.4/src/META-INF/services/000077500000000000000000000000001204517051200174655ustar00rootroot00000000000000libspi-java-0.2.4/src/META-INF/services/javax.annotation.processing.Processor000066400000000000000000000000471204517051200270240ustar00rootroot00000000000000org.mangosdk.spi.processor.SpiProcessorlibspi-java-0.2.4/src/org/000077500000000000000000000000001204517051200152715ustar00rootroot00000000000000libspi-java-0.2.4/src/org/mangosdk/000077500000000000000000000000001204517051200170745ustar00rootroot00000000000000libspi-java-0.2.4/src/org/mangosdk/spi/000077500000000000000000000000001204517051200176675ustar00rootroot00000000000000libspi-java-0.2.4/src/org/mangosdk/spi/ProviderFor.java000066400000000000000000000016771204517051200230060ustar00rootroot00000000000000/* Copyright 2008 TOPdesk, the Netherlands Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.mangosdk.spi; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface ProviderFor { Class[] value(); } libspi-java-0.2.4/src/org/mangosdk/spi/processor/000077500000000000000000000000001204517051200217065ustar00rootroot00000000000000libspi-java-0.2.4/src/org/mangosdk/spi/processor/CheckResult.java000066400000000000000000000022311204517051200247630ustar00rootroot00000000000000/* Copyright 2008 TOPdesk, the Netherlands Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.mangosdk.spi.processor; public final class CheckResult { public static final CheckResult OK = new CheckResult(null); private final boolean error; private final String message; public static CheckResult valueOf(String message) { if (message == null) { throw new NullPointerException("message"); } return new CheckResult(message); } private CheckResult(String message) { error = (message != null); this.message = message; } public boolean isError() { return error; } public String getMessage() { return message; } }libspi-java-0.2.4/src/org/mangosdk/spi/processor/Collector.java000066400000000000000000000042401204517051200244770ustar00rootroot00000000000000/* Copyright 2008 TOPdesk, the Netherlands Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.mangosdk.spi.processor; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; final class Collector { private final Map services = new HashMap(); private final List removed = new ArrayList(); private final Initializer initializer; private final Logger logger; Collector(Initializer initializer, Logger logger) { this.initializer = initializer; this.logger = logger; } Service getService(String service) { if (service == null) { throw new NullPointerException("service"); } if (!services.containsKey(service)) { Service newService = new Service(logger, service); CharSequence initialData = initializer.initialData(service); if (initialData != null) { newService.fromProviderNamesList(initialData.toString()); for (String provider : removed) { newService.removeProvider(provider); } } services.put(service, newService); } return services.get(service); } Collection services() { return Collections.unmodifiableMap(services).values(); } void removeProvider(String provider) { if (provider == null) { throw new NullPointerException("provider"); } logger.note(LogLocation.LOG_FILE, "Removing " + provider); removed.add(provider); for (Service service : services.values()) { service.removeProvider(provider); } } @Override public String toString() { return services.values().toString(); } } libspi-java-0.2.4/src/org/mangosdk/spi/processor/Initializer.java000066400000000000000000000013041204517051200250320ustar00rootroot00000000000000/* Copyright 2008 TOPdesk, the Netherlands Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.mangosdk.spi.processor; public interface Initializer { CharSequence initialData(String serviceName); }libspi-java-0.2.4/src/org/mangosdk/spi/processor/LogLocation.java000066400000000000000000000003521204517051200247630ustar00rootroot00000000000000package org.mangosdk.spi.processor; public enum LogLocation { MESSAGER, LOG_FILE, BOTH; public boolean toMessager() { return this != LOG_FILE; } public boolean toLogFile() { return this != MESSAGER; } } libspi-java-0.2.4/src/org/mangosdk/spi/processor/Logger.java000066400000000000000000000014251204517051200237720ustar00rootroot00000000000000/* Copyright 2008 TOPdesk, the Netherlands Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.mangosdk.spi.processor; public interface Logger { void note(LogLocation location, String message); void warning(LogLocation location, String message); String getFileContent(); } libspi-java-0.2.4/src/org/mangosdk/spi/processor/Options.java000066400000000000000000000072111204517051200242050ustar00rootroot00000000000000/* Copyright 2008 TOPdesk, the Netherlands Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.mangosdk.spi.processor; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; public final class Options { static final String SPI_DISABLED_OPTION = "spi_disabled"; static final String SPI_DIR_OPTION = "spi_dir"; static final String SPI_LOG_OPTION = "spi_log"; static final String SPI_VERBOSE_OPTION = "spi_verbose"; private final List warnings = new ArrayList(); private final boolean disabled; private final boolean log; private final boolean verbose; private final String dir; private final String report; public Options(Map values) { disabled = getBooleanParameter(values, SPI_DISABLED_OPTION); log = getBooleanParameter(values, SPI_LOG_OPTION); verbose = getBooleanParameter(values, SPI_VERBOSE_OPTION); dir = cleanPath(values.get(SPI_DIR_OPTION)); report = createReport(values); } public boolean disabled() { return disabled; } public boolean verbose() { return verbose; } public boolean logging() { return log; } public String dir() { return dir; } public Collection getWarnings() { return Collections.unmodifiableCollection(warnings); } public String report() { return report; } private String createReport(Map values) { StringBuilder result = new StringBuilder(); result .append("Initializing Annotation Processor ") .append(SpiProcessor.NAME) .append("\nUsed options:\n"); writeOption(result, values, SPI_DISABLED_OPTION); writeOption(result, values, SPI_VERBOSE_OPTION); writeOption(result, values, SPI_LOG_OPTION); writeOption(result, values, SPI_DIR_OPTION); return result.toString(); } private static String cleanPath(String path) { if (path == null) { return ""; } String backSlashless = path.replace("\\", "/"); if (backSlashless.endsWith("/")) { return backSlashless; } return backSlashless + "/"; } private boolean getBooleanParameter(Map values, String optionName) { if (!values.containsKey(optionName)) { return false; } String optionValue = values.get(optionName); if (optionValue == null || "true".equalsIgnoreCase(optionValue)) { return true; } if (!"false".equalsIgnoreCase(optionValue)) { warnings.add("Unrecognized value for parameter '" + optionName + "'. Found '" + optionValue + "'. Legal values: 'true', 'false'."); } return false; } private void writeOption(StringBuilder result, Map values, String optionName) { result .append(" - ") .append(optionName) .append(": ") .append(optionMessage(values, optionName)) .append("\n"); } private String optionMessage(Map values, String optionName) { if (values.containsKey(optionName)) { String optionValue = values.get(optionName); if (optionValue == null) { return "''"; } return "'" + optionValue + "'"; } return "missing"; } } libspi-java-0.2.4/src/org/mangosdk/spi/processor/Persistence.java000066400000000000000000000101551204517051200250370ustar00rootroot00000000000000/* Copyright 2008 TOPdesk, the Netherlands Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.mangosdk.spi.processor; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.Writer; import java.net.URI; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Locale; import javax.annotation.processing.Filer; import javax.tools.FileObject; import javax.tools.StandardLocation; class Persistence { private final String name; private final String path; final Filer filer; final Logger logger; Persistence(String name, String root, Filer filer, Logger logger) { this.name = name; this.logger = logger; this.path = root + "META-INF/services/"; this.filer = filer; } void writeLog() { try { String logContent = logger.getFileContent(); if (logContent != null && !logContent.isEmpty()) { write("log" + System.currentTimeMillis() + ".log", logContent); } } catch (IOException e) { e.printStackTrace(); } } Collection tryFind() { Collection fileList; File dir = determineOutputLocation(); if (dir == null) { fileList = Collections.emptyList(); } else { fileList = listDiscoveredServiceFiles(dir.listFiles(ServiceFileFilter.INSTANCE)); } return fileList; } private Collection listDiscoveredServiceFiles(File[] list) { if (list == null) { return Collections.emptyList(); } List result = new ArrayList(); for (File file : list) { String fileName = file.getName(); logger.note(LogLocation.LOG_FILE, "Discovered " + fileName); result.add(fileName); } return result; } private File determineOutputLocation() { FileObject resource; try { resource = filer.getResource(StandardLocation.CLASS_OUTPUT, "", path + "locator"); } catch (FileNotFoundException e) { // Could happen return null; } catch (IOException e) { logger.note(LogLocation.MESSAGER, "IOException while determining output location: " + e.getMessage()); // System.out.println(e); return null; } catch (IllegalArgumentException e) { // Happens when the path is invalid. For instance absolute or relative to a path // not part of the class output folder. // // Due to a bug in javac for Linux, this also occurs when no output path is specified // for javac using the -d parameter. // See http://forums.sun.com/thread.jspa?threadID=5240999&tstart=45 // and http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6647996 // logger.toConsole("IllegalArgumentException: " + e.getMessage()); return null; } URI uri = resource.toUri(); if (uri.isAbsolute()) { return new File(uri).getParentFile(); } return new File(uri.toString()).getParentFile(); } Initializer getInitializer() { return new ServiceFileInitializer(filer, path, logger); } void write(String serviceName, String value) throws IOException { logger.note(LogLocation.BOTH, "Generating file '" + path + serviceName + "'"); FileObject output = filer.createResource(StandardLocation.CLASS_OUTPUT, "", path + serviceName); Writer writer = output.openWriter(); try { writer.write("# Generated by " + name + "\n"); writer.write("# " + new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US).format(new Date()) + "\n"); writer.write(value); } finally { try { writer.close(); } catch (IOException e) { // Ignore } } } } libspi-java-0.2.4/src/org/mangosdk/spi/processor/ProcessorLogger.java000066400000000000000000000051521204517051200256730ustar00rootroot00000000000000/* Copyright 2008 TOPdesk, the Netherlands Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.mangosdk.spi.processor; import java.io.PrintWriter; import java.io.StringWriter; import javax.annotation.processing.Messager; import javax.tools.Diagnostic.Kind; public final class ProcessorLogger implements Logger { private final Messager messager; private final Options options; private final StringBuffer logContent = new StringBuffer(); public ProcessorLogger(Messager messager, Options options) { if (messager == null) { throw new NullPointerException("messager"); } if (options == null) { throw new NullPointerException("options"); } this.messager = messager; this.options = options; note(LogLocation.MESSAGER, options.report()); for (String warning : options.getWarnings()) { warning(LogLocation.BOTH, warning); } } @Override public void note(LogLocation location, String message) { if (location == null) { throw new NullPointerException("location"); } if (message == null) { throw new NullPointerException("message"); } if (options.verbose() && location.toMessager()) { messager.printMessage(Kind.NOTE, message); } if (options.logging() && location.toLogFile()) { logContent.append(message).append("\n"); } } @Override public void warning(LogLocation location, String message) { if (location == null) { throw new NullPointerException("location"); } if (message == null) { throw new NullPointerException("message"); } if (location.toMessager()) { messager.printMessage(Kind.WARNING, message); } if (options.logging() && location.toLogFile()) { logContent.append("warning: ").append(message).append("\n"); } } @Override public String getFileContent() { return logContent.toString(); } public static String exceptionToString(Exception exception) { if (exception == null) { throw new NullPointerException("exception"); } StringWriter out = new StringWriter(); exception.printStackTrace(new PrintWriter(out)); return out.toString(); } } libspi-java-0.2.4/src/org/mangosdk/spi/processor/Service.java000066400000000000000000000047771204517051200241700ustar00rootroot00000000000000/* Copyright 2008 TOPdesk, the Netherlands Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.mangosdk.spi.processor; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; final class Service { private final Logger logger; private final String serviceName; private final Set providers = new HashSet(); Service(Logger logger, String name) { if (logger == null) { throw new NullPointerException("logger"); } if (name == null) { throw new NullPointerException("name"); } this.logger = logger; logger.note(LogLocation.LOG_FILE, "Creating " + name); this.serviceName = name; } void addProvider(String provider) { if (provider == null) { throw new NullPointerException("provider"); } logger.note(LogLocation.LOG_FILE, "Adding " + provider + " to " + serviceName); providers.add(provider); } boolean contains(String provider) { return providers.contains(provider); } boolean removeProvider(String provider) { if (providers.remove(provider)) { logger.note(LogLocation.LOG_FILE, "Removing " + provider + " from " + serviceName); return true; } return false; } String getName() { return serviceName; } String toProviderNamesList() { StringBuilder sb = new StringBuilder(); List names = new ArrayList(providers); Collections.sort(names); for (String provider : names) { sb.append(provider).append("\n"); } return sb.toString(); } void fromProviderNamesList(String input) { if (input == null) { throw new NullPointerException("input"); } String[] lines = input.split("\\n"); for (String line : lines) { String[] content = line.split("#"); if (content.length > 0) { String trimmed = content[0].trim(); if (trimmed.length() > 0) { addProvider(trimmed); } } } } @Override public String toString() { return serviceName + "=" + providers; } }libspi-java-0.2.4/src/org/mangosdk/spi/processor/ServiceFileFilter.java000066400000000000000000000022661204517051200261250ustar00rootroot00000000000000/* Copyright 2008 TOPdesk, the Netherlands Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.mangosdk.spi.processor; import java.io.File; import java.io.FileFilter; import java.io.Serializable; public final class ServiceFileFilter implements FileFilter, Serializable { private static final long serialVersionUID = 1L; public static final FileFilter INSTANCE = new ServiceFileFilter(); private ServiceFileFilter() { if (INSTANCE != null) { throw new IllegalStateException("Already instantiated"); } } @Override public boolean accept(File file) { if (!file.isFile()) { return false; } return !file.getName().toLowerCase().endsWith(".log"); } }libspi-java-0.2.4/src/org/mangosdk/spi/processor/ServiceFileInitializer.java000066400000000000000000000053461204517051200271650ustar00rootroot00000000000000/* Copyright 2008 TOPdesk, the Netherlands Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.mangosdk.spi.processor; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; import javax.annotation.processing.Filer; import javax.tools.FileObject; import javax.tools.StandardLocation; final class ServiceFileInitializer implements Initializer { private final Filer filer; private final String path; private final Logger logger; ServiceFileInitializer(Filer filer, String path, Logger logger) { this.filer = filer; this.path = path; this.logger = logger; } @Override public CharSequence initialData(String serviceName) { try { FileObject resource = filer.getResource(StandardLocation.CLASS_OUTPUT, "", path + serviceName); CharSequence result; try { // Eclipse can't handle the getCharContent // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=246089 // 2008-09-12 RoelS: I've posted a patch file result = tryWithReader(resource); } catch (FileNotFoundException e) { // Could happen return null; } catch (IOException e) { logger.note(LogLocation.MESSAGER, "Eclipse gave an IOException: " + e.getMessage()); return null; } catch (Exception other) { try { // Javac can't handle the openReader // Filed as a bug at bugs.sun.com and recieved a review ID: 1339738 result = resource.getCharContent(true); } catch (FileNotFoundException e) { // Could happen return null; } catch (IOException e) { logger.note(LogLocation.MESSAGER, "Javac gave an IOException: " + e.getMessage()); return null; } } return result; } catch (IOException e) { logger.note(LogLocation.MESSAGER, "getResource gave an IOException: " + e.getMessage()); } return null; } private CharSequence tryWithReader(FileObject resource) throws IOException { StringBuilder sb = new StringBuilder(); BufferedReader reader = new BufferedReader(resource.openReader(true)); try { String line; while ((line = reader.readLine()) != null) { sb.append(line).append("\n"); } } finally { reader.close(); } return sb; } }libspi-java-0.2.4/src/org/mangosdk/spi/processor/SpiProcessor.java000066400000000000000000000244461204517051200252160ustar00rootroot00000000000000/* Copyright 2008 TOPdesk, the Netherlands Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.mangosdk.spi.processor; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedOptions; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Types; import javax.tools.FileObject; import javax.tools.StandardLocation; import javax.tools.Diagnostic.Kind; import org.mangosdk.spi.ProviderFor; @SupportedAnnotationTypes("*") @SupportedSourceVersion(SourceVersion.RELEASE_6) @SupportedOptions({Options.SPI_DIR_OPTION, Options.SPI_LOG_OPTION, Options.SPI_VERBOSE_OPTION, Options.SPI_DISABLED_OPTION}) public class SpiProcessor extends AbstractProcessor { public static final String NAME = SpiProcessor.class.getName() + " (" + Version.VERSION + ")"; private Options options; private Logger logger; private Persistence persistence; private Collector data; @Override public synchronized void init(ProcessingEnvironment environment) { super.init(environment); try { initialize(); } catch (Exception e) { environment.getMessager().printMessage(Kind.ERROR, ProcessorLogger.exceptionToString(e)); } } private void initialize() { options = new Options(processingEnv.getOptions()); if (options.disabled()) { return; } logger = new ProcessorLogger(processingEnv.getMessager(), options); checkCompatibility(); persistence = new Persistence(NAME, options.dir(), processingEnv.getFiler(), logger); data = new Collector(persistence.getInitializer(), logger); // Initialize if possible for (String serviceName : persistence.tryFind()) { data.getService(serviceName); } } @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { if (options.disabled()) { return false; } long start = System.currentTimeMillis(); logger.note(LogLocation.LOG_FILE, "Starting round with " + roundEnv.getRootElements().size() + " elements"); removeStaleData(roundEnv); handleAnnotations(roundEnv); long end = System.currentTimeMillis(); logger.note(LogLocation.LOG_FILE, "Ending round in " + (end - start) + " milliseconds"); if (roundEnv.processingOver()) { writeData(); } return false; } private void writeData() { logger.note(LogLocation.LOG_FILE, "Writing output"); for (Service service : data.services()) { try { persistence.write(service.getName(), service.toProviderNamesList()); } catch (IOException e) { processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage()); } } persistence.writeLog(); } private void removeStaleData(RoundEnvironment roundEnv) { for (Element e : roundEnv.getRootElements()) { if (e instanceof TypeElement) { TypeElement currentClass = (TypeElement)e; data.removeProvider(createProperQualifiedName(currentClass)); } } } private void handleAnnotations(RoundEnvironment roundEnv) { Set elements = roundEnv.getElementsAnnotatedWith(ProviderFor.class); for (Element e : elements) { handleElement(e); } } private void handleElement(Element e) { TypeElement currentClass = (TypeElement)e; CheckResult checkResult = checkCurrentClass(currentClass); if (checkResult.isError()) { reportError(currentClass, checkResult); return; } for (TypeElement service : findServices(currentClass)) { CheckResult implementationResult = isImplementation(currentClass, service); if (implementationResult.isError()) { reportError(currentClass, implementationResult); } else { register(createProperQualifiedName(service), currentClass); } } } private void reportError(TypeElement element, CheckResult result) { processingEnv.getMessager().printMessage(Kind.ERROR, element.getSimpleName() + " " + result.getMessage(), element); } private CheckResult checkCurrentClass(TypeElement currentClass) { if (currentClass.getKind() != ElementKind.CLASS) { return CheckResult.valueOf("is not a class"); } if (!currentClass.getModifiers().contains(Modifier.PUBLIC)) { return CheckResult.valueOf("is not a public class"); } if (!isStaticClass(currentClass)) { return CheckResult.valueOf("is not a static class"); } if (!hasCorrectConstructor(currentClass)) { return CheckResult.valueOf("has no public no-args constructor"); } return CheckResult.OK; } private boolean hasCorrectConstructor(TypeElement currentClass) { List constructors = ElementFilter.constructorsIn(currentClass.getEnclosedElements()); for (ExecutableElement constructor : constructors) { if (constructor.getModifiers().contains(Modifier.PUBLIC) && constructor.getParameters().isEmpty()) { return true; } } return false; } private boolean isStaticClass(TypeElement element) { if (element.getEnclosingElement().getKind() != ElementKind.CLASS) { return true; } return element.getModifiers().contains(Modifier.STATIC); } private CheckResult isImplementation(TypeElement currentClass, TypeElement provider) { if (isAssignable(currentClass.asType(), provider.asType())) { return CheckResult.OK; } String message; if (provider.getKind() == ElementKind.INTERFACE) { message = "does not implement"; } else { message = "does not extend"; } return CheckResult.valueOf(message + " " + provider.getQualifiedName()); } private boolean isAssignable(TypeMirror currentClass, TypeMirror provider) { Types typeUtils = processingEnv.getTypeUtils(); if (typeUtils.isAssignable(typeUtils.erasure(currentClass), typeUtils.erasure(provider))) { return true; } for (TypeMirror superType : typeUtils.directSupertypes(currentClass)) { if (isAssignable(superType, provider)) { return true; } } return false; } private List findServices(TypeElement classElement) { List services = new ArrayList(); for (AnnotationMirror annotation : findAnnotationMirrors(classElement, ProviderFor.class.getName())) { for (AnnotationValue value : findValue(annotation)) { services.add(toElement(value)); } } return services; } private static List findAnnotationMirrors(TypeElement element, String lookingFor) { List annotationMirrors = new ArrayList(); for (AnnotationMirror annotation : element.getAnnotationMirrors()) { if (annotationMirrorMatches(annotation, lookingFor)) { annotationMirrors.add(annotation); } } return annotationMirrors; } private static boolean annotationMirrorMatches(AnnotationMirror annotation, String lookingFor) { Name qualifiedName = ((TypeElement)(annotation.getAnnotationType()).asElement()).getQualifiedName(); return qualifiedName.contentEquals(lookingFor); } private TypeElement toElement(AnnotationValue value) { return (TypeElement)((DeclaredType)((TypeMirror)value.getValue())).asElement(); } private Collection findValue(AnnotationMirror mirror) { Map elementValues = mirror.getElementValues(); for (Map.Entry entry : elementValues.entrySet()) { if (entry.getKey().getSimpleName().contentEquals("value")) { @SuppressWarnings("unchecked") Collection result = (Collection)entry.getValue().getValue(); return result; } } throw new IllegalStateException("No value found in element"); } private void register(String serviceName, TypeElement provider) { data.getService(serviceName).addProvider(createProperQualifiedName(provider)); } private String createProperQualifiedName(TypeElement provider) { return processingEnv.getElementUtils().getBinaryName(provider).toString(); } private void checkCompatibility() { logger.note(LogLocation.MESSAGER, "Testing for compatability options"); try { checkJavacOnLinux(); } catch (Exception e) { warning(ProcessorLogger.exceptionToString(e)); } logger.note(LogLocation.MESSAGER, "Testing complete"); } private void checkJavacOnLinux() { try { FileObject resource = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", options.dir() + "a/b"); if (resource.toUri().toString().equals("b")) { warning("Output files will be placed in the root of the output folder.\n This is a known bug in the java compiler on Linux.\n Please use the -d compiler option to circumvent this problem.\n See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6647996 for more information."); } } catch (IOException e) { warning("IOException during testing Javac on Linux"); } } private void warning(String message) { processingEnv.getMessager().printMessage(Kind.WARNING, message); } }libspi-java-0.2.4/src/org/mangosdk/spi/processor/Version.java000066400000000000000000000016561204517051200242060ustar00rootroot00000000000000/* Copyright 2008 TOPdesk, the Netherlands Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.mangosdk.spi.processor; public final class Version { public static final String VERSION = "0.2.4"; public static void main(String... args) { System.out.print(VERSION); } private Version() { // Prevent instantiation throw new UnsupportedOperationException("Cannot instantiate " + Version.class.getName()); } }