Is there a way to 'alter' beans.xml without redeploying a WAR? - java

I'm packaging a WAR with multiple implementations of an interface. I have one implementation with no qualifier (i.e. #Default) and one with #Alternative. I'd like to know if there is an easy way (without editing the WAR itself) to change beans.xml to point to the alternative implementation, without having to package/deliver two different WAR files. If it's of any interest, I'm using JBoss EAP 6.4.
If not, what would be the best approach? I guess I could provide a property file where they can choose an implementation. I can then use #Inject #Any Instance<Intf> and match the correct implementation during server startup.
Edit:
The end goal is to be able to use the alternative implementation, even though it's not explicitly added in beans.xml alternatives.
The reason for this requirement is that the same service might be interfacing with different versions of the external system. I want to deliver the default, latest adapter implementation by default. At the same time, customers should be able to fallback to an older implementation if needed.

Related

Dynamically adding beans and jars to Java application

For an ongoing project, we are looking for a possibility to dynamically download and load jar files into a running application. Apart from downloading the files (which is probably fairly straightforward), I am unaware of any solution that would automatically add the jar's to the classpath, and do discovery of the annotations (like CDI beans).
Given such a system, it would be rather handy if the #Inject annotation would not throw a runtime failure of an implementation of a class is not present (because that module-jar was not loaded).
Is there currently any such system? Does spring or OSGi fit this need?
Any ideas how close project Jigsaw would come in trying to fulfill this on application level?
I think you need OSGI, using an OSGI container like Karaf : https://karaf.apache.org
In standard java provide ServiceLoader https://docs.oracle.com/javase/tutorial/ext/basics/spi.html
I advice you to not follow that path
It should be possible to dynamically load jar files without the usage of OGSI. The keyword are Classloaders especially when used with a proper hierarchy. The following answer should give you an idea: How should I load Jars dynamically at runtime? but keep in mind that this might cause serious security issues
You followed the path at 2. even I advice you not to do it. But now you end up in the scenario that the context of your used framework does not know this classes. You would have this problem with most IOC frameworks. Since they build up the context on startup. There are libraries for this created for development purpose (spring-loaded, spring dev tools, JRebel). If your IOC framework supports it go with it.
Regarding handling not available jars. The best point to do research on this is Spring Boot and its auto configuration mechanism. It checks if certain classes/jars (not sure to be honest) are available and add additional behavior for this cases. But still this is application startup solution and not a runtime IOC solution.

Changing Java code after deployment

When distributing a Java application to others, it can be deployed as a JAR file for easy execution.
But is there a way to change a Java class / part of the code after deployment without having to rebundle the whole application again?
If you have an app with say 10 classes where 9 are finalized but one needs to be adjusted according to the individual case. What would be the easiest way to change just one class in an app?
Probably you want to use java web start. If your user starts application via java web start it is automatically being updated if updates are available.
EDIT
It does not provide class-based granularity, but I believe this is not the real issue. It however provides the jar-based granularity, i.e. the newer version of jar is being downloaded only if it was changed.
No, there's not.
You should repackage OR design the one that should be adjusted to be configurable at runtime. If you can modify it using a configuration database and factory that would be the only way to do it without repackaging.
In theory you could create another jar for the customized classes and put it into the classpath before the old jar, and the JVM will load the customized classes. But this is simply looking for trouble...
Better to build two jars, one with the non changing classes and another with the customized classes and rebuild the later when you need it.

How use two verions of itext jar files in pom.xml?

