copyright The Portico Project 2008.

org.portico.shared.plugin
Class PluginLocator

java.lang.Object
  extended by org.portico.shared.plugin.PluginLocator

public class PluginLocator
extends Object

The PluginLocator will search a directory and locate all jar files that constitute Portico plugins. These are jar files that contain a Portico plugin configuration file (the name of the file differs depending on whether or not it is an RTI or LRC plugin).

The PluginLocator will also add any jar files it finds (regardless of whether they are plugins or not) to the SYSTEM classpath. This means that any dependencies that a plugin may have can be dropped into the plugin directory and they will be added to the classpath and be accessible from the plugin code.

Each PluginLocator keeps track of the jar files it has already loaded to ensure that each one is only loaded one. The PluginLocator is a singleton and it accessible via the instance() static method.

What is a plugin?

A plugin is just a jar file that contains plugin configuration data in certain locations inside it. All jars are just appended to the classpath, but plugin jar files should be processed by either the RTI or LRC to extract their configuration data.


Nested Class Summary
private  class PluginLocator.JarFilter
          Filter implementation that ensures we only deal with files that end in ".jar"
 
Field Summary
private static PluginLocator INSTANCE
           
private  Map<String,LoadedLibrary> loaded
           
private  Set<LoadedLibrary> lrcPlugins
           
private  Set<LoadedLibrary> rtiPlugins
           
 
Constructor Summary
private PluginLocator()
           
 
Method Summary
private  void appendClasspath(File entry, org.apache.log4j.Logger logger)
          This method will append the given location to the system classpath.
private  URL findResource(File jarfile, String resource)
          This method will attempt to locate a resource of the given name in the given jar file.
 Collection<LoadedLibrary> getAllLoadedLibraries()
          Get the collection of all libraries that have been found and appended to the system classpath (whether they are plugins or not).
 Set<LoadedLibrary> getLrcPlugins()
          Get the set of all loaded libraries that contain LRC plugin configuration data.
 Set<LoadedLibrary> getRtiPlugins()
          Get the set of all loaded libraries that contain RTI plugin configuration data.
static PluginLocator instance()
           
 List<LoadedLibrary> process(org.apache.log4j.Logger logger)
          This method will scan the default plug-in directory (as identified by the value in the PorticoConstants.DEFAULT_PLUGIN_DIR variable).
 List<LoadedLibrary> process(String pluginDir, org.apache.log4j.Logger logger)
          This method is the same as process(Logger) except that you can specify the directory that you wish to scan.
private  List<LoadedLibrary> scan(String location, org.apache.log4j.Logger logger)
          This method will scan the given directory for all jar files and will return a list of LoadedLibrary instances containing the information about any that were found, as long as they were not previously loaded (previously loaded files will be ignored).
private  void scanForPluginData(LoadedLibrary library, org.apache.log4j.Logger logger)
          This method will scan the given library for any RTI or LRC plugin configuration data.
private  Set<URL> scanForPluginData(LoadedLibrary library, String resourceLocation, String manifestAttribute, org.apache.log4j.Logger logger)
          This method performs the actual scanning.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

INSTANCE

private static final PluginLocator INSTANCE

loaded

private Map<String,LoadedLibrary> loaded

rtiPlugins

private Set<LoadedLibrary> rtiPlugins

lrcPlugins

private Set<LoadedLibrary> lrcPlugins
Constructor Detail

PluginLocator

private PluginLocator()
Method Detail

process

public List<LoadedLibrary> process(org.apache.log4j.Logger logger)
                            throws JException
This method will scan the default plug-in directory (as identified by the value in the PorticoConstants.DEFAULT_PLUGIN_DIR variable). It will find all the contained jar files contained within and will add them to the *SYSTEM* classpath. However, each file will only be added to the classpath once, thus, if it was added previously, it will be ignored.

The method will return a list of LoadedLibrary instances containing location information about all the jar files that have been newly loaded as a result of this call.

Plugin Processing

After having added each jar file to the classpath, it will look inside them to see if they contain any RTI or LRC plugin configuration data (see the scanForPluginData(LoadedLibrary, String, String, Logger) method for information about how that data is found). If there is plugin data, its location within the jar file is added to the LoadedLibrary. Also, it is stored within this instance so that it can be reterived later.

Parameters:
logger - The logger that should be used to log any generated output
Returns:
A list of all the newly loaded jar files (those that are plugins and those that are just regular jar files
Throws:
JException - If there is a problem processing the directory, appending the system classpath or searching the jars for plugin data

process

public List<LoadedLibrary> process(String pluginDir,
                                   org.apache.log4j.Logger logger)
                            throws JException
This method is the same as process(Logger) except that you can specify the directory that you wish to scan. Note that at the end of the processing, the directory itself is also appended to the classpath

See process(Logger) for more information

Throws:
JException

scan

private List<LoadedLibrary> scan(String location,
                                 org.apache.log4j.Logger logger)
                          throws JException
This method will scan the given directory for all jar files and will return a list of LoadedLibrary instances containing the information about any that were found, as long as they were not previously loaded (previously loaded files will be ignored).

Each new library found will be added to the system classpath, but it will not be checked to see if it is a plugin or not.

Parameters:
location - The location to search
logger - The logger to send all relevant output to
Returns:
A list of library instances containing information about libraries that have not been previously loaded.
Throws:
JException - If there is a problem scanning the directory or appending to the system classpath

appendClasspath

private void appendClasspath(File entry,
                             org.apache.log4j.Logger logger)
                      throws JException
This method will append the given location to the system classpath. This uses a dirty cludge to achieve this goal, apologies in advance :(. Through reflection, it will make the addURL(URL) method of URLClassLoader available (it is protected) and invoke it. Given that the system class loader is a URLClassLoader, it will invoke the method on that instance, there-by adding the file to the system classpath.

This method will NOT check to see if the location has been previously added, it just does the appending and noting else.

Throws:
JException

scanForPluginData

private void scanForPluginData(LoadedLibrary library,
                               org.apache.log4j.Logger logger)
                        throws JException
This method will scan the given library for any RTI or LRC plugin configuration data. If some is found, the appropriate URLs are added to the library and a referece to the library is added to the internal collection within the PluginLocator.

For example, if RTI plugin data is found in the library, the URL of that file (or files) will be added to the library, and the library will be added to the set contained within this class of all the libraries that have RTI plugin data. If a library contains BOTH lrc and rti plugin data, the library will be added to both sets.

Parameters:
library - The library to scan for plugin data
logger - The logger to send any output to
Throws:
JException

scanForPluginData

private Set<URL> scanForPluginData(LoadedLibrary library,
                                   String resourceLocation,
                                   String manifestAttribute,
                                   org.apache.log4j.Logger logger)
                            throws JException
This method performs the actual scanning. It will *NOT* change the LoadedLibrary in any way, it will just search inside it for configuration data and return a set of URLs that point to anything it does find.

It will scan for configuration data two separate ways. Firstly, it will look for a file as a resource inside the jar. The location of that resource is specified by the first String parameter. If a file at that location is found, it is added to the set of URLs that are returned.

Secondly, the method will look at the jar manifest for additional directives on locations in the jar where configuration files might be located (provided the manifest exists). The method will look for any attributes in the main section that have the same name as the second String parameter. If there are any attributes of this name found (and there may be 0..*), it will treat the value as a location of a plugin configuration file relative to the root of the jar file. If you want, you can specify more than one location in a single value by using a ',' separated list.

Having found the location of more configuration files, the method will attempt to find those files are resources within the jar. If it is successful, the appropriate URL is added to the LoadedLibrary. If the resource cannot be found, an exception will be thrown. Unlike when looking for a resource in the default location, if the resource is not found here, it signals a configuration error (the manifest attribute points directly at a file that doesn't exist), hence the exception.

Example Manifest:

Below is an example of a manifest that contains pointers to additional RTI config files:

 Manifest-Version: 1.0
 Ant-Version: Apache Ant 1.6.5
 Created-By: 1.5.0_07-87 ("Apple Computer, Inc.")
 Built-By: tim
 Rti-Plugin: etc/pluginOne.plugin, other/extraPlugin.xml
 Rti-Plugin: anotherDir/anotherFile.properties
 
The manifest above identifies two plugin configuration files. It is expected that these are paths to config files WITHIN the jar, so after these have been extracted, there will be an attempt to load them as resources. Unlike when looking for the default resource (as in step 1), if the resource cannot be found, an exception will be thrown, as it signals a mis-configuration in the manifest.

Special Ant Manifest Building Note

Sadly, Ant (as at version 1.7.0) won't let you specify more than one attribute for a section with the same name. As such, if you want to specify multiple files, you will have to create a single attribute with a ',' separated list. However, realising how much of a pain this can be, we have expanded the processing capabilities such that any attribute STARTING with the same value as the second String parameter will be processed. Thus, you COULD have a file like:

 Manifest-Version: 1.0
 Ant-Version: Apache Ant 1.6.5
 Created-By: 1.5.0_07-87 ("Apple Computer, Inc.")
 Built-By: tim
 Rti-Plugin: etc/pluginOne.plugin
 Rti-Plugin2: other/extraPlugin.xml
 Rti-Plugin3: anotherDir/anotherFile.properties
 

Parameters:
library - The library to scan for plugin data
resourceLocation - The location within the jar file to look for a resource at
manifestAttribute - The name of the manifest main attribute that will contain pointers to files with config data. There may be more than one of these.
logger - The logger to send all output to
Returns:
A set of URLs that point to all the located configuration files inside the library
Throws:
JException - If the manifest points to a config file that doesn't exist in the jar

findResource

private URL findResource(File jarfile,
                         String resource)
This method will attempt to locate a resource of the given name in the given jar file.

Parameters:
jarfile - The jar file
resource - The resource to locate
Returns:
A URL pointing to the resource if it is found, null if it is not
Throws:
MalformedURLException - If there is a problem working with the jar file

getAllLoadedLibraries

public Collection<LoadedLibrary> getAllLoadedLibraries()
Get the collection of all libraries that have been found and appended to the system classpath (whether they are plugins or not). If there are none, an empty collection is returned.


getRtiPlugins

public Set<LoadedLibrary> getRtiPlugins()
Get the set of all loaded libraries that contain RTI plugin configuration data. If there are none, an empty set is returned.


getLrcPlugins

public Set<LoadedLibrary> getLrcPlugins()
Get the set of all loaded libraries that contain LRC plugin configuration data. If there are none, an empty set is returned.


instance

public static PluginLocator instance()

copyright The Portico Project 2008.