maven-service-plugin
diff -N pom.xml
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ pom.xml 28 Aug 2008 20:21:35 -0000 1.1
@@ -0,0 +1,41 @@
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.lcsim</groupId>
+ <artifactId>maven-service-plugin</artifactId>
+ <packaging>maven-plugin</packaging>
+ <version>1.0-SNAPSHOT</version>
+ <name>Generates a services file by scanning over a directory containing Java classes.</name>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ <version>2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>1.3.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-artifact</artifactId>
+ <version>2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-project</artifactId>
+ <version>2.0</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
maven-service-plugin/src/main/java/org/lcsim
diff -N MavenServicePluginMojo.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ MavenServicePluginMojo.java 28 Aug 2008 20:21:36 -0000 1.1
@@ -0,0 +1,226 @@
+package org.lcsim;
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.commons.io.DirectoryWalker;
+import org.apache.maven.project.MavenProject;
+import java.io.FileFilter;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.net.URLClassLoader;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.util.StringTokenizer;
+import java.io.Writer;
+import java.io.FileWriter;
+import java.io.BufferedWriter;
+
+/**
+ * A Maven plugin that generates a services file by walking a directory looking for
+ * subclasses of a specified service class.
+ *
+ * @goal generate-service-file
+ */
+public class MavenServicePluginMojo extends AbstractMojo
+{
+ /**
+ * Directory to scan for classes implementing service, which defaults to project's build output directory.
+ *
+ * @parameter expression="scanDir=${project.build.outputDirectory}"
+ */
+ private String scanDir;
+
+ /**
+ * Fully qualified name of super class which corresponds to the service, with no default.
+ *
+ * @parameter expression="className"
+ */
+ private String className;
+
+ /**
+ * Output directory where services file is placed, which defaults to standard resources area.
+ *
+ * @parameter expression="outputDirectory=${basedir}/src/main/resources/META-INF/services"
+ */
+ private String outputDirectory;
+
+ /**
+ * File containing full classpath that should be used by the services search.
+ * Generate with <code>mvn dependency:build-classpath</code> saved to <code>target/classpath.txt</code>.
+ * @parameter expression="classPathFile"
+ */
+ private String classPathFile;
+
+ /**
+ * The ClassLoader that will be used when instantiating classes to test against.
+ */
+ private MyURLClassLoader loader;
+
+ /**
+ * The service class that will be compared against.
+ */
+ private Class serviceClass;
+
+ /**
+ * Setup the custom ClassLoader with the full class path.
+ * @throws Exception
+ */
+ private void setupClassLoader() throws Exception
+ {
+ BufferedReader input = new BufferedReader(new FileReader(new File(classPathFile)));
+ String line = null;
+ List<URL> urls = new ArrayList<URL>();
+ while (( line = input.readLine()) != null)
+ {
+ StringTokenizer tok = new StringTokenizer(line,":");
+ while(tok.hasMoreTokens())
+ {
+ String nextTok = tok.nextToken();
+ urls.add((new File(nextTok)).toURL());
+ }
+ }
+ URL urlsArr[] = new URL[urls.size()];
+ for (int i=0; i<urls.size(); i++)
+ {
+ urlsArr[i] = urls.get(i);
+ }
+ loader = new MyURLClassLoader(urlsArr);
+ }
+
+ public void execute() throws MojoExecutionException
+ {
+ if (scanDir == null) throw new RuntimeException("scanDir not set");
+ if (className == null) throw new RuntimeException("className not set");
+ if (outputDirectory == null) throw new RuntimeException("outputDirectory not set");
+ if (classPathFile == null) throw new RuntimeException("classPathFile not set");
+
+ try {
+ setupClassLoader();
+ }
+ catch (Exception x)
+ {
+ throw new RuntimeException(x);
+ }
+
+ try {
+ serviceClass = loader.loadClass(className);
+ }
+ catch (Exception x)
+ {
+ throw new RuntimeException(x);
+ }
+
+ // Walk the start directory for subclasses of the service class.
+ ServiceDirWalker dirWalk = new ServiceDirWalker(new ClassFileFilter(), -1);
+ Collection drivers = new ArrayList();
+ dirWalk.walkIt(new File(scanDir), drivers);
+
+ // Add results of search to services file.
+ try {
+ (new File(outputDirectory)).mkdirs();
+ File outfile = new File(outputDirectory + File.separator + className);
+
+ BufferedWriter output = new BufferedWriter(new FileWriter(outfile));
+
+ for (Object o : drivers)
+ {
+ Class klass = (Class)o;
+ output.write(klass.getName());
+ output.newLine();
+ }
+ output.close();
+
+ getLog().info("Wrote services file to " + outfile.toString());
+ }
+ catch (Exception x)
+ {
+ throw new RuntimeException(x);
+ }
+ }
+
+ class ServiceDirWalker extends DirectoryWalker
+ {
+ File baseDir;
+
+ public ServiceDirWalker(FileFilter filter, int depth)
+ {
+ super(filter, depth);
+ }
+
+ public void handleDirectoryStart(File directory, int depth, Collection results)
+ {
+ try
+ {
+ loader.addURL(directory.toURL());
+ }
+ catch (Exception x)
+ {
+ throw new RuntimeException(x);
+ }
+ }
+
+ public void handleFile(File file, int depth, Collection results)
+ {
+ try {
+ // Load the class.
+ Class klass =
+ loader.loadClass(file.getCanonicalPath().replace(baseDir.getCanonicalPath(),"").replace(".class","").replace("/",".").substring(1));
+ // Check if service class is a superclass.
+ if (serviceClass.isAssignableFrom(klass))
+ {
+ // Add to results.
+ results.add(klass);
+ }
+ }
+ catch (Exception x)
+ {
+ throw new RuntimeException(x);
+ }
+ }
+
+ public void walkIt(File f, Collection c)
+ {
+ baseDir = f;
+ try
+ {
+ super.walk(f, c);
+ }
+ catch(IOException x)
+ {
+ throw new RuntimeException(x);
+ }
+ }
+ }
+
+ class MyURLClassLoader extends URLClassLoader
+ {
+ public MyURLClassLoader(URL urls[])
+ {
+ super(urls, Thread.currentThread().getContextClassLoader());
+ }
+
+ public void addURL(URL url)
+ {
+ super.addURL(url);
+ }
+ }
+
+ class ClassFileFilter implements FileFilter
+ {
+ public boolean accept(File pathname)
+ {
+ if (pathname.isDirectory()) return true;
+ try {
+ if (pathname.getCanonicalPath().endsWith(".class")) return true; else return false;
+ }
+ catch (Exception x)
+ {
+ throw new RuntimeException(x);
+ }
+ }
+ }
+}