[Jguiraffe-developers] SF.net SVN: jguiraffe:[211] trunk/core
Brought to you by:
oheger
|
From: <oh...@us...> - 2012-07-10 19:49:25
|
Revision: 211
http://jguiraffe.svn.sourceforge.net/jguiraffe/?rev=211&view=rev
Author: oheger
Date: 2012-07-10 19:49:13 +0000 (Tue, 10 Jul 2012)
Log Message:
-----------
[3535847] Added OSGi support.
- The maven build now generates an OSGi bundle.
- Fixed various class loader problems, e.g. in ClassPathLocator or when locating resources or icons.
- Added support for exit handlers to Application.
Modified Paths:
--------------
trunk/core/pom.xml
trunk/core/src/main/java/net/sf/jguiraffe/di/impl/DefaultClassLoaderProvider.java
trunk/core/src/main/java/net/sf/jguiraffe/gui/app/Application.java
trunk/core/src/main/java/net/sf/jguiraffe/gui/builder/components/tags/IconTag.java
trunk/core/src/main/java/net/sf/jguiraffe/gui/builder/impl/JellyBuilder.java
trunk/core/src/main/java/net/sf/jguiraffe/locators/ClassPathLocator.java
trunk/core/src/main/java/net/sf/jguiraffe/locators/LocatorConverter.java
trunk/core/src/main/java/net/sf/jguiraffe/locators/LocatorUtils.java
trunk/core/src/main/java/net/sf/jguiraffe/resources/impl/bundle/BundleResourceGroup.java
trunk/core/src/main/java/net/sf/jguiraffe/resources/impl/bundle/BundleResourceLoader.java
trunk/core/src/main/resources/defaultbeans.jelly
trunk/core/src/test/java/net/sf/jguiraffe/di/impl/TestDefaultClassLoaderProvider.java
trunk/core/src/test/java/net/sf/jguiraffe/di/impl/TestDefaultDependencyProvider.java
trunk/core/src/test/java/net/sf/jguiraffe/gui/app/TestApplication.java
trunk/core/src/test/java/net/sf/jguiraffe/gui/app/TestDefaultBeans.java
trunk/core/src/test/java/net/sf/jguiraffe/gui/builder/components/tags/TestIconTag.java
trunk/core/src/test/java/net/sf/jguiraffe/gui/builder/impl/TestJellyBuilder.java
trunk/core/src/test/java/net/sf/jguiraffe/locators/TestClassPathLocator.java
trunk/core/src/test/java/net/sf/jguiraffe/locators/TestLocatorConverter.java
trunk/core/src/test/java/net/sf/jguiraffe/locators/TestLocatorUtils.java
trunk/core/src/test/java/net/sf/jguiraffe/resources/impl/bundle/TestBundleResourceLoader.java
trunk/core/src/test/resources/jelly_scripts/icon.jelly
Modified: trunk/core/pom.xml
===================================================================
--- trunk/core/pom.xml 2012-02-12 18:16:04 UTC (rev 210)
+++ trunk/core/pom.xml 2012-07-10 19:49:13 UTC (rev 211)
@@ -29,7 +29,7 @@
<groupId>net.sf.jguiraffe</groupId>
<artifactId>jguiraffe</artifactId>
- <packaging>jar</packaging>
+ <packaging>bundle</packaging>
<name>JGUIraffe</name>
<description>Java GUI Resource and Application Framework with Form Extensions</description>
@@ -104,6 +104,22 @@
<groupId>com.mycila.maven-license-plugin</groupId>
<artifactId>maven-license-plugin</artifactId>
</plugin>
+
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ <inherited>true</inherited>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <_nouses>true</_nouses>
+ <_versionpolicy>
+ [$(version;==;$(@)), $(version;+;$(@)))
+ </_versionpolicy>
+ </instructions>
+ </configuration>
+ </plugin>
</plugins>
</build>
Modified: trunk/core/src/main/java/net/sf/jguiraffe/di/impl/DefaultClassLoaderProvider.java
===================================================================
--- trunk/core/src/main/java/net/sf/jguiraffe/di/impl/DefaultClassLoaderProvider.java 2012-02-12 18:16:04 UTC (rev 210)
+++ trunk/core/src/main/java/net/sf/jguiraffe/di/impl/DefaultClassLoaderProvider.java 2012-07-10 19:49:13 UTC (rev 211)
@@ -35,27 +35,69 @@
* can be set. If none has been set, the class loader that loaded this class is
* returned as default class loader.
* </p>
+ * <p>
+ * Per default, classes of the library (starting with the prefix
+ * {@code net.sf.jguiraffe}) are always loaded by the class loader which loaded
+ * this class. This makes sense for instance in an OSGi environment: it
+ * allows access even to internal implementation classes. This behavior can be
+ * disabled by setting the {@code handleInternalClasses} property to
+ * <b>false</b>. Then the selected class loader is used to load all classes.
+ * </p>
*
* @author Oliver Heger
* @version $Id$
*/
public class DefaultClassLoaderProvider implements ClassLoaderProvider
{
+ /** The prefix for class names which belong to this library. */
+ private static final String LIBRARY_CLASS_PREFIX = "net.sf.jguiraffe.";
+
/** A map with the class loaders registered at this object. */
private final Map<String, ClassLoader> mapLoaders;
/** Stores the default class loader name. */
private volatile String defaultLoaderName;
+ /** A flag whether internal classes should be treated in a special way. */
+ private final boolean handleInternalClasses;
+
/**
* Creates a new instance of {@code DefaultClassLoaderProvider}.
*/
public DefaultClassLoaderProvider()
{
+ this(true);
+ }
+
+ /**
+ * Creates a new instance of {@code DefaultClassLoaderProvider} and sets the
+ * flag whether internal classes should be handled in a special way.
+ *
+ * @param fHandleInternalClasses the value of the flag
+ * @since 1.2
+ */
+ public DefaultClassLoaderProvider(boolean fHandleInternalClasses)
+ {
mapLoaders = new ConcurrentHashMap<String, ClassLoader>();
+ handleInternalClasses = fHandleInternalClasses;
}
/**
+ * Returns a flag whether internal library classes are handled in a special
+ * way by this class loader provider. If this property is <b>true</b>, all
+ * classes belonging to this library are loaded by the class loader which
+ * also loaded this class.
+ *
+ * @return <b>true</b> if library classes are handled in a special way,
+ * <b>false</b> otherwise
+ * @since 1.2
+ */
+ public boolean isHandleInternalClasses()
+ {
+ return handleInternalClasses;
+ }
+
+ /**
* Returns a set with the names of the class loaders that have been
* registered at this object. All these names can be passed into the {@code
* getClassLoader()} method.
@@ -71,7 +113,7 @@
/**
* Returns the class loader specified by the given symbolic name. This
* method supports all variants: the default class loader (in this case the
- * name is <b>null</b>, the context class loader, and a registered class
+ * name is <b>null</b>), the context class loader, and a registered class
* loader.
*
* @param name the name of the class loader
@@ -122,7 +164,8 @@
*/
public Class<?> loadClass(String name, String loaderRef)
{
- return ReflectionUtils.loadClass(name, getClassLoader(loaderRef));
+ return ReflectionUtils.loadClass(name,
+ determineClassLoader(name, loaderRef));
}
/**
@@ -163,4 +206,19 @@
{
defaultLoaderName = loaderName;
}
+
+ /**
+ * Obtains the class loader for loading the specified class.
+ *
+ * @param clsName the class name
+ * @param loaderRef the reference to the class loader
+ * @return the class loader for loading this class
+ * @throws IllegalArgumentException if the class name is <b>null</b>
+ */
+ private ClassLoader determineClassLoader(String clsName, String loaderRef)
+ {
+ return (isHandleInternalClasses() && clsName != null && clsName
+ .startsWith(LIBRARY_CLASS_PREFIX)) ? getClass()
+ .getClassLoader() : getClassLoader(loaderRef);
+ }
}
Modified: trunk/core/src/main/java/net/sf/jguiraffe/gui/app/Application.java
===================================================================
--- trunk/core/src/main/java/net/sf/jguiraffe/gui/app/Application.java 2012-02-12 18:16:04 UTC (rev 210)
+++ trunk/core/src/main/java/net/sf/jguiraffe/gui/app/Application.java 2012-07-10 19:49:13 UTC (rev 211)
@@ -19,9 +19,11 @@
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
+import java.util.concurrent.atomic.AtomicReference;
import javax.swing.event.EventListenerList;
@@ -74,7 +76,7 @@
* the application's configuration file.</li>
* <li>This configuration file is loaded using commons-configuration.</li>
* <li>From properties defined in the application's configuration the
- * <code>ApplicationContext</code> is created and initialized. This includes
+ * {@code ApplicationContext} is created and initialized. This includes
* setting up a resource manager.</li>
* <li>The name of the application's main GUI builder script is also determined
* by configuration properties. This script is executed, and the resulting main
@@ -85,15 +87,15 @@
* Per default the application's configuration file is expected to be located in
* the class path and has the name <em>config.xml</em>. This can be changed
* using system properties: The property
- * <code>net.sf.jguiraffe.configName</code> allows to change the name of the
+ * {@code net.sf.jguiraffe.configName} allows to change the name of the
* configuration file. If defined, a file with this name will be searched in the
- * class path. If the property <code>net.sf.jguiraffe.configURL</code> is
+ * class path. If the property {@code net.sf.jguiraffe.configURL} is
* provided, the class tries to load this file directly from this URL.
* </p>
* <p>
* A bunch of configuration properties is evaluated by this class to perform the
* correct setup. All of these must be placed in a section called
- * <code>framework</code>. The following table lists the available properties:
+ * {@code framework}. The following table lists the available properties:
* </p>
* <p>
* <table border="1">
@@ -106,10 +108,10 @@
* <td valign="top">appctx</td>
* <td>In this section some properties of the application context are defined:
* <dl>
- * <dt><code>locale</code></dt>
+ * <dt>{@code locale}</dt>
* <dd>Here the locale to be set at startup can be specified. If the property is
* missing, the system's default locale will be used.</dd>
- * <dt><code>defaultResourceGroup</code></dt>
+ * <dt>{@code defaultResourceGroup}</dt>
* <dd>Allows to define a default resource group that is used by the resource
* manager when no specific resource group is specified.</dd>
* </dl>
@@ -123,25 +125,25 @@
* are optional - meaningful default values are applied if a value is not set.
* The following sub elements are supported:
* <dl>
- * <dt><code>beanBuilderFactory</code></dt>
+ * <dt>{@code beanBuilderFactory}</dt>
* <dd>Specifies the full qualified name of the {@link BeanBuilderFactory}
* implementation that is used to obtain bean builder instances. Here the
* implementation class and additional initialization properties can be
* specified.</dd>
- * <dt><code>beandefinitions</code></dt>
- * <dd>In this subsection an arbitrary number of <code>beandefinition</code>
- * elements can be specified. Each <code>beandefinition</code> element points to
+ * <dt>{@code beandefinitions}</dt>
+ * <dd>In this subsection an arbitrary number of {@code beandefinition}
+ * elements can be specified. Each {@code beandefinition} element points to
* a script with bean definitions. These scripts will be processed by the
* default bean builder.</dd>
- * <dt><code>menuIcon</code></dt>
+ * <dt>{@code menuIcon}</dt>
* <dd>An optional boolean flag that determines whether menu items should be
* rendered with an icon if one is defined. Note that this may not work on all
* platforms. The default value for this flag is <b>false</b>.</dd>
- * <dt><code>toolbarText</code></dt>
+ * <dt>{@code toolbarText}</dt>
* <dd>An optional boolean flag that determines whether toolbar buttons should
* display their text. Note that this may not be supported by all platforms. The
* default value of this flag is <b>false</b>.</dd>
- * <dt><code>mainScript</code></dt>
+ * <dt>{@code mainScript}</dt>
* <dd>With this property the name of the main builder script can be specified.
* If defined, the script will be executed using the application's builder. If
* this results in a window, this window will be displayed.</dd></td>
@@ -155,13 +157,13 @@
* again on next application start. The following properties can be defined in
* this section:
* <dl>
- * <dt><code>xpos</code></dt>
+ * <dt>{@code xpos}</dt>
* <dd>Defines the x position of the main window.</dd>
- * <dt><code>ypos</code></dt>
+ * <dt>{@code ypos}</dt>
* <dd>Defines the y position of the main window.</dd>
- * <dt><code>width</code></dt>
+ * <dt>{@code width}</dt>
* <dd>Defines the width position of the main window.</dd>
- * <dt><code>height</code></dt>
+ * <dt>{@code height}</dt>
* <dd>Defines the height position of the main window.</dd></td>
* <td valign="top">Yes</td>
* </tr>
@@ -197,7 +199,7 @@
* </p>
* <p>
* To override bean definitions, use the
- * <code>framework.builder.beandefinitions</code> section in the application's
+ * {@code framework.builder.beandefinitions} section in the application's
* main configuration file (see above). In this section the names of an
* arbitrary number of bean definition files can be specified (the files will be
* loaded from the class path). Using the predefined names for the default beans
@@ -333,7 +335,17 @@
/** Constant for the name of the user configuration. */
public static final String USRCONF_NAME = "userConfig";
- /** Constant for the default beann builder factory class. */
+ /**
+ * Constant for the name of the class loader which loaded the application
+ * class. This class loader is set as the default class loader at the
+ * {@code ClassLoaderProvider} created at startup.
+ *
+ * @since 1.2
+ */
+ public static final String CLASS_LOADER = BEAN_PREFIX
+ + "Application.classLoader";
+
+ /** Constant for the default bean builder factory class. */
private static final Class<?> DEF_BEAN_BUILDER_FACTORY_CLS = JellyBeanBuilderFactory.class;
/** Constant for the script with the default bean definitions. */
@@ -365,12 +377,32 @@
private final Collection<BeanBuilderResult> beanBuilderResults;
/**
- * Creates a new instance of <code>Application</code>.
+ * The default exit handler. This instance is returned if no specific exit
+ * handler has been set. It calls {@code System.exit()} with the current exit
+ * code.
*/
+ private final Runnable defaultExitHandler = new Runnable()
+ {
+ public void run()
+ {
+ System.exit(getExitCode());
+ }
+ };
+
+ /** The current exit handler of this application. */
+ private final AtomicReference<Runnable> exitHandler;
+
+ /** The exit code of this application. */
+ private int exitCode;
+
+ /**
+ * Creates a new instance of {@code Application}.
+ */
public Application()
{
shutdownListeners = new EventListenerList();
beanBuilderResults = new ArrayList<BeanBuilderResult>();
+ exitHandler = new AtomicReference<Runnable>();
}
/**
@@ -421,7 +453,7 @@
/**
* Returns a reference to the actual application context.
*
- * @return the <code>ApplicationContext</code>
+ * @return the {@code ApplicationContext}
*/
public ApplicationContext getApplicationContext()
{
@@ -439,11 +471,11 @@
}
/**
- * Returns the <code>BeanBuilderFactory</code> for obtaining a bean
+ * Returns the {@code BeanBuilderFactory} for obtaining a bean
* builder. This method can be used when a bean definition file is to be
* processed.
*
- * @return the <code>BeanBuilderFactory</code>
+ * @return the {@code BeanBuilderFactory}
*/
public BeanBuilderFactory getBeanBuilderFactory()
{
@@ -451,11 +483,11 @@
}
/**
- * Allows to set the <code>BeanBuilderFactory</code>. Normally it is not
+ * Allows to set the {@code BeanBuilderFactory}. Normally it is not
* necessary to set this property. When the application is initialized it
* creates a default factory.
*
- * @param beanBuilderFactory the new <code>BeanBuilderFactory</code>
+ * @param beanBuilderFactory the new {@code BeanBuilderFactory}
*/
public void setBeanBuilderFactory(BeanBuilderFactory beanBuilderFactory)
{
@@ -492,16 +524,20 @@
* name of a file (either relative or absolute)
* @param name the resource name
* @return the URL to the resource or <b>null </b> if it cannot be found
+ * @deprecated This method does not make sense in the public interface of
+ * this class. It will be removed in later versions. Use corresponding
+ * functionality from the {@code LocatorUtils} class instead.
*/
+ @Deprecated
public static URL resolveResourceURL(String url, String name)
{
return LocatorUtils.locate(url, name);
}
/**
- * Tries to the set a reference to the global <code>Application</code>
+ * Tries to the set a reference to the global {@code Application}
* object in the target object. If the target object implements the
- * <code>ApplicationClient</code> interface, the reference can be set.
+ * {@code ApplicationClient} interface, the reference can be set.
*
* @param target the target object
* @param ref the application reference to set
@@ -522,7 +558,7 @@
* configuration definition file must include an entry for the user
* configuration that is identified by its name. Per default the name is
* "userConfig", but can be altered with the
- * <code>userconfigname</code> property. The following example fragment
+ * {@code userconfigname} property. The following example fragment
* from the application's configuration definition file demonstrates how the
* user configuration should be declared:
* </p>
@@ -539,20 +575,20 @@
*
* </p>
* <p>
- * In this example the attributes starting with <code>config-</code> are
- * of special importance. With <code>config-name</code> the
+ * In this example the attributes starting with {@code config-} are
+ * of special importance. With {@code config-name} the
* configuration's name is specified, which is necessary for the framework
- * to retrieve the correct user configuration. <code>config-optional</code>
+ * to retrieve the correct user configuration. {@code config-optional}
* declares this configuration source as optional. This means that it won't
* cause an error when this source cannot be loaded (which will probably be
* the case when a user starts this application for the first time). The
- * <code>config-forceCreate</code> attribute finally tells the
+ * {@code config-forceCreate} attribute finally tells the
* configuration framework to create an empty configuration when loading of
* the configuration file fails. This will cause the configuration to be
* automatically created for the new user. If the user customizes the
* application, these settings can be stored in this configuration. When the
* application terminates it checks the value of the
- * <code>storeuserconfig</code> property. If this is set to <b>true</b>,
+ * {@code storeuserconfig} property. If this is set to <b>true</b>,
* the user configuration will be stored. So the next time the application
* starts it will be found there and override the values in all other
* configuration sources.
@@ -587,9 +623,9 @@
/**
* Stores the configuration with user specific settings. This method obtains
* the user configuration by calling the
- * <code>{@link #getUserConfiguration() getUserConfiguration()}</code>
+ * {@link #getUserConfiguration()}
* method. It expects that the user configuration implements the
- * <code>FileConfiguration</code> interface. If a different configuration
+ * {@code FileConfiguration} interface. If a different configuration
* type is used as user configuration, this method should also be adapted.
*
* @throws ApplicationException if an error occurs
@@ -669,7 +705,7 @@
/**
* Returns the URL to the configuration file. This URL is determined by the
- * properties <code>configURL</code> and <code>configResourceName</code>.
+ * properties {@code configURL} and {@code configResourceName}.
*
* @return the URL to the application's main configuration file
* @throws ApplicationRuntimeException if the configuration file cannot be
@@ -677,7 +713,9 @@
*/
protected URL fetchConfigURL()
{
- URL url = resolveResourceURL(getConfigURL(), getConfigResourceName());
+ URL url =
+ LocatorUtils.locate(getConfigURL(), getConfigResourceName(),
+ getClass().getClassLoader());
if (url == null)
{
throw new ApplicationRuntimeException(
@@ -688,7 +726,7 @@
/**
* Creates the configuration for this application. This method calls
- * <code>fetchConfigURL()</code> to determine the URL to the main
+ * {@code fetchConfigURL()} to determine the URL to the main
* configuration file. Then this file is loaded with commons-configuration.
*
* @return the configuration to use
@@ -702,7 +740,7 @@
/**
* Reads the application's configuration from the specified URL. The
- * <code>DefaultConfigurationBuilder</code> of
+ * {@code DefaultConfigurationBuilder} of
* <em>Commons Configuration</em> is used for reading the configuration.
* Occurring exceptions are re-thrown as runtime exceptions.
*
@@ -753,7 +791,7 @@
* will be returned.
*
* @param config the main configuration
- * @return the <code>BeanBuilderFactory</code> to be used
+ * @return the {@code BeanBuilderFactory} to be used
*/
protected BeanBuilderFactory createBeanBuilderFactory(Configuration config)
{
@@ -767,7 +805,7 @@
/**
* Initializes the application's bean definitions. This implementation will
* first process the framework-internal bean definition file, which defines
- * the standard beans. After that <code>findBeanDefinitions()</code> is
+ * the standard beans. After that {@code findBeanDefinitions()} is
* called for obtaining a list of additional definition files to be
* evaluated. Finally a bean context is created allowing access to all beans
* defined this way. This algorithm allows concrete applications to define
@@ -800,7 +838,8 @@
}
// Now process custom bean definitions
- processBeanDefinitions(findBeanDefinitions(config), context, clpInit);
+ processBeanDefinitions(findBeanDefinitions(config, context), context,
+ clpInit);
return context;
}
@@ -814,8 +853,9 @@
* ClassLoaderProvider}. It can even create a completely new object (the
* {@code ClassLoaderProvider} returned by this method will become the
* global {@code ClassLoaderProvider}; it need not be the same object as was
- * passed to this method). This base implementation simply returns the
- * passed in argument without any modifications.
+ * passed to this method). This base implementation registers the
+ * class loader which has loaded the concrete {@code Application} sub
+ * class and makes it the default class loader.
*
* @param clp the {@code ClassLoaderProvider} as obtained from the default
* beans
@@ -825,6 +865,8 @@
protected ClassLoaderProvider initClassLoaderProvider(
ClassLoaderProvider clp)
{
+ clp.registerClassLoader(CLASS_LOADER, getClass().getClassLoader());
+ clp.setDefaultClassLoaderName(CLASS_LOADER);
return clp;
}
@@ -858,26 +900,56 @@
/**
* Returns a collection with additional bean definition files to process.
+ *
+ * @param config the main configuration source
+ * @return a list with locators to bean definition files to be processed
+ * (can be <b>null</b>)
+ * @deprecated This method is replaced by
+ * {@link #findBeanDefinitions(Configuration, BeanContext)}. It
+ * is still called during application initialization to keep
+ * backwards compatibility, but this base implementation simply
+ * returns an empty collection.
+ */
+ @Deprecated
+ protected Collection<Locator> findBeanDefinitions(Configuration config)
+ {
+ return new ArrayList<Locator>(0);
+ }
+
+ /**
+ * Returns a collection with additional bean definition files to process.
* This method is called when the application context is created. All files
* contained in the returned list will be processed by the bean builder.
* This base implementation obtains the value(s) of the
- * <code>framework.builder.beandefinitions.beandefinition</code>
- * configuration property. The values are interpreted as textual
- * representations of {@link Locator} objects which can be converted using
- * the {@link LocatorConverter} class. Strings that do not contain a locator
+ * {@code framework.builder.beandefinitions.beandefinition} configuration
+ * property. The values are interpreted as textual representations of
+ * {@link Locator} objects which can be converted using the
+ * {@link LocatorConverter} class. Strings that do not contain a locator
* type prefix (e.g. {@code classpath:} or {@code url:} are expected to be
* names of bean definition files, which can be read from the class path. If
* an application has different requirements for specifying additional bean
* definition files, this method can be overridden.
*
* @param config the main configuration source
+ * @param beanCtx the current {@code BeanContext}
* @return a list with locators to bean definition files to be processed
* (can be <b>null</b>)
+ * @since 1.2
*/
- protected Collection<Locator> findBeanDefinitions(Configuration config)
+ protected Collection<Locator> findBeanDefinitions(Configuration config,
+ BeanContext beanCtx)
{
List<?> defLocators = config.getList(PROP_BEAN_DEFS);
- Collection<Locator> result = new ArrayList<Locator>(defLocators.size());
+ // for backwards compatibility reasons call old method
+ Collection<Locator> locs = findBeanDefinitions(config);
+ if (locs == null)
+ {
+ locs = Collections.emptyList();
+ }
+
+ Collection<Locator> result =
+ new ArrayList<Locator>(defLocators.size() + locs.size());
+ result.addAll(locs);
LocatorConverter converter = null;
for (Iterator<?> it = defLocators.iterator(); it.hasNext();)
@@ -888,14 +960,16 @@
{
if (converter == null)
{
- converter = new LocatorConverter();
+ converter =
+ new LocatorConverter(
+ beanCtx.getBean(ClassLoaderProvider.class));
}
result.add((Locator) converter.convert(Locator.class,
locatorRep));
}
else
{
- result.add(ClassPathLocator.getInstance(strLocatorRep));
+ result.add(cpLocator(strLocatorRep));
}
}
return result;
@@ -999,8 +1073,7 @@
{
if (config.containsKey(PROP_BUILDER_MAIN_SCRIPT))
{
- return ClassPathLocator.getInstance(config
- .getString(PROP_BUILDER_MAIN_SCRIPT));
+ return cpLocator(config.getString(PROP_BUILDER_MAIN_SCRIPT));
}
else
{
@@ -1092,7 +1165,7 @@
}
/**
- * Returns the <code>GUISynchronizer</code> object used by this
+ * Returns the {@code GUISynchronizer} object used by this
* application. This object can be used to deal with the event dispatch
* thread.
*
@@ -1104,7 +1177,7 @@
}
/**
- * Sets the <code>GUISynchronizer</code> object to be used by this
+ * Sets the {@code GUISynchronizer} object to be used by this
* application. This object can be used for safe GUI updates that need to
* take place at the event dispatch thread. It will also set at the
* application's command queue, so that always the same synchronizer is
@@ -1120,7 +1193,7 @@
/**
* Executes the given command. The command is put into the internal command
* queue. It is then executed in another thread. If the passed in command
- * implements the <code>ApplicationClient</code> interface, a reference to
+ * implements the {@code ApplicationClient} interface, a reference to
* this application will be automatically set before execution.
*
* @param cmd the command to be executed
@@ -1138,7 +1211,7 @@
* a message is displayed (using the message output object) to the user
* asking if the application should be ended anyway. The resource for this
* message is defined by the passed in parameter, which can be a resource ID
- * or an <code>ApplicationResourceDef</code> object. Only if the user
+ * or an {@code ApplicationResourceDef} object. Only if the user
* confirms this, the application will be ended.
*
* @param msgres defines the resource of the message to be displayed
@@ -1184,14 +1257,57 @@
}
/**
+ * Returns the current <em>exit handler</em> of this application. This is
+ * the object called during a {@code shutdown()} operation. This method
+ * never returns <b>null</b>. If no exit handler has been set, a default one
+ * is returned. The default exit handler terminates this application by
+ * calling {@code System.exit()} with the current exit code.
+ *
+ * @return the exit handler of this application
+ * @since 1.2
+ */
+ public Runnable getExitHandler()
+ {
+ Runnable eh = exitHandler.get();
+ return (eh != null) ? eh : defaultExitHandler;
+ }
+
+ /**
+ * Sets the <em>exit handler</em> for this application. The exit handler is
+ * called eventually by {@code shutdown()}. Its task is to ultimately
+ * terminate this application, e.g. by calling {@code System.exit()}.
+ *
+ * @param handler the exit handler for this application (may be <b>null</b>)
+ * @since 1.2
+ */
+ public void setExitHandler(Runnable handler)
+ {
+ exitHandler.set(handler);
+ }
+
+ /**
+ * Returns the current exit code for this application. This value is only
+ * defined during a {@code shutdown()} operation. This method is intended to
+ * be called by an <em>exit handler</em> to find out the exit status of the
+ * application.
+ *
+ * @return this application's exit status
+ * @see #setExitHandler(Runnable)
+ * @since 1.2
+ */
+ public int getExitCode()
+ {
+ return exitCode;
+ }
+
+ /**
* A hook for shutdown. This method is called by the default implementation
- * of the <code>shutdown()</code> method. Here application specific
+ * of the {@code shutdown()} method. Here application specific
* cleanup can be placed. Note: if this method is overloaded in a derived
* class, the inherited method should be called. This implementation cares
* for storing the user specific configuration if the
- * <code>storeuserconfig</code> property is <b>true</b>. Before that the
- * <code>{@link #updateUserConfiguration() updateUserConfiguration()</code>
- * method is called.
+ * {@code storeuserconfig} property is <b>true</b>. Before that the
+ * {@link #updateUserConfiguration()} method is called.
*/
protected void onShutdown()
{
@@ -1212,7 +1328,7 @@
/**
* Updates the user configuration. This method is called during shutdown if
- * the <code>storeuserconfig</code> configuration property is set. Here
+ * the {@code storeuserconfig} configuration property is set. Here
* actual settings can be written in the user configuration object so that
* they can be restored the next time the application is started again. This
* implementation stores the actual bounds of the main frame in the user
@@ -1232,7 +1348,7 @@
}
/**
- * Calls the <code>canShutdown()</code> method on all registered shutdown
+ * Calls the {@code canShutdown()} method on all registered shutdown
* listeners. If one of them returns <b>false </b>, the remaining listeners
* are not invoked and shutdown process is canceled.
*
@@ -1300,16 +1416,22 @@
/**
* Terminates this application. This method is called by
- * {@link #shutdown(Object, Object)} at the very end. It simply calls
- * <code>System.exit()</code> with the passed in exit code to end this
- * application.
+ * {@link #shutdown(Object, Object)} at the very end. It calls the
+ * <em>exit handler</em>. This object is responsible for actually
+ * terminating this application.
*
* @param exitCode the exit code
+ * @see #setExitHandler(Runnable)
*/
protected void exitApplication(int exitCode)
{
- log.info("Application ends with exit code " + exitCode);
- System.exit(exitCode);
+ if (log.isInfoEnabled())
+ {
+ log.info("Application ends with exit code " + exitCode);
+ log.info("Calling exit handler.");
+ }
+
+ getExitHandler().run();
}
/**
@@ -1345,11 +1467,11 @@
/**
* Starts an application. This method performs all steps to initialize and
- * startup an <code>Application</code> object. First the system properties
+ * startup an {@code Application} object. First the system properties
* are checked if the configuration file is specified. Then the application
* is given the opportunity of processing its command line. Finally its
- * <code>run()</code> method is invoked, which starts the application. A
- * typical use case for this method is to create an <code>Application</code>
+ * {@code run()} method is invoked, which starts the application. A
+ * typical use case for this method is to create an {@code Application}
* instance (which also can be of a derived class) and pass it to this
* method together with the command line array. The rest is done by this
* method.
@@ -1387,7 +1509,7 @@
* A main method for applications based on this framework. This method tries
* to determine the name of the configuration file from system properties.
* Then it creates an instance of this class, initializes it, and calls the
- * <code>startup()</code> method.
+ * {@code startup()} method.
*
* @param args command line arguments
* @throws ApplicationException if an error occurs
@@ -1398,16 +1520,18 @@
}
/**
- * Obtains the central <code>Application</code> instance from the specified
- * <code>BeanContext</code>. This method provides an easy way for obtaining
- * the <code>Application</code> when only the
- * <code>ApplicationContext</code> is known: just call
- * <code>Application myApp = Application.getInstance(appCtx.getBeanContext());</code>
- * . If the application cannot be found in the given bean context, an
+ * Obtains the central {@code Application} instance from the specified
+ * {@code BeanContext}. This method provides an easy way for obtaining
+ * the {@code Application} when only the {@code ApplicationContext} is
+ * known: just call
+ * <pre>
+ * Application myApp = Application.getInstance(appCtx.getBeanContext());
+ * </pre>
+ * If the application cannot be found in the given bean context, an
* exception is thrown.
*
* @param context the bean context
- * @return the <code>Application</code> object defined in this bean context
+ * @return the {@code Application} object defined in this bean context
* @throws net.sf.jguiraffe.di.InjectionException if the application bean
* cannot be found
* @throws IllegalArgumentException if the passed in context is <b>null</b>
@@ -1422,6 +1546,19 @@
}
/**
+ * Helper method for creating a {@code ClassPathLocator} which is configured
+ * with this application's class loader.
+ *
+ * @param resource the name of the resource to be loaded
+ * @return the newly created {@code ClassPathLocator}
+ */
+ private ClassPathLocator cpLocator(String resource)
+ {
+ return ClassPathLocator.getInstance(resource, getClass()
+ .getClassLoader());
+ }
+
+ /**
* Adds a bean to a bean store. This implementation creates a constant bean
* provider for the specified bean.
*
Modified: trunk/core/src/main/java/net/sf/jguiraffe/gui/builder/components/tags/IconTag.java
===================================================================
--- trunk/core/src/main/java/net/sf/jguiraffe/gui/builder/components/tags/IconTag.java 2012-02-12 18:16:04 UTC (rev 210)
+++ trunk/core/src/main/java/net/sf/jguiraffe/gui/builder/components/tags/IconTag.java 2012-07-10 19:49:13 UTC (rev 211)
@@ -31,27 +31,31 @@
* <p>
* This tag supports multiple ways for defining an icon:
* <ul>
- * <li>By specifying an URL using the <code>url</code> attribute.</li>
- * <li>By specifying a resource name using the <code>resource</code> attribute.
- * In this case the icon is searched on the class path.</li>
- * <li>By specifying an arbitrary <code>{@link Locator}</code> pointing to the
- * icon data using the <code>locator</code> attribute. This is actually the
- * generic form of the ways described above. The locator is looked up by its
- * name in the current bean context.</li>
- * <li>With the <code>ref</code> attribute an icon can be referenced that has
- * already been created and stored in the Jelly context (e.g by another
- * <code>icon</code> tag that had a <code>var</code> attribute (see below).</li>
+ * <li>By specifying an URL using the {@code url} attribute.</li>
+ * <li>By specifying a resource name using the {@code resource} attribute. In
+ * this case the icon is searched on the class path. Per default, the current
+ * default class loader is used for resolving the resource name. If a different
+ * class loader is desired, its name (as registered at the current
+ * {@code ClassLoaderProvider}) can be specified using the
+ * {@code resourceLoader} attribute.</li>
+ * <li>By specifying an arbitrary {@link Locator} pointing to the icon data
+ * using the {@code locator} attribute. This is actually the generic form of the
+ * ways described above. The locator is looked up by its name in the current
+ * bean context.</li>
+ * <li>With the {@code ref} attribute an icon can be referenced that has already
+ * been created and stored in the Jelly context (e.g by another {@code icon} tag
+ * that had a {@code var} attribute (see below).</li>
* </ul>
* Exactly one of these attributes must be present.
* </p>
* <p>
* The icon is created using the component manager. Then the tag searches for an
- * enclosing tag that implements the <code>{@link IconSupport}</code> interface.
- * If one is found, this tag is passed the icon. With the <code>var</code>
- * attribute the name of a variable can be specified, which is assigned the
- * icon. So it can be reused. At least one of the ways for storing an icon (the
- * <code>var</code> attribute or an <code>IconSupport</code> tag) must be
- * defined, otherwise an exception is thrown.
+ * enclosing tag that implements the {@link IconSupport} interface. If one is
+ * found, this tag is passed the icon. With the {@code var} attribute the name
+ * of a variable can be specified, which is assigned the icon. So it can be
+ * reused. At least one of the ways for storing an icon (the {@code var}
+ * attribute or an {@code IconSupport} tag) must be defined, otherwise an
+ * exception is thrown.
* </p>
*
* @author Oliver Heger
@@ -65,6 +69,9 @@
/** Stores the resource name of the icon. */
private String resource;
+ /** The name of the class loader for resolving a resource name. */
+ private String resourceLoader;
+
/** Stores the name of a variable, from which the icon should be fetched. */
private String ref;
@@ -97,6 +104,33 @@
}
/**
+ * Returns the name of the class loader for resolving the resource name.
+ *
+ * @return the name of the class loader
+ * @since 1.2
+ */
+ public String getResourceLoader()
+ {
+ return resourceLoader;
+ }
+
+ /**
+ * Setter method for the {@code resourceLoader} attribute. Here the name of
+ * a class loader for resolving the resource name can be provided. A class
+ * loader with this name is looked up using the current
+ * {@code ClassLoaderProvider}. If no class loader has been specified, the
+ * default one is used.
+ *
+ * @param resourceLoader the name of the class loader for resolving class
+ * path resources
+ * @since 1.2
+ */
+ public void setResourceLoader(String resourceLoader)
+ {
+ this.resourceLoader = resourceLoader;
+ }
+
+ /**
* Returns the URL that points to the icon.
*
* @return the URL
@@ -159,10 +193,10 @@
}
/**
- * Returns the name of the <code>Locator</code>, from which the icon should
+ * Returns the name of the {@code Locator}, from which the icon should
* be obtained.
*
- * @return the name of the <code>Locator</code>
+ * @return the name of the {@code Locator}
*/
public String getLocator()
{
@@ -170,12 +204,12 @@
}
/**
- * Setter method of the <code>locator</code> attribute. With this attribute
- * an arbitrary <code>Locator</code> can be specified, from which the icon
+ * Setter method of the {@code locator} attribute. With this attribute
+ * an arbitrary {@code Locator} can be specified, from which the icon
* data is loaded. The locator is looked up in the current bean context
* under the name specified here.
*
- * @param locator the name of <code>Locator</code> with the icon data
+ * @param locator the name of {@code Locator} with the icon data
*/
public void setLocator(String locator)
{
@@ -252,13 +286,13 @@
/**
* Fetches the locator for the icon. This method is called by
- * <code>createIcon()</code> when no reference attribute is specified, i.e.
- * the icon has to be obtained from a locator. If the <code>locator</code>
- * attribute is specified, the locator is looked up from the current bean
- * context. Otherwise a locator is created from the other convenience
- * attributes (<code>url</code> or <code>resource</code>).
+ * {@code createIcon()} when no reference attribute is specified, i.e. the
+ * icon has to be obtained from a locator. If the {@code locator} attribute
+ * is specified, the locator is looked up from the current bean context.
+ * Otherwise a locator is created from the other convenience attributes (
+ * {@code url} or {@code resource}).
*
- * @return the <code>Locator</code> that defines the icon
+ * @return the {@code Locator} that defines the icon
*/
protected Locator fetchLocator()
{
@@ -269,7 +303,10 @@
}
else if (getResource() != null)
{
- return ClassPathLocator.getInstance(getResource());
+ ClassLoader cl =
+ getBuilderData().getBeanContext().getClassLoaderProvider()
+ .getClassLoader(getResourceLoader());
+ return ClassPathLocator.getInstance(getResource(), cl);
}
else
{
Modified: trunk/core/src/main/java/net/sf/jguiraffe/gui/builder/impl/JellyBuilder.java
===================================================================
--- trunk/core/src/main/java/net/sf/jguiraffe/gui/builder/impl/JellyBuilder.java 2012-02-12 18:16:04 UTC (rev 210)
+++ trunk/core/src/main/java/net/sf/jguiraffe/gui/builder/impl/JellyBuilder.java 2012-07-10 19:49:13 UTC (rev 211)
@@ -21,6 +21,7 @@
import net.sf.jguiraffe.di.BeanContext;
import net.sf.jguiraffe.di.BeanCreationListener;
+import net.sf.jguiraffe.di.ClassLoaderProvider;
import net.sf.jguiraffe.di.ConversionHelper;
import net.sf.jguiraffe.di.InvocationHelper;
import net.sf.jguiraffe.di.MutableBeanStore;
@@ -442,6 +443,37 @@
}
/**
+ * Adds all converters in the specified map as default base class converters
+ * to this object using the specified {@code ClassLoaderProvider} to resolve
+ * class names. This method works like the method with the same name, but
+ * converter class are specified by name and resolved dynamically.
+ *
+ * @param converters the map with the converters to be added (must not be
+ * <b>null</b>
+ * @param clp the {@code ClassLoaderProvider} (must not be <b>null</b>)
+ * @throws IllegalArgumentException if the map is <b>null</b> or contains
+ * <b>null</b> entries or the {@code ClassLoaderProvider} is
+ * <b>null</b>
+ * @since 1.2
+ */
+ public void addDefaultBaseClassConverters(
+ Map<String, ? extends Converter> converters, ClassLoaderProvider clp)
+ {
+ checkConvertersMap(converters);
+ if (clp == null)
+ {
+ throw new IllegalArgumentException(
+ "ClassLoaderProvider must not be null!");
+ }
+
+ for (Map.Entry<String, ? extends Converter> e : converters.entrySet())
+ {
+ addDefaultBaseClassConverter(e.getValue(),
+ clp.loadClass(e.getKey(), null));
+ }
+ }
+
+ /**
* Removes all base class converters that have been added to this object
* before.
*/
@@ -985,7 +1017,7 @@
* @throws IllegalArgumentException if the map is invalid
*/
private static void checkConvertersMap(
- Map<Class<?>, ? extends Converter> converters)
+ Map<?, ? extends Converter> converters)
{
if (converters == null)
{
Modified: trunk/core/src/main/java/net/sf/jguiraffe/locators/ClassPathLocator.java
===================================================================
--- trunk/core/src/main/java/net/sf/jguiraffe/locators/ClassPathLocator.java 2012-02-12 18:16:04 UTC (rev 210)
+++ trunk/core/src/main/java/net/sf/jguiraffe/locators/ClassPathLocator.java 2012-07-10 19:49:13 UTC (rev 211)
@@ -17,21 +17,24 @@
import java.net.URL;
+import org.apache.commons.lang.ObjectUtils;
+
/**
* <p>
- * A specific <code>Locator</code> implementation that can obtain resources from
+ * A specific {@code Locator} implementation that can obtain resources from
* the class path.
* </p>
* <p>
- * This class is initialized with a resource name. The <code>getURL()</code>
+ * This class is initialized with a resource name. The {@code getURL()}
* method tries to find this resource from the class path (using the
* {@link LocatorUtils} class. No caching is performed; each invocation of
- * <code>getURL()</code> will look up the resource. Because a lookup takes the
- * context class loader into account, multiple invocations of
- * <code>getURL()</code> may yield different results.
+ * {@code getURL()} will look up the resource. Because a lookup might depend
+ * on the context class loader, multiple invocations of {@code getURL()} may
+ * yield different results. In addition, it is possible to specify the
+ * class loader to be used for resource lookup.
* </p>
* <p>
- * Instances of this class are created using the <code>getInstance()</code>
+ * Instances of this class are created using the {@code getInstance()}
* factory method. They are immutable and thus can be shared between multiple
* threads.
* </p>
@@ -44,16 +47,21 @@
/** Stores the name of the resource. */
private final String resourceName;
+ /** The default class loader for the resource lookup. */
+ private final ClassLoader classLoader;
+
/**
- * Creates a new instance of <code>ClassPathLocator</code> and sets the name
+ * Creates a new instance of {@code ClassPathLocator} and sets the name
* of the represented resource. To create an instance client code can use
- * the <code>getInstance()</code> factory method.
+ * the {@code getInstance()} factory method.
*
* @param resourceName the resource name
+ * @param cl the default class loader
*/
- private ClassPathLocator(String resourceName)
+ private ClassPathLocator(String resourceName, ClassLoader cl)
{
this.resourceName = resourceName;
+ classLoader = cl;
}
/**
@@ -67,7 +75,21 @@
}
/**
- * Returns a <code>ClassPathLocator</code> instance for the specified
+ * Returns the default class loader used by this locator when looking up the
+ * resource name. This is the class loader passed to the
+ * {@code getInstance()} method. It may be <b>null</b> if no specific class
+ * loader was provided when constructing this object.
+ *
+ * @return the default class loader for resource lookup
+ * @since 1.2
+ */
+ public ClassLoader getClassLoader()
+ {
+ return classLoader;
+ }
+
+ /**
+ * Returns a {@code ClassPathLocator} instance for the specified
* resource name.
*
* @param resourceName the name of the resource (must not be <b>null</b>)
@@ -76,28 +98,46 @@
*/
public static ClassPathLocator getInstance(String resourceName)
{
+ return getInstance(resourceName, null);
+ }
+
+ /**
+ * Returns a {@code ClassPathLocator} instance which looks up the specified
+ * resource name using the given class loader. If a {@code ClassLoader}
+ * reference is provided, this class loader is tried first when resolving
+ * the resource name. Otherwise, the default order of class loaders is used
+ * as implemented in {@link LocatorUtils}.
+ *
+ * @param resourceName the name of the resource (must not be <b>null</b>)
+ * @param cl an optional class loader to be used for resource lookup
+ * @return the instance with this resource name
+ * @throws IllegalArgumentException if the resource name is <b>null</b>
+ * @since 1.2
+ */
+ public static ClassPathLocator getInstance(String resourceName,
+ ClassLoader cl)
+ {
if (resourceName == null)
{
throw new IllegalArgumentException(
"Resource name must not be null!");
}
- return new ClassPathLocator(resourceName);
+ return new ClassPathLocator(resourceName, cl);
}
/**
* Returns the URL for the represented resource. This implementation uses
- * the
- * <code>{@link LocatorUtils#locateResource(String) locateResource()}</code>
- * method of <code>{@link LocatorUtils}</code> to find the resource on the
- * class path. If this fails, an exception is thrown.
+ * the {@link LocatorUtils#locateResource(String, ClassLoader)} method to
+ * find the resource on the class path. If this fails, an exception is
+ * thrown.
*
* @return the URL to the resource
* @throws LocatorException if the resource URL cannot be obtained
*/
public URL getURL()
{
- URL result = LocatorUtils.locateResource(getResourceName());
+ URL result = LocatorUtils.locateResource(getResourceName(), getClassLoader());
if (result == null)
{
throw new LocatorException("Cannot locate resource "
@@ -109,7 +149,8 @@
/**
* Compares this object with another one. Two instances of this class are
- * equal if and only if they refer to the same resource name.
+ * equal if and only if they refer to the same resource name and use the
+ * same default class loader.
*
* @param obj the object to be compared to
* @return a flag whether the objects are equal
@@ -127,7 +168,8 @@
}
ClassPathLocator c = (ClassPathLocator) obj;
- return getResourceName().equals(c.getResourceName());
+ return getResourceName().equals(c.getResourceName())
+ && ObjectUtils.equals(getClassLoader(), c.getClassLoader());
}
/**
@@ -138,7 +180,13 @@
@Override
public int hashCode()
{
- return getResourceName().hashCode();
+ final int factor = 31;
+ int result = getResourceName().hashCode();
+ if (getClassLoader() != null)
+ {
+ result = factor * result + getClassLoader().hashCode();
+ }
+ return result;
}
/**
Modified: trunk/core/src/main/java/net/sf/jguiraffe/locators/LocatorConverter.java
===================================================================
--- trunk/core/src/main/java/net/sf/jguiraffe/locators/LocatorConverter.java 2012-02-12 18:16:04 UTC (rev 210)
+++ trunk/core/src/main/java/net/sf/jguiraffe/locators/LocatorConverter.java 2012-07-10 19:49:13 UTC (rev 211)
@@ -17,6 +17,8 @@
import java.util.Locale;
+import net.sf.jguiraffe.di.ClassLoaderProvider;
+
import org.apache.commons.beanutils.ConversionException;
import org.apache.commons.beanutils.Converter;
@@ -47,8 +49,12 @@
* <tr>
* <td valign="top">classpath</td>
* <td>Creates a {@link ClassPathLocator} instance. The data is interpreted as a
- * resource name which is looked up on the current class path.</td>
- * <td>classpath:myresource.properties</td>
+ * resource name which is looked up on the current class path. Optionally, a
+ * class loader name can be provided separated by a semicolon. If this is used,
+ * the corresponding class loader is obtained from the
+ * {@link ClassLoaderProvider}; otherwise, the default class loader is used.</td>
+ * <td>classpath:myresource.properties<br>
+ * classpath:myresource.properties;myClassLoader</td>
* </tr>
* <tr>
* <td valign="top">file</td>
@@ -91,6 +97,54 @@
public static final char PREFIX_SEPARATOR = ':';
/**
+ * The separator for a class loader name. This character is evaluated for
+ * locator declarations of type classpath.
+ */
+ private static final char CL_SEPARATOR = ';';
+
+ /** The current class loader provider. */
+ private final ClassLoaderProvider classLoaderProvider;
+
+ /**
+ * Creates a new instance of {@code LocatorConverter} and initializes it
+ * with the given {@code ClassLoaderProvider}. Class loaders for class path
+ * locators are obtained from this provider.
+ *
+ * @param clp the {@code ClassLoaderProvider}
+ * @since 1.2
+ */
+ public LocatorConverter(ClassLoaderProvider clp)
+ {
+ classLoaderProvider = clp;
+ }
+
+ /**
+ * Creates a new instance of {@code LocatorConverter} without a class loader
+ * provider. A converter constructed this way cannot resolve any class
+ * loader names. This constructor exists for reasons of backwards
+ * compatibility. It is recommended to always provide a
+ * {@code ClassLoaderProvider}.
+ */
+ public LocatorConverter()
+ {
+ this(null);
+ }
+
+ /**
+ * Returns the {@code ClassLoaderProvider} used by this converter. This
+ * object is used to determine class loaders when locators for class path
+ * resources are to be created. Result may be <b>null</b> if no
+ * {@code ClassLoaderProvider} has been set.
+ *
+ * @return the current {@code ClassLoaderProvider}
+ * @since 1.2
+ */
+ public ClassLoaderProvider getClassLoaderProvider()
+ {
+ return classLoaderProvider;
+ }
+
+ /**
* Tries to convert the specified object to a {@link Locator}. The
* conversion is based on prefixes as described in the class comment.
*
@@ -159,7 +213,8 @@
LocatorRepresentation locRep = getRepresentation(rep.substring(0, pos));
try
{
- return locRep.createLocator(rep.substring(pos + 1));
+ return locRep.createLocator(rep.substring(pos + 1),
+ getClassLoaderProvider());
}
catch (LocatorException lex)
{
@@ -180,15 +235,34 @@
{
/**
* Creates a {@link ClassPathLocator}. The passed in data is
- * interpreted as the resource name.
+ * interpreted as the resource name. If it contains a class loader
+ * name (separated by a semicolon), this class loader is obtained
+ * from the given {@code ClassLoaderProvider} and passed to the
+ * newly created {@code Locator}.
*
* @param data data for the locator
* @return the new locator instance
*/
@Override
- public Locator createLocator(String data)
+ public Locator createLocator(String data, ClassLoaderProvider clp)
{
- return ClassPathLocator.getInstance(data);
+ String resourceName;
+ String clName;
+ int posCLName = data.indexOf(CL_SEPARATOR);
+ if (posCLName > 0)
+ {
+ resourceName = data.substring(0, posCLName);
+ clName = data.substring(posCLName + 1);
+ }
+ else
+ {
+ resourceName = data;
+ clName = null;
+ }
+ ClassLoader cl =
+ (clp != null) ? clp.getClassLoader(clName) : null;
+
+ return ClassPathLocator.getInstance(resourceName, cl);
}
},
@@ -203,7 +277,7 @@
* @return the new locator instance
*/
@Override
- public Locator createLocator(String data)
+ public Locator createLocator(String data, ClassLoaderProvider clp)
{
return FileLocator.getInstance(data);
}
@@ -220,7 +294,7 @@
* @return the new locator instance
*/
@Override
- public Locator createLocator(String data)
+ public Locator createLocator(String data, ClassLoaderProvider clp)
{
return URLLocator.getInstance(data);
}
@@ -232,8 +306,10 @@
* string. It is provided to the locator.
*
* @param data the data for the new locator
+ * @param clp the provider for class loaders
* @return the locator instance
*/
- public abstract Locator createLocator(String data);
+ public abstract Locator createLocator(String data,
+ ClassLoaderProvider clp);
}
}
Modified: trunk/core/src/main/java/net/sf/jguiraffe/locators/LocatorUtils.java
===================================================================
--- trunk/core/src/main/java/net/sf/jguiraffe/locators/LocatorUtils.java 2012-02-12 18:16:04 UTC (rev 210)
+++ trunk/core/src/main/java/net/sf/jguiraffe/locators/LocatorUtils.java 2012-07-10 19:49:13 UTC (rev 211)
@@ -85,14 +85,20 @@
}
/**
- * Tries to locate a resource in the class path. This method tries the
- * context, the default, and the system class loader to find the resource in
- * the class path.
+ * Tries to locate a resource in the class path using the specified class
+ * loader. If the {@code ClassLoader} parameter is not <b>null</b>, this
+ * class loader is tried first. If this fails, this method tries the
+ * context, the default, and the system class loader (in this order) to find
+ * the resource in the class path. Search stops as soon as the resource is
+ * found.
*
* @param resource the name of the resource
- * @re...
[truncated message content] |