In my project i have dependencies displaytag and birt-runtime. And here display tag needs itext-2.0.1.jar and birt-runtime needs itext-2.1.7.jar so how can i declare this in my pom.xml to use itext-2.0.1.jar only by displaytag and use itext-2.1.7.jar only by birt-runtime. could some one let me know how to achieve this?
Thanks in advance.
In normal java application this is not possible, because in the application itext 2.1 and 2.0 will share the same classloader.
But normally, java-apis take care about backward-compatibility, so it should be possible to include only 2.1.
If not, you need multiple classloaders and then it will become complicated.
Existing solutions:
You could try to add an OSGi container to your application and run
both dependencies as a separate osgi-bundle.
If you run a jboss
application server, you could create one module with displaytag and
another one with birt-runtime.
DIY:
I've never done this but you could try to create to manage your own classloaders in your application and load the dependent jars into each own classloader. This article seems to cover the topic.
Short answer: you can't.
Long answer: Maven is a build tool and has no effect on runtime class loading in your application. Normally what it generates is one (or more) artifact(s), tipically jar or war files that may or may not contain your project's dependencies (depending on your POM files).
What you want to achieve is done at runtime by class loaders but under normal circumstances you don't want to tamper with class loading.
What you could do is:
Exclude unnecessary transitive dependencies of a dependency in your pom by defining exclusions, this way only one version of itext would be used. Of course, this only works if your dependencies don't rely on the internals of itext and their public API's are compatible but this might be the cleanest and easiest solution.
Use a framework/container that has stronger control over class loading, such as an OSGi container. These container provide bundles (somewhat equivalent to artifacts) with "private" class loaders enabling your application having multiple versions of the same library loaded that don't interfere with each other. This solution, however, has other disadvantages and I would only recommend this if you're already familiar with OSGi.

Late discovery of beans using CDI

I'm creating a Java web application, making use of CDI. My War includes various Jar files that are bean sources (including the META-INF/beans.xml file). My beans are automatically discovered when running inside a Java EE container like JBoss (I'm currently using JBoss AS 7.1.1). This much is working well.
I want to be able to extend the web application, ideally by allowing it to load classes from Jar files stored in a configurable location (so at a location specified by a system property). This too is fine, since I can use a ClassLoader to resolve classes and resources. What I'm missing is the ability to have CDI scan these external Jar files and include their beans.
This would allow my application to host plug-in functionality including new REST resources. I don't mind if I had to restart the application for it to pick up classes and resources contained within these external Jar files.
I can see no way of achieving this. Is this even something that should be attempted in this kind of environment?
I can see no way of achieving this.
You actually have two options:
Use the CDI extension mechanism to work with beans / bean-archives
at startup time and to modify them in the way you want. Have a look at the examples provided in the documentation, this should give you a start.
Work with the BeanManager at execution time. Have a look at this similar question.

JSR-299 (CDI) configuration at runtime

I need to configure different #Alternatives, #Decorators and #Injectors for different runtime environments (think testing, staging and production servers).
Right now I use maven to create three wars, and the only difference between those wars are in the beans.xml files. Is there a better way to do this? I do have #Alternative #Stereotypes for the different environments, but even then I need to alter beans.xml, and they don't work for #Decorators (or do they?)
Is it somehow possible to instruct CDI to ignore the values in beans.xml and use a custom configuration source? Because then I could for example read a system property or other environment variable.
The application exclusively runs in containers that use Weld, so a weld-specific solution would be ok.
I already tried to google this but can't seem to find good search terms, and I asked the Weld-Users-Forums, but to no avail. Someone over there suggested to write my own custom extension, but I can't find any API to actually change the container configuration at runtime.
I think it would be possible to have some sort of #ApplicationScoped configuration bean and inject that into all #Decorators which could then decide themselves whether they should be active or not and then in order to configure #Alternatives write #Produces methods for every interface with multiple implementations and inject the config bean there too.
But this seems to me like a lot of unnecessary work to essentially duplicate functionality already present in CDI?
edit
Ok, I realized I'm a bit stupid... of course it is possible to add stereotypes and inteceptors at runtime using the CDI extension API:
void beforeBeanDiscovery(#Observes BeforeBeanDiscovery bbd) {
bbd.addInterceptorBinding(...)
bbd.addStereotype(...)
}
But what I didn't find was an API to add a decorator. The only thing I found was to activate all #Decorators in the beans.xml, then observe
public <T> void processAnotated(#Observes ProcessAnnotatedType<T> event)
and call
event.veto()
if I don't want a #Decorator to be active.
You might want to take a look at JBoss Seam, specifically the Solder sub-project.
It allows dependency driven CDI resolution, so that certain beans are only available if other beans or resources are available. (Class A if "dataSource" is available, Class B if "entityManager" is available)
Since it's open source, you can also take a look at how they wired that together, and use that knowledge as a basis for writing your own extension if needed.
If you're using JSF, I would highly recommend using SEAM-JSF as well, as it gets rid of the clunkiness of having two injection frameworks (JSF DI/CDI) and allows CDI beans in JSF scopes.

Categories