|
From: <fd...@us...> - 2008-08-31 18:12:27
|
Revision: 4522
http://jnode.svn.sourceforge.net/jnode/?rev=4522&view=rev
Author: fduminy
Date: 2008-08-31 18:12:16 +0000 (Sun, 31 Aug 2008)
Log Message:
-----------
jar packager tool :
- refactored for better separation with regular build
- now, each sub directory can be packaged as a jnode plugin, which will be automatically unzipped to a directory
Modified Paths:
--------------
trunk/all/build.xml
trunk/builder/build.xml
trunk/builder/src/builder/org/jnode/build/AbstractPluginsTask.java
trunk/builder/src/builder/org/jnode/build/InitJarBuilder.java
trunk/builder/src/builder/org/jnode/build/InitJarsBuilder.java
trunk/builder/src/builder/org/jnode/build/PluginList.java
trunk/builder/src/builder/org/jnode/build/PluginTask.java
Added Paths:
-----------
trunk/builder/src/builder/org/jnode/build/packager/
trunk/builder/src/builder/org/jnode/build/packager/PackagerTask.java
trunk/builder/src/builder/org/jnode/build/packager/PluginBuilder.java
trunk/builder/src/builder/org/jnode/build/packager/PluginListInsertor.java
trunk/builder/src/builder/org/jnode/build/packager/plugins.properties
Modified: trunk/all/build.xml
===================================================================
--- trunk/all/build.xml 2008-08-31 16:58:22 UTC (rev 4521)
+++ trunk/all/build.xml 2008-08-31 18:12:16 UTC (rev 4522)
@@ -223,8 +223,9 @@
<target name="assemble-plugins" depends="assemble-projects,openjdk-annotate">
<!-- Now assemble all plugins -->
<taskdef name="plugin" classname="org.jnode.build.PluginTask" classpathref="cp-jnode"/>
- <plugin todir="${plugins.dir}" tmpdir="${build.dir}/tmp/plugins" pluginDir="${descriptors.dir}"
- userApplicationsDir="${user.applications.dir}" userApplicationsProperty="userApplications">
+ <plugin todir="${plugins.dir}" tmpdir="${build.dir}/tmp/plugins" pluginDir="${descriptors.dir}">
+ <packager userApplicationsDir="${user.applications.dir}" pathRefId="cp"/>
+
<libalias name="jnode-core.jar" alias="${jnode-core.jar}"/>
<libalias name="jnode-distr.jar" alias="${jnode-distr.jar}"/>
<libalias name="jnode-fs.jar" alias="${jnode-fs.jar}"/>
@@ -295,8 +296,9 @@
<taskdef name="initjars" classname="org.jnode.build.InitJarsBuilder" classpathref="cp-jnode"/>
<initjars destdir="${initjars.dir}"
pluginDir="${plugins.dir}"
- systemPluginList="${basedir}/conf/system-plugin-list.xml"
- userPlugins="${userApplications}">
+ systemPluginList="${basedir}/conf/system-plugin-list.xml">
+ <insert userApplicationsDir="${user.applications.dir}"/>
+
<fileset dir="${basedir}/conf">
<exclude name="system-plugin-list.xml"/>
<include name="*plugin-list.xml"/>
Modified: trunk/builder/build.xml
===================================================================
--- trunk/builder/build.xml 2008-08-31 16:58:22 UTC (rev 4521)
+++ trunk/builder/build.xml 2008-08-31 18:12:16 UTC (rev 4522)
@@ -26,6 +26,10 @@
<mkdir dir="${my-classes.dir}"/>
<mkdir dir="${jnasm-preprocessor-gen.dir}"/>
<mkdir dir="${jnasm-assembler-gen.dir}"/>
+
+ <copy todir="${my-classes.dir}">
+ <fileset dir="${my-src.dir}/builder" includes="**/*.properties"/>
+ </copy>
</target>
<!-- Compile the Template ANT task needed for compiling the core -->
Modified: trunk/builder/src/builder/org/jnode/build/AbstractPluginsTask.java
===================================================================
--- trunk/builder/src/builder/org/jnode/build/AbstractPluginsTask.java 2008-08-31 16:58:22 UTC (rev 4521)
+++ trunk/builder/src/builder/org/jnode/build/AbstractPluginsTask.java 2008-08-31 18:12:16 UTC (rev 4522)
@@ -51,7 +51,7 @@
* @throws PluginException
* @throws MalformedURLException
*/
- protected PluginList getPluginList() throws PluginException,
+ public PluginList getPluginList() throws PluginException,
MalformedURLException {
if (pluginList == null) {
pluginList = new PluginList(pluginListFile, pluginDir, targetArch);
Modified: trunk/builder/src/builder/org/jnode/build/InitJarBuilder.java
===================================================================
--- trunk/builder/src/builder/org/jnode/build/InitJarBuilder.java 2008-08-31 16:58:22 UTC (rev 4521)
+++ trunk/builder/src/builder/org/jnode/build/InitJarBuilder.java 2008-08-31 18:12:16 UTC (rev 4522)
@@ -29,11 +29,13 @@
import java.util.Iterator;
import java.util.List;
import java.util.Set;
+
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.GZip;
import org.apache.tools.ant.taskdefs.Jar;
import org.apache.tools.ant.taskdefs.Manifest;
import org.apache.tools.ant.types.FileSet;
+import org.jnode.build.packager.PluginListInsertor;
import org.jnode.plugin.PluginDescriptor;
import org.jnode.plugin.PluginException;
import org.jnode.plugin.PluginPrerequisite;
@@ -48,7 +50,7 @@
private File destFile;
- private String userPlugins;
+ private PluginListInsertor insertor;
public void execute() throws BuildException {
@@ -59,11 +61,11 @@
final long lmPI;
try {
piList = getPluginList();
-
- if ((userPlugins != null) && !userPlugins.isEmpty()) {
- piList.processUserPlugins(userPlugins);
+
+ if (insertor != null) {
+ insertor.insertInto(piList);
}
-
+
systemPluginList = getSystemPluginList();
if ((destFile == null) && (destDir != null)) {
destFile = new File(destDir, piList.getName() + ".jgz");
@@ -289,7 +291,7 @@
this.destDir = destDir;
}
- public void setUserPlugins(String userPlugins) {
- this.userPlugins = userPlugins;
+ public void setPackager(PluginListInsertor insertor) {
+ this.insertor = insertor;
}
}
Modified: trunk/builder/src/builder/org/jnode/build/InitJarsBuilder.java
===================================================================
--- trunk/builder/src/builder/org/jnode/build/InitJarsBuilder.java 2008-08-31 16:58:22 UTC (rev 4521)
+++ trunk/builder/src/builder/org/jnode/build/InitJarsBuilder.java 2008-08-31 18:12:16 UTC (rev 4522)
@@ -23,10 +23,12 @@
import java.io.File;
import java.util.ArrayList;
+
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.FileSet;
+import org.jnode.build.packager.PluginListInsertor;
/**
* Task used to build several initjars.
@@ -43,7 +45,7 @@
private File pluginDir;
private File systemPluginListFile;
- private String userPlugins;
+ private PluginListInsertor insertor;
/**
* Add a fileset to this task.
@@ -75,9 +77,8 @@
builder.setPluginList(listFile);
builder.setDestDir(getDestDir());
- // FIXME we should put the plugin list ("full-plugin-list.xml") outside
- if (listFiles[j].equals("full-plugin-list.xml") && (userPlugins != null)) {
- builder.setUserPlugins(userPlugins);
+ if (insertor != null) {
+ builder.setPackager(insertor);
}
builder.execute();
@@ -128,7 +129,9 @@
this.systemPluginListFile = systemPluginListFile;
}
- public void setUserPlugins(String userPlugins) {
- this.userPlugins = userPlugins;
+ public PluginListInsertor createInsert() {
+ insertor = new PluginListInsertor();
+ insertor.setProject(getProject());
+ return insertor;
}
}
Modified: trunk/builder/src/builder/org/jnode/build/PluginList.java
===================================================================
--- trunk/builder/src/builder/org/jnode/build/PluginList.java 2008-08-31 16:58:22 UTC (rev 4521)
+++ trunk/builder/src/builder/org/jnode/build/PluginList.java 2008-08-31 18:12:16 UTC (rev 4522)
@@ -104,6 +104,10 @@
}
}
+ public void addPlugin(String id) throws MalformedURLException, PluginException {
+ addPlugin(descrList, pluginList, id);
+ }
+
private void addPlugin(List<URL> descrList, List<URL> pluginList, String id)
throws MalformedURLException, PluginException {
final File f = findPlugin(defaultDir, id);
@@ -245,17 +249,4 @@
throw new RuntimeException(e);
}
}
-
- /**
- * Add user plugins to the list
- * @param userPlugins
- * @throws MalformedURLException
- * @throws PluginException
- */
- public void processUserPlugins(String userPlugins) throws MalformedURLException, PluginException {
- for (String pluginId : userPlugins.split(",")) {
- System.out.println("Adding user plugin " + pluginId);
- addPlugin(descrList, pluginList, pluginId);
- }
- }
}
Modified: trunk/builder/src/builder/org/jnode/build/PluginTask.java
===================================================================
--- trunk/builder/src/builder/org/jnode/build/PluginTask.java 2008-08-31 16:58:22 UTC (rev 4521)
+++ trunk/builder/src/builder/org/jnode/build/PluginTask.java 2008-08-31 18:12:16 UTC (rev 4522)
@@ -22,29 +22,14 @@
package org.jnode.build;
import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.FilenameFilter;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
-import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.jar.Attributes;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
@@ -52,11 +37,9 @@
import org.apache.tools.ant.taskdefs.Manifest;
import org.apache.tools.ant.taskdefs.ManifestException;
import org.apache.tools.ant.types.FileSet;
-import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.ZipFileSet;
import org.apache.tools.ant.util.FileUtils;
-import org.jnode.nanoxml.XMLElement;
-import org.jnode.nanoxml.XMLParseException;
+import org.jnode.build.packager.PluginBuilder;
import org.jnode.plugin.Library;
import org.jnode.plugin.PluginDescriptor;
import org.jnode.plugin.Runtime;
@@ -70,8 +53,7 @@
private File todir;
private File tmpDir = new File(System.getProperty("java.io.tmpdir"));
- private File userApplicationsDir;
- private String userApplicationsProperty;
+ private PluginBuilder packager;
public ZipFileSet createDescriptors() {
final ZipFileSet fs = new ZipFileSet();
@@ -102,7 +84,6 @@
int max_thread_count = 10;
int max_plugin_count = 500;
- StringBuilder userPlugins = new StringBuilder();
final AtomicBoolean failure = new AtomicBoolean(false);
ThreadPoolExecutor executor = new ThreadPoolExecutor(max_thread_count, max_thread_count, 60, TimeUnit.SECONDS,
@@ -127,19 +108,9 @@
});
}
}
- if ((userApplicationsDir != null) && userApplicationsDir.exists() && userApplicationsDir.isDirectory()) {
- File[] userJars = userApplicationsDir.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- return name.endsWith(".jar");
- }
-
- });
-
- for (File userJar : userJars) {
- processUserJar(executor, descriptors, userJar, userPlugins);
- }
+ if (packager != null) {
+ packager.execute(executor, descriptors);
}
executor.shutdown();
@@ -153,240 +124,18 @@
throw new RuntimeException("At least one plugin task failed : see above errors");
}
- // that must be called after completion of all plugin tasks
- if ((userPlugins.length() > 0) && (userPlugins.charAt(userPlugins.length() - 1) == ',')) {
- userPlugins.deleteCharAt(userPlugins.length() - 1);
- }
- getProject().setProperty(userApplicationsProperty, userPlugins.toString());
- }
-
- /**
- * Attention : userPluginList must be a StringBuilder because it's accessed from multiple threads
- * @param executor
- * @param descriptors
- * @param userJar
- * @param userPluginList
- */
- private void processUserJar(ExecutorService executor, final Map<String, File> descriptors, final File userJar,
- final StringBuilder userPluginList) {
- executor.execute(new Runnable() {
- public void run() {
- final String jarName = userJar.getName();
- final String pluginId = jarName.substring(0, jarName.length() - 4); // remove ".jar"
-
- userPluginList.append(pluginId + ",");
-
- // replace ".jar" by ".xml"
- final String pluginDesc = pluginId + ".xml";
-
- // FIXME remove the explicit reference to "cp"
- // add user jar to path named "cp" (used in build.xml)
- Path path = (Path) getProject().getReference("cp");
- path.createPathElement().setLocation(userJar);
-
- // create the lib alias
- final String alias = pluginId + ".jar";
- LibAlias libAlias = createLibAlias();
- libAlias.setName(alias);
- libAlias.setAlias(userJar);
-
- final File descriptorFile = new File(userJar.getParent(), pluginDesc);
- if (!descriptorFile.exists()) {
- // build the descriptor from scratch
- buildDescriptor(userJar, descriptorFile, pluginId, alias);
- }
-
- buildPlugin(descriptors, descriptorFile);
- }
- });
- }
-
- private void buildDescriptor(File userJar, File descriptorFile, String pluginId, String alias) {
- PrintStream out = null;
- boolean success = false;
- try {
- out = new PrintStream(descriptorFile);
-
- out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
- out.println("<!DOCTYPE plugin SYSTEM \"jnode.dtd\">");
-
- out.println("<plugin id=\"" + pluginId + "\"");
- out.println(" name=\"" + pluginId + "\"");
- out.println(" version=\"\"");
- out.println(" license-name=\"unspecified\">");
-
- out.println(" <runtime>");
- out.println(" <library name=\"" + alias + "\">");
- out.println(" <export name=\"*\"/>");
- out.println(" </library>");
- out.println(" </runtime>");
-
- List<String> mainClasses = searchMain(userJar);
- if (!mainClasses.isEmpty()) {
- out.println(" <extension point=\"org.jnode.shell.aliases\">");
- for (String mainClass : mainClasses) {
- int idx = mainClass.lastIndexOf('.');
- String name = (idx < 0) ? mainClass : mainClass.substring(idx + 1);
- out.println(" <alias name=\"" + name + "\" class=\"" + mainClass + "\"/>");
- System.out.println(pluginId + " : added alias " + name + " for class " + mainClass);
- }
-
- out.println(" </extension>");
- } else {
- System.err.println("WARNING : no main found for plugin " + pluginId);
- }
-
- // FIXME using AllPermission is bad ! we must avoid that
- out.println(" <extension point=\"org.jnode.security.permissions\">");
- out.println(" <permission class=\"java.security.AllPermission\" />");
- out.println(" </extension>");
-
- out.println("</plugin>");
- success = true;
- } catch (IOException ioe) {
- throw new BuildException(ioe);
- } finally {
- if (out != null) {
- out.close();
- }
-
- if (!success) {
- // in case of failure, remove the incomplete descriptor file
- descriptorFile.delete();
- }
+ if (packager != null) {
+ // that must be called after completion of all plugin tasks
+ packager.finish();
}
}
-
- private List<String> searchMain(File userJar) throws FileNotFoundException, IOException {
- List<String> mainList = new ArrayList<String>();
-
- JarFile jarFile = null;
- try {
- jarFile = new JarFile(userJar);
-
- // try to find the main class from the manifest
- Object value = null;
-
- // do we have a manifest ?
- if (jarFile.getManifest() != null) {
- value = jarFile.getManifest().getMainAttributes().get(Attributes.Name.MAIN_CLASS);
- if (value == null) {
- String name = Attributes.Name.MAIN_CLASS.toString();
- final Attributes attr = jarFile.getManifest().getAttributes(name);
-
- // we have a manifest but do we have a main class defined inside ?
- if (attr != null) {
- value = attr.get(Attributes.Name.MAIN_CLASS);
- }
- }
- }
-
- if (value != null) {
- mainList.add(String.valueOf(value));
- } else {
- // scan the jar to find the main classes
- for (Enumeration<JarEntry> e = jarFile.entries(); e.hasMoreElements(); ) {
- final JarEntry entry = e.nextElement();
- final String name = entry.getName();
- InputStream is = null;
-
- try {
- if (name.endsWith(".class")) {
- String className = name.substring(0, name.length() - ".class".length());
- className = className.replace('/', '.');
- is = jarFile.getInputStream(entry);
- ClassLoader cl = new InputStreamLoader(is, (int) entry.getSize());
- Class<?> clazz = Class.forName(className, false, cl);
- Method m = clazz.getMethod("main", new Class<?>[]{String[].class});
- if ((m.getModifiers() & Modifier.STATIC) == Modifier.STATIC) {
- mainList.add(className);
- }
- }
- } catch (ClassNotFoundException cnfe) {
- cnfe.printStackTrace();
- // ignore
- } catch (SecurityException se) {
- se.printStackTrace();
- // ignore
- } catch (NoSuchMethodException nsme) {
- // such error is expected for non-main classes => ignore
- } catch (Throwable t) {
- t.printStackTrace();
- // ignore
- } finally {
- if (is != null) {
- is.close();
- }
- }
- }
- }
- } finally {
- if (jarFile != null) {
- jarFile.close();
- }
- }
-
- return mainList;
- }
-
- private static class InputStreamLoader extends ClassLoader {
- private InputStream inputStream;
- private int size;
-
- public InputStreamLoader(InputStream inputStream, int size) {
- this.inputStream = inputStream;
- this.size = size;
- }
-
- public Class loadClass(String className) throws ClassNotFoundException {
- return loadClass(className, true);
- }
-
- public synchronized Class loadClass(String className, boolean resolve)
- throws ClassNotFoundException {
- Class<?> result;
-
- try {
-
- result = super.findSystemClass(className);
-
- } catch (ClassNotFoundException e) {
- byte[] classData = null;
-
- try {
- classData = new byte[size];
- inputStream.read(classData);
- } catch (IOException ioe) {
- throw new ClassNotFoundException(className, ioe);
- }
-
- if (classData == null) {
- throw new ClassNotFoundException(className);
- }
-
- result = defineClass(className, classData, 0, classData.length);
-
- if (result == null) {
- throw new ClassFormatError();
- }
-
- if (resolve) {
- resolveClass(result);
- }
- }
-
- return result;
- }
- }
-
-
/**
* @param descriptors map of fullPluginId to File descriptor
* @param descriptor the plugin descriptor XML
* @throws BuildException on failure
*/
- protected void buildPlugin(Map<String, File> descriptors, File descriptor) throws BuildException {
+ public void buildPlugin(Map<String, File> descriptors, File descriptor) throws BuildException {
final PluginDescriptor descr = readDescriptor(descriptor);
final String fullId = descr.getId() + "_" + descr.getVersion();
@@ -457,18 +206,6 @@
return mf;
}
- protected void addResourceList(File pluginDescr, Collection<ZipFileSet> resources)
- throws XMLParseException, FileNotFoundException, IOException {
- final XMLElement xml = new XMLElement();
- xml.parseFromReader(new FileReader(pluginDescr));
-
-// XMLElement runtime = xml.g
-
- }
-
-// private final XMLElement getRuntimeElement(XMLElement xml) {
-// }
-
/**
* @return The destination directory
*/
@@ -497,17 +234,8 @@
this.tmpDir = tmpDir;
}
- /**
- * @param file
- */
- public void setUserApplicationsDir(File file) {
- userApplicationsDir = file;
+ public PluginBuilder createPackager() {
+ packager = new PluginBuilder(this);
+ return packager;
}
-
- /**
- * @param file
- */
- public void setUserApplicationsProperty(String name) {
- userApplicationsProperty = name;
- }
}
Added: trunk/builder/src/builder/org/jnode/build/packager/PackagerTask.java
===================================================================
--- trunk/builder/src/builder/org/jnode/build/packager/PackagerTask.java (rev 0)
+++ trunk/builder/src/builder/org/jnode/build/packager/PackagerTask.java 2008-08-31 18:12:16 UTC (rev 4522)
@@ -0,0 +1,111 @@
+package org.jnode.build.packager;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+/**
+ * Abstract class used for common stuff among packager tasks
+ *
+ * @author fabien
+ *
+ */
+public class PackagerTask extends Task {
+ protected static final String PROPERTIES_FILE = "plugins.properties";
+
+ /**
+ * The default properties for the packager tool
+ */
+ private static final Properties DEFAULT_PROPERTIES;
+
+ static {
+ Properties props;
+ try {
+ props = readProperties(PackagerTask.class.getResourceAsStream(PROPERTIES_FILE), null);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ props = new Properties();
+ }
+ DEFAULT_PROPERTIES = props;
+ }
+
+ // properties names
+ protected static final String USER_PLUGIN_IDS = "user.plugin.ids";
+ protected static final String PLUGIN_LIST_NAME = "plugin.list.name";
+
+ /**
+ * Directory for suer plugins/resources
+ */
+ protected File userApplicationsDir = null;
+
+ /**
+ * Define the directory where user put its own plugins/resources to add in jnode cdrom
+ * @param file
+ */
+ public final void setUserApplicationsDir(File file) {
+ if ((file != null) && file.exists() && file.isDirectory()) {
+ userApplicationsDir = file;
+ } else {
+ userApplicationsDir = null;
+ }
+ }
+
+ /**
+ * Is that task enabled ?
+ * @return
+ */
+ protected final boolean isEnabled() {
+ return (userApplicationsDir != null);
+ }
+
+ /**
+ * Get properties file used to configure the packager tool
+ * @return
+ */
+ protected final File getPropertiesFile() {
+ return isEnabled() ? new File(userApplicationsDir, PROPERTIES_FILE) : null;
+ }
+
+ /**
+ * Read the properties file used to configure the packager tool
+ * @return
+ */
+ protected final Properties readProperties() {
+ try {
+ return readProperties(new FileInputStream(getPropertiesFile()), DEFAULT_PROPERTIES);
+ } catch (FileNotFoundException e) {
+ throw new BuildException("failed to read properties file", e);
+ }
+ }
+
+ /**
+ * Read the properties from the given {@link InputStream}
+ *
+ * @param input
+ * @param defaultProps
+ * @return
+ */
+ private static final Properties readProperties(InputStream input, Properties defaultProps) {
+ Properties properties = (defaultProps == null) ? new Properties() : new Properties(defaultProps);
+
+ try {
+ properties.load(input);
+ } catch (IOException ioe) {
+ throw new BuildException("failed to read properties file", ioe);
+ } finally {
+ try {
+ input.close();
+ } catch (IOException ioe) {
+ throw new BuildException("failed to close input stream", ioe);
+ }
+ }
+
+ return properties;
+ }
+}
Added: trunk/builder/src/builder/org/jnode/build/packager/PluginBuilder.java
===================================================================
--- trunk/builder/src/builder/org/jnode/build/packager/PluginBuilder.java (rev 0)
+++ trunk/builder/src/builder/org/jnode/build/packager/PluginBuilder.java 2008-08-31 18:12:16 UTC (rev 4522)
@@ -0,0 +1,369 @@
+package org.jnode.build.packager;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Path;
+import org.jnode.build.BuildException;
+import org.jnode.build.PluginTask;
+import org.jnode.build.AbstractPluginTask.LibAlias;
+
+/**
+ * Class building new jnode plugins from third party jars/resources
+ *
+ * @author fabien
+ *
+ */
+public class PluginBuilder extends PackagerTask {
+ private final Task parent;
+
+ /**
+ * List of user plugin ids
+ */
+ private StringBuilder userPluginIds = new StringBuilder();
+
+ /**
+ * {@link Path} to third party jars for compilation purpose
+ */
+ private Path path;
+
+ public PluginBuilder(Task parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Define the path reference for compilation
+ * @param pathRefId
+ */
+ public void setPathRefId(String pathRefId) {
+ this.path = (Path) parent.getProject().getReference(pathRefId);
+ }
+
+ /**
+ * Main method for build the jnode plugin
+ *
+ * @param executor
+ * @param descriptors
+ */
+ public void execute(ThreadPoolExecutor executor, final Map<String, File> descriptors) {
+ if (isEnabled()) {
+ if (path == null) {
+ throw new BuildException("pathRefId is mandatory");
+ }
+
+ File[] userJars = userApplicationsDir.listFiles(new FileFilter() {
+
+ @Override
+ public boolean accept(File pathname) {
+ return pathname.getName().endsWith(".jar") || pathname.isDirectory();
+ }
+
+ });
+
+ for (File userJar : userJars) {
+ processUserJar(executor, descriptors, userJar, userPluginIds);
+ }
+ }
+ }
+
+ /**
+ * Do finalization tasks. For instance, it's writing the plugin ids to the properties file
+ */
+ public void finish() {
+ if (isEnabled()) {
+ if ((userPluginIds.length() > 0) && (userPluginIds.charAt(userPluginIds.length() - 1) == ',')) {
+ userPluginIds.deleteCharAt(userPluginIds.length() - 1);
+ }
+
+ // write properties
+ Properties properties = new Properties();
+ properties.put(USER_PLUGIN_IDS, userPluginIds.toString());
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(getPropertiesFile());
+ properties.store(fos, "");
+ } catch (IOException e) {
+ throw new BuildException("failed to write properties file", e);
+ } finally {
+ if (fos != null) {
+ try {
+ fos.close();
+ } catch (IOException e) {
+ throw new BuildException("failed to close properties file", e);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Attention : userPluginList must be a StringBuilder because it's accessed from multiple threads
+ * @param executor
+ * @param descriptors
+ * @param userJar
+ * @param userPluginList
+ */
+ private void processUserJar(ExecutorService executor, final Map<String, File> descriptors, final File userJar,
+ final StringBuilder userPluginList) {
+ final PluginTask task = (PluginTask) parent;
+ executor.execute(new Runnable() {
+ public void run() {
+ final String jarName = userJar.getName();
+ final String pluginId;
+
+ if (userJar.isFile()) {
+ pluginId = jarName.substring(0, jarName.length() - 4); // remove ".jar"
+ } else {
+ pluginId = jarName; // use directory name as plugin id
+ }
+
+ userPluginList.append(pluginId + ",");
+
+ // replace ".jar" by ".xml"
+ final String pluginDesc = pluginId + ".xml";
+
+ path.createPathElement().setLocation(userJar);
+
+ // create the lib alias
+ final String alias = pluginId + ".jar";
+ LibAlias libAlias = task.createLibAlias();
+ libAlias.setName(alias);
+ libAlias.setAlias(userJar);
+
+ final File descriptorFile = new File(userJar.getParent(), pluginDesc);
+ if (!descriptorFile.exists()) {
+ // build the descriptor from scratch
+ buildDescriptor(userJar, descriptorFile, pluginId, alias);
+ }
+
+ task.buildPlugin(descriptors, descriptorFile);
+ }
+ });
+ }
+
+ /**
+ * Build the plugin descriptor
+ *
+ * @param userJar
+ * @param descriptorFile
+ * @param pluginId
+ * @param alias
+ */
+ private void buildDescriptor(File userJar, File descriptorFile, String pluginId, String alias) {
+ PrintStream out = null;
+ boolean success = false;
+ try {
+ out = new PrintStream(descriptorFile);
+
+ out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ out.println("<!DOCTYPE plugin SYSTEM \"jnode.dtd\">");
+
+ out.println("<plugin id=\"" + pluginId + "\"");
+ out.println(" name=\"" + pluginId + "\"");
+ out.println(" version=\"\"");
+ out.println(" class=\"org.jnode.plugin.AutoUnzipPlugin\"");
+ out.println(" auto-start=\"true\"");
+ out.println(" license-name=\"unspecified\">");
+
+ out.println(" <runtime>");
+ out.println(" <library name=\"" + alias + "\">");
+ out.println(" <export name=\"*\"/>");
+ out.println(" </library>");
+ out.println(" </runtime>");
+
+ if (userJar.isFile()) {
+ List<String> mainClasses = searchMain(userJar);
+ if (!mainClasses.isEmpty()) {
+ out.println(" <extension point=\"org.jnode.shell.aliases\">");
+ for (String mainClass : mainClasses) {
+ int idx = mainClass.lastIndexOf('.');
+ String name = (idx < 0) ? mainClass : mainClass.substring(idx + 1);
+ out.println(" <alias name=\"" + name + "\" class=\"" + mainClass + "\"/>");
+ log(pluginId + " : added alias " + name + " for class " + mainClass, Project.MSG_INFO);
+ }
+
+ out.println(" </extension>");
+ } else {
+ log("no main found for plugin " + pluginId, Project.MSG_WARN);
+ }
+ }
+
+ out.println(" <!-- FIXME : use more restricted permissions -->");
+ out.println(" <extension point=\"org.jnode.security.permissions\">");
+ out.println(" <permission class=\"java.security.AllPermission\" />");
+ out.println(" </extension>");
+
+ out.println("</plugin>");
+ success = true;
+ } catch (IOException ioe) {
+ throw new BuildException("failed to write plugin descriptor", ioe);
+ } finally {
+ if (out != null) {
+ out.close();
+ }
+
+ if (!success) {
+ // in case of failure, remove the incomplete descriptor file
+ descriptorFile.delete();
+ }
+ }
+ }
+
+ /**
+ * Search for the main classes in the jars/resources.
+ * Starts by looking in the jars manifests and, if nothing is found,
+ * then scans the jars/resources for main classes.
+ *
+ * @param userJar
+ * @return
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ private List<String> searchMain(File userJar) throws FileNotFoundException, IOException {
+ List<String> mainList = new ArrayList<String>();
+
+ JarFile jarFile = null;
+ try {
+ jarFile = new JarFile(userJar);
+
+ // try to find the main class from the manifest
+ Object value = null;
+
+ // do we have a manifest ?
+ if (jarFile.getManifest() != null) {
+ value = jarFile.getManifest().getMainAttributes().get(Attributes.Name.MAIN_CLASS);
+ if (value == null) {
+ String name = Attributes.Name.MAIN_CLASS.toString();
+ final Attributes attr = jarFile.getManifest().getAttributes(name);
+
+ // we have a manifest but do we have a main class defined inside ?
+ if (attr != null) {
+ value = attr.get(Attributes.Name.MAIN_CLASS);
+ }
+ }
+ }
+
+ if (value != null) {
+ mainList.add(String.valueOf(value));
+ } else {
+ // scan the jar to find the main classes
+ for (Enumeration<JarEntry> e = jarFile.entries(); e.hasMoreElements(); ) {
+ final JarEntry entry = e.nextElement();
+ final String name = entry.getName();
+ InputStream is = null;
+
+ try {
+ if (name.endsWith(".class")) {
+ String className = name.substring(0, name.length() - ".class".length());
+ className = className.replace('/', '.');
+
+ is = jarFile.getInputStream(entry);
+ ClassLoader cl = new InputStreamLoader(is, (int) entry.getSize());
+ Class<?> clazz = Class.forName(className, false, cl);
+ Method m = clazz.getMethod("main", new Class<?>[]{String[].class});
+ if ((m.getModifiers() & Modifier.STATIC) == Modifier.STATIC) {
+ mainList.add(className);
+ }
+ }
+ } catch (ClassNotFoundException cnfe) {
+ cnfe.printStackTrace();
+ // ignore
+ } catch (SecurityException se) {
+ se.printStackTrace();
+ // ignore
+ } catch (NoSuchMethodException nsme) {
+ // such error is expected for non-main classes => ignore
+ } catch (Throwable t) {
+ t.printStackTrace();
+ // ignore
+ } finally {
+ if (is != null) {
+ is.close();
+ }
+ }
+ }
+ }
+ } finally {
+ if (jarFile != null) {
+ jarFile.close();
+ }
+ }
+
+ return mainList;
+ }
+
+ /**
+ * Custom {@link ClassLoader} used to load classes from an InputStream.
+ * It helps finding a main class in a jar file.
+ * @author fabien
+ *
+ */
+ private static class InputStreamLoader extends ClassLoader {
+ private InputStream inputStream;
+ private int size;
+
+ public InputStreamLoader(InputStream inputStream, int size) {
+ this.inputStream = inputStream;
+ this.size = size;
+ }
+
+ public Class loadClass(String className) throws ClassNotFoundException {
+ return loadClass(className, true);
+ }
+
+ public synchronized Class loadClass(String className, boolean resolve)
+ throws ClassNotFoundException {
+ Class<?> result;
+
+ try {
+
+ result = super.findSystemClass(className);
+
+ } catch (ClassNotFoundException e) {
+ byte[] classData = null;
+
+ try {
+ classData = new byte[size];
+ inputStream.read(classData);
+ } catch (IOException ioe) {
+ throw new ClassNotFoundException(className, ioe);
+ }
+
+ if (classData == null) {
+ throw new ClassNotFoundException(className);
+ }
+
+ result = defineClass(className, classData, 0, classData.length);
+
+ if (result == null) {
+ throw new ClassFormatError();
+ }
+
+ if (resolve) {
+ resolveClass(result);
+ }
+ }
+
+ return result;
+ }
+ }
+}
Added: trunk/builder/src/builder/org/jnode/build/packager/PluginListInsertor.java
===================================================================
--- trunk/builder/src/builder/org/jnode/build/packager/PluginListInsertor.java (rev 0)
+++ trunk/builder/src/builder/org/jnode/build/packager/PluginListInsertor.java 2008-08-31 18:12:16 UTC (rev 4522)
@@ -0,0 +1,66 @@
+package org.jnode.build.packager;
+
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.tools.ant.Project;
+import org.jnode.build.PluginList;
+import org.jnode.plugin.PluginException;
+
+/**
+ * Task that insert the user plugins into a plugin list
+ * without actually modifying the plugin list files.
+ *
+ * @author fabien
+ *
+ */
+public class PluginListInsertor extends PackagerTask {
+
+ /**
+ * Main method of the task.
+ *
+ * @param list
+ * @throws MalformedURLException
+ * @throws PluginException
+ */
+ public void insertInto(final PluginList list) throws MalformedURLException, PluginException {
+ if (isEnabled()) {
+ for (String pluginId : readPluginIds(list.getName())) {
+ log("Adding user plugin " + pluginId, Project.MSG_INFO);
+ list.addPlugin(pluginId);
+ }
+ }
+ }
+
+ /**
+ * Read the user plugins ids from the properties file
+ * @param pluginListName
+ * @return
+ */
+ private List<String> readPluginIds(String pluginListName) {
+ List<String> pluginIds = new ArrayList<String>();
+
+ final Properties properties = readProperties();
+ final String targetName = properties.getProperty(PLUGIN_LIST_NAME, null);
+ if (targetName == null) {
+ log("property " + PLUGIN_LIST_NAME + " not specified in " +
+ getPropertiesFile().getAbsolutePath(), Project.MSG_ERR);
+ } else {
+ if (targetName.equals(pluginListName)) {
+ final String ids = properties.getProperty(USER_PLUGIN_IDS, null);
+ if ((ids == null) || ids.trim().isEmpty()) {
+ log("property " + USER_PLUGIN_IDS + " not specified in " +
+ getPropertiesFile().getAbsolutePath(), Project.MSG_ERR);
+ } else {
+ for (String pluginId : ids.split(",")) {
+ pluginIds.add(pluginId);
+ }
+ }
+ }
+ }
+
+ return pluginIds;
+ }
+}
Added: trunk/builder/src/builder/org/jnode/build/packager/plugins.properties
===================================================================
--- trunk/builder/src/builder/org/jnode/build/packager/plugins.properties (rev 0)
+++ trunk/builder/src/builder/org/jnode/build/packager/plugins.properties 2008-08-31 18:12:16 UTC (rev 4522)
@@ -0,0 +1,4 @@
+#
+# Default values for the packager
+#
+plugin.list.name=full
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|