Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * DynTool.java
- */
- package at.mwildam.common;
- import java.beans.Expression;
- import java.io.File;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.net.URLClassLoader;
- import java.util.Date;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- import javax.tools.JavaCompiler;
- /**
- * Dynamic class loading and method invocation
- * <p>
- * By <a href="http://www.google.com/profiles/mwildam" target="_blank">Martin Wildam</a>
- * <p>
- * @author Martin Wildam
- */
- public class DynTool
- {
- /**
- * Tries to instanciate an object of the given class and returns a pointer to it.
- * <p>
- * Expects the class files in the directory given by the
- * <i>dynClassPath</i> parameter. For each dot (.) in the class path there
- * must be given a subfolder. If there exists a .java file instead of
- * the expected .class file then the method tries to compile the .java file.
- * It tries also a compile if both the .java and the .class file exists but
- * the .class file is out of date (older than the .java file.
- * The <i>addClassPath</i> parameter is only used if the attempt to
- * compile is done.
- * <p>
- * You can also specify a jar file in the <i>dynClassPath</i> parameter if
- * you have a fully compiled and prepared package.
- * <p>
- * Returns null if the object could not be created.
- * <p>
- * Sample: getPluginInstance("/Work/Java/TestGUI/dist/TestGUI.jar", "testgui.TestPluginClass", "/Work/Java/TestGUI/dist/lib")
- * <p>
- * <b>Note:</b> Dynamic class loading and calls evaluated during runtime
- * using reflection is time consuming in general and therefore should be
- * avoided for performance citrical operations (although already better
- * since Java 5).
- * <p>
- * We are returning null here in error case although not recommended
- * because I do agree with <a href="http://www.joelonsoftware.com/">Joel Spolsky</a> on
- * <a href="http://www.joelonsoftware.com/items/2003/10/13.html">Exceptions</a>.
- *
- * @param dynClassPath path to classes root dir where to search for the class to instantiate.
- * Can also be a .jar file.
- * @param className Full class name for the plugin class to use.
- * @param addClassPath is an additional option for classpath to search (;-separated)
- * which is only used when a compile attempt is done.
- * @return Object or null in error case.
- */
- public static Object getPluginInstance(String dynClassPath, String className, String addClassPath)
- {
- if (!dynClassPath.toLowerCase().endsWith(".jar"))
- {
- String classFile = className.replace(".", "/");
- classFile = dynClassPath + "/" + classFile;
- String javaFile = classFile;
- javaFile += ".java";
- classFile += ".class";
- if (addClassPath.length() != 0) addClassPath = ";" + addClassPath;
- if ((!existsFile(classFile) && existsFile(javaFile))
- || getFileDate(classFile).before(getFileDate(javaFile)))
- {
- JavaCompiler jc = javax.tools.ToolProvider.getSystemJavaCompiler();
- int r = jc.run(null, null, null, "-classpath", dynClassPath + addClassPath, "-d", dynClassPath, javaFile);
- if (r != 0) return null;
- }
- }
- else
- addFileToClassPath(dynClassPath);
- try
- {
- if (addClassPath != null && addClassPath.length() > 0)
- addFilesToClassPath(addClassPath);
- URL url = new URL(DynTool.getUrlFromPath(dynClassPath));
- URL[] clsList = new URL[1];
- clsList[0] = url;
- URLClassLoader ucl = new URLClassLoader(clsList);
- Class cls = ucl.loadClass(className);
- return cls.newInstance();
- }
- catch (NoClassDefFoundError ex)
- {
- Logger.getLogger(DynTool.class.getName()).log(Level.SEVERE, null, ex);
- return null;
- }
- catch (ClassNotFoundException ex)
- {
- Logger.getLogger(DynTool.class.getName()).log(Level.SEVERE, null, ex);
- return null;
- }
- catch (InstantiationException ex)
- {
- Logger.getLogger(DynTool.class.getName()).log(Level.SEVERE, null, ex);
- return null;
- }
- catch (IllegalAccessException ex)
- {
- Logger.getLogger(DynTool.class.getName()).log(Level.SEVERE, null, ex);
- return null;
- }
- catch (MalformedURLException ex)
- {
- Logger.getLogger(DynTool.class.getName()).log(Level.SEVERE, null, ex);
- return null;
- }
- }
- /**
- * Late binding method call on an already instantiated object.
- * <p>
- * Invokes the requested method of a given object instance where the
- * object class is not specified at compile time.
- * <p>
- * To call a method that does not have a parameter then pass null for the
- * <i>params</i> parameters.
- * <p>
- * What the method returns is routed to the caller of this method as Object
- * so you have to cast the return type to something more specific if needed
- * or just use .tostring. If the called method is declared void then this
- * method returns null.
- * <p>
- * <b>Note:</b> Dynamic class loading and calls evaluated during runtime
- * using reflection is time consuming in general and therefore should be
- * avoided for performance critical operations.
- * <p>
- * We are returning null here in error case although not recommended
- * because I do agree with <a href="http://www.joelonsoftware.com/">Joel Spolsky</a> on
- * <a href="http://www.joelonsoftware.com/items/2003/10/13.html">Exceptions</a>.
- *
- * @param instance A not well known object for that we hope to be able to
- * call the requested method.
- * @param methodName Name of the method to be called
- * @param params parameter objects to pass to the method (best matching declaration variant is searched)
- * @return Returned object or null if method is declared void or an error occurred.
- */
- public static Object call(Object instance, String methodName, Object... params)
- {
- //Statement stmt = new Statement(obj, methodName, null);
- //stmt.execute();
- Expression expr = new Expression(instance, methodName, params);
- //expr.execute(); //Not necessary, called automatically on getValue();
- Object result = null;
- try
- {
- result = expr.getValue();
- }
- catch (Exception ex)
- {
- Logger.getLogger(DynTool.class.getName()).log(Level.SEVERE, null, ex);
- }
- return result;
- }
- /**
- * Adds a resource given as URL to the classpath.
- * <p>
- * Adds the given url to the classpath dynamically.
- * <p>
- * From antony_miguel at
- * <a href="http://forums.sun.com/thread.jspa?threadID=300557&start=0&tstart=0">http://forums.sun.com/thread.jspa?threadID=300557</a>:
- * <blockquote><i>I've seen a lot of forum posts about how to modify the
- * classpath at runtime and a lot of answers saying it can't be done.
- * I needed to add JDBC driver JARs at runtime so I figured out the
- * following method.
- * <p>
- * The system classloader (ClassLoader.getSystemClassLoader()) is a subclass
- * of URLClassLoader. It can therefore be casted into a URLClassLoader and
- * used as one.
- * <p>
- * URLClassLoader has a protected method addURL(URL url), which you can use
- * to add files, jars, web addresses - any valid URL in fact.
- * <p>
- * Since the method is protected you need to use reflection to invoke it.
- * </i></blockquote>
- * <p>
- * The class path change does not reflect in the system property
- * "" because that property does not get modified any more after application
- * start. So don't check success by checking
- * <i>System.getProperty("java.class.path");</i>.
- *
- * @param url Url to add to the class path.
- * @return True if operation was successful
- */
- public static boolean addUrlToClassPath(URL url)
- {
- if (url == null)
- {
- Logger.getLogger(DynTool.class.getName()).log(Level.WARNING, "Missing url to add to classpath.");
- return false;
- }
- boolean b = false;
- URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
- Class sysclass = URLClassLoader.class;
- try
- {
- Class[] methodParams = new Class[1];
- methodParams[0] = URL.class;
- //There could be really different classes in the array.
- @SuppressWarnings("unchecked")
- Method method = sysclass.getDeclaredMethod("addURL", methodParams);
- method.setAccessible(true);
- method.invoke(sysloader, new Object[]
- {
- url
- });
- b = true;
- }
- catch (IllegalAccessException ex)
- {
- Logger.getLogger(DynTool.class.getName()).log(Level.WARNING, null, ex);
- }
- catch (IllegalArgumentException ex)
- {
- Logger.getLogger(DynTool.class.getName()).log(Level.WARNING, null, ex);
- }
- catch (InvocationTargetException ex)
- {
- Logger.getLogger(DynTool.class.getName()).log(Level.WARNING, null, ex);
- }
- catch (NoSuchMethodException ex)
- {
- Logger.getLogger(DynTool.class.getName()).log(Level.WARNING, null, ex);
- }
- catch (SecurityException ex)
- {
- Logger.getLogger(DynTool.class.getName()).log(Level.WARNING, null, ex);
- }
- return b;
- }
- /**
- * Converts a file path to an url link.
- * <p>
- * Returns the url link equivalent to the given path as string.
- *
- * @param path
- * @return Url string
- */
- public static String getUrlFromPath(String path)
- {
- try
- {
- return new File(path).toURI().toURL().toString();
- }
- catch (MalformedURLException ex)
- {
- return "";
- }
- }
- /**
- * Returns a boolean true if a "normal" file with the specified name exists.
- * <p>
- * Note: Returns false for files that are part of the kernel system.
- * So it returns true only for "normal" files.
- *
- * @param fileFullName FQPN of the file to be searched for
- * @return Boolean
- */
- public static Boolean existsFile(String fileFullName)
- {
- if (fileFullName == null)
- return false;
- else
- {
- File f = new File(fileFullName);
- return f.exists() && f.isFile();
- }
- }
- /**
- * Returns the timestamp of the file with the given name if exists otherwise 0.
- * <p>
- * Returns a Date of 0 if the file could not be found otherwise the last
- * file modification date.
- *
- * @param fileName Name of the file from which to read the date and timestamp
- * @return Date
- */
- public static Date getFileDate(String fileName)
- {
- if (!existsFile(fileName))
- return new Date(0);
- else
- {
- File f = new File(fileName);
- return new Date(f.lastModified());
- }
- }
- /**
- * Adds the given file dynamically to the class path.
- * <p>
- * Further details see {@link #addUrlToClassPath(java.net.URL) }.
- *
- * @param file File object to be added dynamically to the class path.
- * @return True if operation was successful.
- */
- public static boolean addFileToClassPath(File file)
- {
- if (file == null)
- {
- Logger.getLogger(DynTool.class.getName()).log(Level.WARNING, "Missing file to add to classpath.");
- return false;
- }
- URL url;
- try
- {
- url = file.toURI().toURL();
- }
- catch (MalformedURLException ex)
- {
- Logger.getLogger(DynTool.class.getName()).log(Level.WARNING, null, ex);
- return false;
- }
- return addUrlToClassPath(url);
- }
- /**
- * Adds the given file dynamically to the class path.
- * <p>
- * Further details see {@link #addUrlToClassPath(java.net.URL) }.
- *
- * @param fileName FQPN of the file object to be added dynamically to the class path.
- * @return True if operation was successful.
- */
- public static boolean addFileToClassPath(String fileName)
- {
- return addFileToClassPath(new File(fileName));
- }
- /**
- * Adds files in the given folder dynamically to the class path.
- * <p>
- * You can specify multiple paths separating them by ";".
- * Further details see {@link #addUrlToClassPath(java.net.URL) }.
- * Path must contain only jars and class files (subfolders not included).
- *
- * @param path FQPN of the path to be added dynamically to the class path
- * or multiple paths separated by ";".
- * @return Number of jars and class files added.
- */
- public static int addFilesToClassPath(String path)
- {
- if (path == null || path.length() == 0) return 0;
- int n = 0;
- if (path.contains(";"))
- {
- String[] subPaths = path.split(";");
- for (String subPath : subPaths)
- {
- n = n + addFilesToClassPath(subPath);
- }
- }
- else
- {
- File dir = new File(path);
- File[] contents = dir.listFiles(); //Path Must contain jars and class files only
- for (int i = 0; i < contents.length; i++)
- {
- File file = contents[i];
- if (addFileToClassPath(file))
- n++;
- }
- }
- return n;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement