From 78d959eb50b4606cc65e2f08cbf24d6441bc43bc Mon Sep 17 00:00:00 2001 From: Decebal Suiu Date: Thu, 10 Oct 2013 15:11:23 +0300 Subject: [PATCH] remove sezpoz dependency --- README.md | 6 +- .../fortsoft/pf4j/demo/hello/HelloPlugin.java | 2 +- pf4j/pom.xml | 20 ++- .../fortsoft/pf4j/DefaultExtensionFinder.java | 94 +++++++++++- .../fortsoft/pf4j/DefaultPluginManager.java | 2 +- .../main/java/ro/fortsoft/pf4j/Extension.java | 3 - .../ro/fortsoft/pf4j/ExtensionsIndexer.java | 135 ++++++++++++++++++ .../fortsoft/pf4j/SezpozExtensionFinder.java | 80 ----------- .../javax.annotation.processing.Processor | 1 + 9 files changed, 244 insertions(+), 99 deletions(-) create mode 100644 pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionsIndexer.java delete mode 100644 pf4j/src/main/java/ro/fortsoft/pf4j/SezpozExtensionFinder.java create mode 100644 pf4j/src/main/resources/META-INF/services/javax.annotation.processing.Processor diff --git a/README.md b/README.md index e11b750..15b7947 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Current build status: [![Build Status](https://buildhive.cloudbees.com/job/dece Features/Benefits ------------------- With PF4J you can easily transform a monolithic java application in a modular application. -PF4J is an open source (Apache license) lightweight (around 35KB) plugin framework for java, with minimal dependencies and very extensible (see PluginDescriptorFinder and ExtensionFinder). +PF4J is an open source (Apache license) lightweight (around 50KB) plugin framework for java, with minimal dependencies (only slf4j-api) and very extensible (see PluginDescriptorFinder and ExtensionFinder). No XML, only Java. @@ -102,7 +102,7 @@ You can define an extension point in your application using **ExtensionPoint** i } Another important internal component is **ExtensionFinder** that describes how the plugin manager discovers extensions for the extensions points. -**DefaultExtensionFinder** is a "link" to **SezpozExtensionFinder** that looks up extensions using **Extension** annotation. +**DefaultExtensionFinder** looks up extensions using **Extension** annotation. public class WelcomePlugin extends Plugin { @@ -169,7 +169,7 @@ You can retrieve the current runtime mode using `PluginManager.getRuntimeMode()` The DefaultPluginManager determines automatically the correct runtime mode and for DEVELOPMENT mode overrides some components(pluginsDirectory is __"../plugins"__, __PropertiesPluginDescriptorFinder__ as PluginDescriptorFinder, __DevelopmentPluginClasspath__ as PluginClassPath). Another advantage of DEVELOPMENT runtime mode is that you can execute some code lines only in this mode (for example more debug messages). -If you use maven as build manger, after each dependency modification in you plugin (maven module) you must run Maven>Update Project... +If you use maven as build manger, after each dependency modification in your plugin (maven module) you must run Maven>Update Project... For more details see the demo application. diff --git a/demo/plugins/plugin2/src/main/java/ro/fortsoft/pf4j/demo/hello/HelloPlugin.java b/demo/plugins/plugin2/src/main/java/ro/fortsoft/pf4j/demo/hello/HelloPlugin.java index d8963fc..7072e3d 100644 --- a/demo/plugins/plugin2/src/main/java/ro/fortsoft/pf4j/demo/hello/HelloPlugin.java +++ b/demo/plugins/plugin2/src/main/java/ro/fortsoft/pf4j/demo/hello/HelloPlugin.java @@ -38,7 +38,7 @@ public class HelloPlugin extends Plugin { System.out.println("HelloPlugin.stop()"); } - @Extension + @Extension(ordinal=1) public static class HelloGreeting implements Greeting { @Override diff --git a/pf4j/pom.xml b/pf4j/pom.xml index 0859a55..52e120b 100644 --- a/pf4j/pom.xml +++ b/pf4j/pom.xml @@ -13,14 +13,20 @@ jar PF4J Plugin Framework for Java - - - - net.java.sezpoz - sezpoz - 1.9 - + + + + org.apache.maven.plugins + maven-compiler-plugin + + -proc:none + + + + + + org.slf4j slf4j-api diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java index 66c1936..5ab989b 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java @@ -12,16 +12,102 @@ */ package ro.fortsoft.pf4j; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** - * The default implementation for ExtensionFinder. - * Now, this class it's a "link" to {@link ro.fortsoft.pf4j.SezpozExtensionFinder}. + * The default implementation for ExtensionFinder. + * All extensions declared in a plugin are indexed in a file "META-INF/extensions.idx". + * This class lookup extensions in all extensions index files "META-INF/extensions.idx". * * @author Decebal Suiu */ -public class DefaultExtensionFinder extends SezpozExtensionFinder { +public class DefaultExtensionFinder implements ExtensionFinder { + private static final Logger log = LoggerFactory.getLogger(DefaultExtensionFinder.class); + + private ClassLoader classLoader; + private volatile Set entries; + public DefaultExtensionFinder(ClassLoader classLoader) { - super(classLoader); + this.classLoader = classLoader; + } + + @Override + public List> find(Class type) { + log.debug("Find extensions for extension point {}", type.getName()); + List> result = new ArrayList>(); + if (entries == null) { + entries = readIndexFiles(); + } + + for (String entry : entries) { + try { + Class extensionType = classLoader.loadClass(entry); + log.debug("Checking extension type {}", extensionType.getName()); + if (type.isAssignableFrom(extensionType)) { + Object instance = extensionType.newInstance(); + if (instance != null) { + Extension extension = extensionType.getAnnotation(Extension.class); + log.debug("Added extension {} with ordinal {}", extensionType, extension.ordinal()); + result.add(new ExtensionWrapper(type.cast(instance), extension.ordinal())); + } + } else { + log.warn("{} is not an extension for extension point {}", extensionType, type.getName()); + } + } catch (ClassNotFoundException e) { + log.error(e.getMessage(), e); + } catch (InstantiationException e) { + log.error(e.getMessage(), e); + } catch (IllegalAccessException e) { + log.error(e.getMessage(), e); + } + } + + if (entries.isEmpty()) { + log.debug("No extensions found for extension point {}", type.getName()); + } else { + log.debug("Found {} extensions for extension point {}", entries.size(), type.getName()); + } + + // sort by "ordinal" property + Collections.sort(result); + + return result; } + private Set readIndexFiles() { + log.debug("Reading extensions index files"); + Set entries = new HashSet(); + + try { + Enumeration indexFiles = classLoader.getResources(ExtensionsIndexer.EXTENSIONS_RESOURCE); + while (indexFiles.hasMoreElements()) { + Reader reader = new InputStreamReader(indexFiles.nextElement().openStream(), "UTF-8"); + ExtensionsIndexer.readIndex(reader, entries); + } + } catch (IOException e) { + log.error(e.getMessage(), e); + } + + if (entries.isEmpty()) { + log.debug("No extensions found"); + } else { + log.debug("Found possible {} extensions", entries.size()); + } + + return entries; + } + } diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java index 30658cd..fcb839b 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java @@ -210,7 +210,7 @@ public class DefaultPluginManager implements PluginManager { filterList.add(new NotFileFilter(createHiddenPluginFilter())); FileFilter pluginsFilter = new AndFileFilter(filterList); File[] directories = pluginsDirectory.listFiles(pluginsFilter); - log.debug("Possible plugins: {}", Arrays.asList(directories)); + log.debug("Found possible {} plugins: {}", directories.length, Arrays.asList(directories)); if (directories.length == 0) { log.info("No plugins"); return; diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/Extension.java b/pf4j/src/main/java/ro/fortsoft/pf4j/Extension.java index f1b7cac..f2c01bd 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/Extension.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/Extension.java @@ -19,12 +19,9 @@ import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; -import net.java.sezpoz.Indexable; - /** * @author Decebal Suiu */ -@Indexable @Retention(RUNTIME) @Target(TYPE) @Documented diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionsIndexer.java b/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionsIndexer.java new file mode 100644 index 0000000..c4a8f40 --- /dev/null +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionsIndexer.java @@ -0,0 +1,135 @@ +/* + * Copyright 2013 Decebal Suiu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with + * the License. You may obtain a copy of the License in the LICENSE file, or 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 ro.fortsoft.pf4j; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic.Kind; +import javax.tools.FileObject; +import javax.tools.StandardLocation; + +/** + * @author Decebal Suiu + */ +public class ExtensionsIndexer extends AbstractProcessor { + + public static final String EXTENSIONS_RESOURCE = "META-INF/extensions.idx"; + + private List extensions = new ArrayList(); + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + @Override + public Set getSupportedAnnotationTypes() { + Set annotationTypes = new HashSet(); + annotationTypes.add(Extension.class.getName()); + + return annotationTypes; + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) { + return false; + } + + for (Element element : roundEnv.getElementsAnnotatedWith(Extension.class)) { + if (!(element instanceof TypeElement)) { + continue; + } + + TypeElement typeElement = (TypeElement) element; + String message = "Extension found in " + processingEnv.getElementUtils().getBinaryName(typeElement).toString(); + processingEnv.getMessager().printMessage(Kind.NOTE, message); + extensions.add(typeElement); + } + + /* + if (!roundEnv.processingOver()) { + return false; + } + */ + + write(); + + return false; +// return true; // no further processing of this annotation type + } + + private void write() { + Set entries = new HashSet(); + for (TypeElement typeElement : extensions) { + entries.add(processingEnv.getElementUtils().getBinaryName(typeElement).toString()); + } + + read(entries); // read old entries + write(entries); // write entries + } + + private void write(Set entries) { + try { + FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", EXTENSIONS_RESOURCE); + Writer writer = file.openWriter(); + for (String entry : entries) { + writer.write(entry); + writer.write("\n"); + } + writer.close(); + } catch (FileNotFoundException e) { + // it's the first time, create the file + } catch (IOException e) { + processingEnv.getMessager().printMessage(Kind.ERROR, e.toString()); + } + } + + private void read(Set entries) { + try { + FileObject file = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", EXTENSIONS_RESOURCE); + readIndex(file.openReader(true), entries); + } catch (FileNotFoundException e) { + } catch (IOException e) { + // thrown by Eclipse JDT when not found + } catch (UnsupportedOperationException e) { + // java6 does not support reading old index files + } + } + + public static void readIndex(Reader reader, Set entries) throws IOException { + BufferedReader bufferedReader = new BufferedReader(reader); + + String line; + while ((line = bufferedReader.readLine()) != null) { + entries.add(line); + } + + reader.close(); + } + +} + \ No newline at end of file diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/SezpozExtensionFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/SezpozExtensionFinder.java deleted file mode 100644 index 3f5014c..0000000 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/SezpozExtensionFinder.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2012 Decebal Suiu - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with - * the License. You may obtain a copy of the License in the LICENSE file, or 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 ro.fortsoft.pf4j; - -import java.lang.reflect.AnnotatedElement; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.java.sezpoz.Index; -import net.java.sezpoz.IndexItem; - -/** - * Using Sezpoz(http://sezpoz.java.net/) for extensions discovery. - * - * @author Decebal Suiu - */ -public class SezpozExtensionFinder implements ExtensionFinder { - - private static final Logger log = LoggerFactory.getLogger(SezpozExtensionFinder.class); - - private volatile List> indices; - private ClassLoader classLoader; - - public SezpozExtensionFinder(ClassLoader classLoader) { - this.classLoader = classLoader; - } - - @Override - public List> find(Class type) { - log.debug("Find extensions for {}", type); - List> result = new ArrayList>(); - getIndices(); -// System.out.println("indices = "+ indices); - for (IndexItem item : indices) { - try { - AnnotatedElement element = item.element(); - Class extensionType = (Class) element; - log.debug("Checking extension type {}", extensionType); - if (type.isAssignableFrom(extensionType)) { - Object instance = item.instance(); - if (instance != null) { - log.debug("Added extension {}", extensionType); - result.add(new ExtensionWrapper(type.cast(instance), item.annotation().ordinal())); - } - } - } catch (InstantiationException e) { - log.error(e.getMessage(), e); - } - } - - return result; - } - - private List> getIndices() { - if (indices == null) { - indices = new ArrayList>(); - Iterator> it = Index.load(Extension.class, Object.class, classLoader).iterator(); - while (it.hasNext()) { - indices.add(it.next()); - } - } - - return indices; - } - -} diff --git a/pf4j/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/pf4j/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 0000000..a944d7c --- /dev/null +++ b/pf4j/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +ro.fortsoft.pf4j.ExtensionsIndexer -- 2.39.5