Late discovery of beans using CDI - java

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.

Related

Can a JAR shared by two web applications log to the same file in Tomcat?

Let's say we have two web applications and a Tomcat instance loading shared JARs (depedencies for both applications) from an external directory (via the means of shared.loader defined in catalina.properties). Therefore, these dependencies are not packaged into the WAR files.
Let's also say that:
Both web applications depend on a particular shared JAR file, which uses a logging framework (log4j2 at the moment but that's not required).
Both web applications use a logging framework of their own (we don't care whether they are identical or not, as long as things work as expected), and different logging configurations.
What we would like to achieve is for the shared JAR to reliably log to the same file, regardless of which web application its methods are called. To our understanding, both web applications have different logging contexts and having two such contexts log to the same file is either not possible or at least dangerous. If that's not true or doesn't have to be true, please elaborate.
The question: is it possible to achieve the above scenario with a single logging context? If so, could you please provide an example to make it working (the crucial bits will perfectly suffice), using lo4j2 or logback? Are there any catches?
Please note that we would like to avoid setting up a special servlet in one of the web applications for this (so the other web application would call it instead of logging directly to a file). Using (e.g.) syslog instead might be a solution perhaps but still, let's keep this question focused on the described scenario please.
After some research, trial and error, we managed to satisfy our requirements:
Each web application logs to its own files.
The shared JAR always logs to its own file too.
At least with Log4j2, the problem appears to revolve around class loaders. In our case, classes from the shared JAR file, and all of its dependencies, were always loaded using a class loader dedicated to (shared.loader). This means that Log4j2's JAR files need to be there beside the shared JAR file and if we tried to remove them, we would see ClassNotFoundExceptions.
Now, we can move to the web applications:
If a web application DOESN'T package Log4j2 for its own use, its loggers are also loaded using the class loader for shared.loader (as a fallback), and the web application's logging configuration overwrites the configuration applied previously (in our case, we had to call explicit initialization or reconfiguration, so that's why). It wouldn't work as expected.
If a web application DOES package Log4j2 for its own use, its loggers are loaded using the class loader for the web application (since dependencies packaged within WEB-INF take precedence), which is a completely different 'context' (class loader) than in approach #1, and the web application's logging configuration does NOT overwrite previously applied configurations (since the shared JAR and all web applications have their own 'context').
That is the behaviour we observed. During approach #1, each web application overwrote logging configuration for the applications initialized/started previously, because the Log4j2 'context' (class loader) was shared. During approach #2, the shared JAR's Log4j2 context was initialized by the web application that called its initialization (only one of them), and the configuration was not touched ever since. In our case, the configuration file was provided by the web application (it was not packaged within the shared JAR). Note that in practice, one of the web applications will always have to initialize the shared JAR, either implicitly or explicitly.
For absolute certainty, we listed open file descriptors to the shared JAR's log files and with approach #2, there was indeed only one. With approach #2, there can still be multiple descriptors open if some of the web applications' configuration files also reference the shared JAR's log files (configuration duplicity). That is precisely the sort of situation you'd normally want to avoid.
Pitfalls that we discovered:
Notice that the shared JAR's Log4j2 context was initialized by the web application that called its initialization (only one of them) remark is a bit tedious. Unless we copy or include the shared JAR's configuration within configuration of each web application (and for the above stated reasons, we want to avoid that), some of the logging messages may end up elsewhere or get lost during servlet container's start. In general, it may not be possible to guarantee the order in which web applications are started. I may be wrong but from what I saw in Tomcat logs, Tomcat starts the web applications (WAR files) in alphabetic order.
If the shared JAR and any of the web applications happen to share some more dependencies (beside the logging framework), these dependencies must, also, be placed within shared.loader. But, if the shared JAR's logging configuration redirects logging messages of any of those dependencies into its own logs, they can not end up in the web application's logs, unless that dependency is also packaged within the web application (same principle as approach #2 above). But in practice, separation of logging API and backing implementations makes this difficult. For example, you can read here on StackOverflow that selection of SLF4J bindings is rather "random" (JVM-dependent). If you put different bindings to shared.loader and into one of the web application's WEB-INF folder, you may not have certainly about which binding is going to get selected.
I certainly can not recommend the scenario we are trying to achieve but the described "solution" definitely works as expected (despite the pitfalls).

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.

Struts 1.2.9 - Questions around custom internationalization

We have a legacy application that uses Struts 1.2.9. The app is currently internationalized the standard way - .properties files for all UI labels, errors, messages, etc; <message-resouces> definition for each .properties file in struts-config.xml using default Factory & MessageResources definitions; <bean:message> usage in all JSPs. This has worked great till now, but for the fact that the application itself a framework for services used by a few hundred (yes 100's!) other applications internally.
We have a requirement to extend the i18n functionality as follows:
Define a custom directory for .properties files - so this would be outside the scope of the classpath; basically not inside the .war package. The idea is to support just message string changes w/o really having to redeploy the entire application.
This custom directory will also contain per supported applications messages - this could be just a subset of the existing ones or the entire set of resources tailored specifically to that application.
Custom way of supporting per request basis Locale setting - barring all other considerations (default stack, classpath/package lookups, etc.) this is analogous to the way I18nInterceptor works in Struts2 with the requestOnlyParameterName attribute set to true.
Yes, I do understand that a few 100 bundles loaded at the same time will be memory intensive, but that is acceptable in our case.
Any help is appreciated - be it direction, sample code, etc.
Note: I completely agree that moving onto a newer UI platform is probably the best solution. But we can't.
TIA.
I had a similar requirement in a spring project, not only for i18n, also web services endpoints and other kind of properties.
We accomplish that requirement by adding that directory, in which we place the properties files, into the classpath in the server start configuration file.
Tested and working in weblogic 11g (Preproduction and production) and in a tomcat server (development environment).
Hope helps

Using a shared parent application context in a multi-war Spring application

I want to shared common application context in a multi-war Spring application, so i don't need to defined beans again and again. But i don't want to instantiate those beans defined in this common application context in each webapp. I only want to instantiate those beans once and share by all the webapps. Is it possible? Bare me if i'm wrong.
PS: this common application context exists in jar, which i'll import to every webapps.
1, Below article tell us how to share the common application context, but need to instantiate those beans in each webapp.
How to import spring-config.xml of one project into spring-config.xml of another project?
2, Below is another article i just read, i demo it, but still don't get what i want, beans got instantiated twice. Can someone check this section "Why would you want to use this?" in the article, i don't get it, do they have a solution there, can someone help me here, thanks a lot for your time.
http://spring.io/blog/2007/06/11/using-a-shared-parent-application-context-in-a-multi-war-spring-application/
here is the demo source code in second article: https://github.com/jasonluo/ceciic/tree/master/Research/multiple-contexts-sample
Updates
The problem of case2 is because i didn't deploy as a ear file, thanks Deinum for pointing this out, i'm using tomcat, so there is no way to achieve that.
Our solution now is using REST to access the service webapp which running in a separate server.
Don't, there is usually classloader isolation going on to prevent this. Doing this right usually requires a thorough understanding of classloading, Java EE, packaging and your server.
Having that said there is way to do this as outlined in the blog you posted. You have to:
package both WARs into an EAR (this means you have to use and appserver like WildFly AS and can't just use a servlet engine like Tomcat or Jetty)
package both WARs as "skinny" WARs with at least Spring (and all its dependencies) and the shared beans (and all their dependencies) in the lib/ folder of the EAR instead of the WEB-INF/lib folder of the WARs.
Even then it depends on implementation details of the server. AFAIK it is not guaranteed to work under the Java EE specification. For example it likely won't work in GlassFish.
Update
I can't tell if the output of your demo is correct because I couldn't find a build file.
Yes, Tomcat does not support EARs, you could use Apache TomEE which is very similar and supports EARs (I don't know if TomEE does classloading in a way that makes this work). In theory you could also make use of the common classloader in Tomcat but that would be quite a hack.
There is a way to do it, using Spring Dynamic Modules, but it requires OSGi environment, which is quite different from simple Tomcat. Few articles worth reading:
Deploying Spring MVC applications to OSGi
Hello world style example
Blueprint - a further development on DM
Another blueprint documentation reference to Spring
That being said there is not a lot of up to date information about Spring with OSGi, but it's worth a try to achieve just what you said (but of course, with additional performance cost)

EJB 3.1 application deployed as WAR-only: What about ejb-jar.xml?

I have a JavaEE6 application, consisting of Web stuff and EJBs and which is deployed as WAR-only (using EJB3.1). The build is based on Maven. I just read about a new possibility to order the module initialization in Java EE 6 here which i also need for my application. Also, i would like to have an option to define some EJB properties in XML.
Since the example is deployed as an EAR-project the order is defined in the application.xml. But in a WAR-deployed project, there is no application.xml. Now i wonder where i can define such informations? Or is it possible to use an application.xml somehow in a WAR-deployed-app?
EDIT:
Oops i didn't read the module-order-example right, in the first moment i thought it was about in which order the EJBs in my app are loaded. Of course i have only one module in my WAR-app, so ordering makes no sense.
Ok, but as i'm at it, one big question remains (also altered the question title to reflect the change): What about the ejb-jar.xml? Can i somehow define stuff about my EJBs in XML (as its useful for some settings, to avoid recompilation)?
In short, it is not possible with a WAR based deployment.
The module initialization feature of Java EE 6 is meant for initializing different modules of an application in a specific order. The moment you have a WAR based EJB application, you no longer have separate modules for your EJB and Web application. There is just one module - the web application module in a WAR based deployment.
Therefore, if you have to achieve the same feature as the module initialization order, offered in Java EE 6, you'll have to do either of the following:
Separate the EJB into a separate module, and use a EAR based deployment.
This is more or less trickery, as was done in Java EE 5, and you would want to be avoiding it. You might want to code in logic to ensure that the singleton EJBs have been created (assuming that this is due to the use of singletons in your application), before they're utilized in code.
Location of the ejb-jar.xml in a WAR file
The EJB 3.1 specification (in the chapter on Packaging) addresses the issue of the location of the ejb-jar.xml file when deployed in a WAR:
In a .war file, the deployment
descriptor is stored with the name
WEB-INF/ejb-jar.xml.
PS: I haven't tried this style of deployment yet. YMMV.
Side note on EJBs in .wars and ejb-jar.xml processing. As already noted the location is WEB-INF/ejb-jar.xml, but also note that is the only location checked even if there are ejbs jars inside WEB-INF/lib/ -- via standard rules any META-INF/ejb-jar.xml files there are ignored.
The Expert Group was rather split on that one, so if you have a preference it's not too late to send feedback to the EJB 3.1 expert group list for consideration in EJB.next.
My vote was to still allow individual jars to have META-INF/ejb-jar.xml files just as these jars can now have persistence.xmls, beans.xmls, web fragments etc. The larger issue for me was that it is at odds with the Embedded EJB Container API which supports an EAR-style classpath which allows several jars/modules each possibly containing a META-INF/ejb-jar.xml file. The result being if you do use the Embedded API to test a multi-jar ejb app that is composed into a single .war file, you are then faced with the task of merging any ejb-jar.xml data you have into a single ejb-jar.xml for the webapp. Sort of a pain for users.

Categories