My project uses a simple plugin mechanism based on multiple application contexts defined in plugin jars. However for this to work i have to include all of the plugin jars on the classpath. It would be nice if Spring could automatically load jars and containing components on it's own which are for example placed in the 'plugins' subdirectory of my project.
Is there some solution for this?
I went a bit furtherer and tried to solve this with Jar Class Loader.
Because i'm instantiating the Spring application context manually i can do the following:
GenericApplicationContext ctx = new GenericApplicationContext();
// Load context definitions from plugin jars
JarClassLoader jcl = new JarClassLoader();
jcl.add("plugins/");
XmlBeanDefinitionReader classPathBeansReader = new XmlBeanDefinitionReader(ctx);
classPathBeansReader.setBeanClassLoader(jcl);
classPathBeansReader.setResourceLoader(new PathMatchingResourcePatternResolver(jcl));
classPathBeansReader.loadBeanDefinitions("classpath*:META-INF/my-plugins-*.xml");
However this is not working. From Spring's log i can see that it doesnt read the XML definition in the plugin jar. If i replace the bottom block with
XmlBeanDefinitionReader classPathBeansReader = new XmlBeanDefinitionReader(ctx);
classPathBeansReader.setBeanClassLoader(jcl);
classPathBeansReader.loadBeanDefinitions(new ClassPathResource("META-INF/my-plugins-somemodule.xml",jcl));
it finds and loads the XML definition file and beans from the jar. However this way i'm hardwiring the XML resource name for one plugin, which i don't wan't. How can i make the pattern matching working with JCL?
You might like to consider using OSGi as your plugin loading mechanism.
The Eclipse Virgo open source project provides an OSGi runtime environment that is suited to your project because it has Spring built in. Virgo offers Tomcat and Jetty based servers and a standalone kernel which can be used on its own or to construct other types of server. See the Virgo web site for features and benefits.
OSGi has quite a different design point than you may be used to in Java. It gives you controlled isolation between plugins, known as bundles, unlike a linear classpath. Bundles are wired together in a dependency graph and support versioning and dynamic life cycle operations.
The preferred means for a bundle to use the facilities of other bundles is via the OSGi service registry. The Spring DM project enables normal Spring beans to be published to the service registry and looked up from the service registry. Spring DM is also built in to Virgo. Spring DM has been donated to Eclipse as the Gemini Blueprint project.
To use Virgo, you would add some Spring DM configuration to each of your plugins in the META-INF/spring directory. This configuration, which is a normal XML Spring configuration file, can reference beans in your other Spring files and publish those beans in the service registry, or can provide beans for services looked up in the service registry which may then be referenced by, and injected into, beans in your other Spring files.
You would then deploy your plugins into Virgo using any of the supported mechanisms. You could simply drop them in dependency order into the pickup directory. Or you could use the web admin console or shell console to deploy then.
Alternatively, and this would seem to fit your requirement rather well, you could place plugins providing packages for other plugins in the Virgo repository by dropping them into repository/usr and then deploy the plugins which depend (transitively) on the repository plugins via the pickup directory or web admin console. Virgo will automatically deploy the dependencies from the repository as the dependent plugins are deployed.
You could also group plugins together either in an archive, known as a PAR, or by storing them in the Virgo repository and then referencing them in an XML file, known as a plan. You would then deploy the PAR or plan as describe above. You can even put some of the dependencies in the Virgo repository and reduce the PAR or plan to contain just the dependent plugins.
If you would like further information about Virgo, just ask on the Virgo community forum.
It seems that JCL doesn't override ClassLoader#findResource(String)
JarClassLoader.java
AbstractClassLoader.java
PathMatchingResourcePatternResolver JavaDocs state:
Internally, this happens via a ClassLoader.getResources() call
JavaDocs for ClassLoader#getResources(String) defers to documentation for ClassLoader#findResource(String), which states:
Finds the resource with the given name. Class loader implementations should override this method to specify where to find resources.
So while my answer is based on just reading a few bits of docs, I'd surmise that JCL doesn't support this due to not overriding the documented methods.
You could test this by subclassing JarClassLoader and implementing findResource(String), to test my hypothesis.
Of course, I could be wildly wrong.
Related
I'm writing a jee app deployed as a WAR to a container.
This app depends (maven dep) on a java lib packaged as a JAR.
The lib contains a client used by the jee app to talk to a backend.
The lib accepts the base uri of the backend (host+port+context-path) as a configuration.
What is the best way to configure the lib from the jee app so that one can provide configuration for multiple environments (e.g. backend production URI is different from test URI)?
I read about #Alternative annotation and ContextParam, but both seem jee specific AKA not understood by plain java...
Maven Assembly does not seem the way to go as it would imply having to deploy to our maven repo one artifact per environment.
UPDATE 1
What if the jee app contains one properties file per environment (dev, test, prod) and can pass the properties down to the lib via plain old java constructor?
I'll try and provide some answers / ideas to the topic. I would follow this approach:
Provide a fallback configuration file in the library.
Implement a default behavior in the library that looks for a predefined configuration file on the classpath which has higher precedence than the fallback (e.g. via java.lang.Class.getResourceAsStream(String))
Let the library provide a Java-API to read the configuration from a different location / ressource.
Let the library provide a Java-API to change specific configuration settings directly from client code.
You could also provide the possibility to configure your library via system environment variables and / or command line parameters.
This way, clients of the library can decide where the configuration resides, dependent on their technical landscape.
In JEE you could then use a ContextParam to set the location of the configuration resource, or to set specific configuration properties, or just provide a configuration resource in the standard location on the classpath.
If you use Spring or similar frameworks, you have loads of other possibilities to provide configuration to an application. Spring Boot provides some nice behavior out-of-the-box regarding this.
Underlying idea is that you have to provide means to the operator of the application to influence the configuration. Then it is possible to adapt configuration according to whether it is run on a developer's machine, in unit / integration testing conditions, in a staging environment or in production.
I am going to create Java Application that can load external jar files at runtime by FileChooser. I am using Spring Framework, and I want to load jar file and its applicationContext.xml file and inject its dependencies dynamically. I tried to achieve this by OSGi, but it seems very complicated so that I am searching another appropriate variants.
I want to make something like Intellij IDEA plugin installation from the disk.
How can I do this? (After the jar file chosen restarting an application also accepted)
I realy like your approach, unfortunately spring has lifecycles that are strict. As you might know, spring autowires "beans" only. Exactly one lifecycle registers the different bean candidates. After that lifecycle spring (by default) does not accept new classes.
You must use the spring-osgi.
If you only need the CDI part out of spring, you might like to use a different CDI like red hat's jboss server.
I am new to Spring and I have tried Googling this, but I am not finding any practical guidance.
I have a Maven Spring utility application that has its own Spring configuration.xml.
I would like other consuming applications (also Maven and Spring most likely) to call this utility by including it in their classpath, and with a minimimum of adjustment, just have the utility application work.
In summary, I would like to have a jar containing my utility code and Spring xml files, then place that jar in the classpath of a consumer application with a minimum of adjustment to the consumer's spring config or command line, and have the utility just work in the consumer application context.
What is the best way to accomplish this?
The scenario you're describing is what Maven was made for. You can simply make the utility module a stand-alone Maven module (with its own pom.xml) that will produce a jar artifact (which is the default type). This jar should and will contain all the Spring configs as well. Later on, when ever you need it, you just declare a dependency to the utility artifact and Maven will make sure it ends up on the classpath so you can use its features.
I would like to take several lists of Maven dependencies from the user, resolve and load each of them as contained applications. Here are the steps:
collect a list of all Maven dependencies (DONE)
resolve all dependencies with Aether (DONE)
resolve classpath with Aether (DONE)
bundle the above in a separate "container" (so that different Maven dependencies with potential conflicting version can be used).
repeat with other lists.
To give some context: I want to use the above in the context of UIMA, to be able to run different (natural language processing) pipelines that rely on different sets of libraries with different versions. My goal is to create an annotation-server in which one defines (Maven) dependencies and pipelines that can be called in a RESTful way. The pipelines (and their corresponding dependencies) should each run in a contained classpath environment (so as to avoid classpath clashes).
Is OSGi the way to go? Based on a classpath (:= a list of resolved jar), can I then build an OSGi bundle and deploy it? All programmatically? I do not have control over the maven dependencies (they are UIMA components, that's it), so no way to add OSGi metadata there.
Would maven-assembly-plugin combined with maven profiles take care of this for you?
You can filter dependencies differently on a per profile basis. You can use profile specific assembly descriptor documents and generate custom manifest to be placed in the war. You are describing a J2EE Web Application (war) assembly -- they will run in a firewalled classloader inside a servlet container so you generate a bunch of them based on the same source (just vary the web app context and the contents of the WEB-INF/lib on a per profile basis.
Drop them into the same Tomcat server, for example, and you are ready to go. Was this what you meant?
HTH,
Nick
You can certainly create a bundle that contains a list of jars, put all of those on the bundle's own classpath and deploy that bundle into an OSGi container. You probably do need to create a BundleActivator (which is the entry point for that bundle, like the main method is for traditional Java).
You then say you have multiple of such bundles, and do I understand correctly that you want to deploy each bundle in a separate container? If so, you can either use some kind of REST library to provide a REST endpoint for each bundle, or you can use OSGi remote services to publish a service that can be discovered by other containers.
I am not sure if this is what you mean, so I am also not sure if OSGi is the right way to go. From your description you use neither services (a very important reason to use OSGi as that decouples parts of your application from each other) nor do you intend to create different bundles for the components (another important reason to use OSGi). You are almost describing an architectural style currently hyped as "micro services". Can you please elaborate a bit more?
Based on your use case I'd suggest you look into the Java ServiceLoader API. The ServiceLoader API allows you to define an interface, and load implementations of that interface from different self-contained JARs. You can build your different libraries into their own jars, exposing the methods you need via the interface, and load them from your Java program independently. The ServiceLoader will even list the different implementations available for you.
From the documentation:
Suppose we have a service type com.example.CodecSet which is intended to represent sets of encoder/decoder pairs for some protocol. In this case it is an abstract class with two abstract methods:
public abstract Encoder getEncoder(String encodingName);
public abstract Decoder getDecoder(String encodingName);
Each method returns an appropriate object or null if the provider does not support the given encoding. Typical providers support more than one encoding.
If com.example.impl.StandardCodecs is an implementation of the CodecSet service then its jar file also contains a file named
META-INF/services/com.example.CodecSet
This file contains the single line:
com.example.impl.StandardCodecs # Standard codecs
The CodecSet class creates and saves a single service instance at initialization:
private static ServiceLoader<CodecSet> codecSetLoader
= ServiceLoader.load(CodecSet.class);
To locate an encoder for a given encoding name it defines a static factory method which iterates through the known and available providers, returning only when it has located a suitable encoder or has run out of providers.
public static Encoder getEncoder(String encodingName) {
for (CodecSet cp : codecSetLoader) {
Encoder enc = cp.getEncoder(encodingName);
if (enc != null)
return enc;
}
return null;
}
A getDecoder method is defined similarly.
That sounds a lot like you could use Apache Stanbol. It's a framework focused on semantic enhancement of content but can be used for any web based work flows involving content. You can define pipelines to process and/or store your data. There are components for NLP using Apache Tika and OpenNLP. As far as I know you can also integrate UIMA. It uses RESTful services and is based on OSGI.
If Stanbol doesn't fit your use case and you need to roll your own application, I think OSGI is still the way to go.
Depending on your use case you can either deploy bundles to a container or simply embed the OSGI framework in a small launcher app that loads the bundles you create.
Many Maven artifacts already contain OSGI metadata. Most of the time you can copy them to your bundle directory using the maven-dependency-plugin and load them directly as OSGI bundles.
Non-OSGI dependencies can be embed in your the bundles that need them. It should also be possible to setup a few maven plugins to modify the manifest to add some meta data based on the maven artifact ids and version and repack the dependencies as bundles (this won't work all the time though, since the Maven pom version and the packages' versions aren't always the same).
The users code and any required dependencies can be bundled up using the maven-bundle-plugin. It can generate the manifest for you.
For REST interfaces I usually would recommend JAX-RS (Jersey or Apache CXF DOSGI) but I haven't used the programmatic approach with those frameworks yet.
We often have Custom Mediators (Java classes) that are performing transformations or other things. Each time we want to change only one little thing inside the class, we need to restart the whole WSO2 ESB.
May the "custom mediator" approach is wrong, but we'd like to keep the java classes, but de-coupled from the whole server - like proxies or endpoints. (Our classes are inside a .jar in /components/lib)
How can a custom mediator or java class added to the WSO2 ESB without restarting?
<class name="my.domain.MyJavaClassThatMustBeUpdatedWithoutRestart"/>
You can create an osgi bundle from your class and then you can control the classes behavior from the OSGI Console. You need to start esb with -DosgiConsole option. You can find more information from this blog post.
http://lalajisureshika.blogspot.co.uk/2013/03/some-useful-osgi-commands-to-find.html
While starting up we make OSGI bundles out of the non-OSGI jars in components/libs.
So you must restart if you want to change the custom mediator jars.
As per the below coment explaining the answer,
WSO2 Products are running on an OSGI based platform. So if you change an OSGI bundle you can restart the bundle from the OSGI Console without restarting the whole server. Also the OSGI Container used by WSO2 is Eclipse Equinox OSGI Container. It provides the ability to add non-OSGI jars to product with the feature of, converting those jars in to OSGI Bundles. And that feature works only at the server startup. So if you want to add/change those jars you should restart the server. In runtime you can change OSGI bundles, but you can not convert non-OSGI bundeles to OSGI in runtime.