I am porting an application from JBoss 4 to JBoss 6.1 EAP. This application uses cxf with spring. Our client's requirement is that we will not change (or add) modules for jboss.
In the jboss cxf module, there is an optional dependency to spring, but by default there is no spring module. I was wondering:
Am I required to add a spring module to JBoss?
Can I just add the spring jars to my application lib directory?
What's the best and/or easiest way to get this to work?
If I don't create a spring module and add the spring jars to the application lib directory, I get the following error:
09:19:44,203 WARN [org.jboss.modules] (MSC service thread 1-1) Failed to define class org.apache.cxf.transport.servlet.CXFServlet in Module "org.apache.cxf.impl:main" from local module loader #1f06dc3 (finder: local module finder #1b64e6a (roots: C:\dev\jboss-eap-6.1\modules,C:\dev\jboss-eap-6.1\modules\system\layers\base)): java.lang.LinkageError: Failed to link org/apache/cxf/transport/servlet/CXFServlet (Module "org.apache.cxf.impl:main" from local module loader #1f06dc3 (finder: local module finder #1b64e6a (roots: C:\dev\jboss-eap-6.1\modules,C:\dev\jboss-eap-6.1\modules\system\layers\base)))
at org.jboss.modules.ModuleClassLoader.defineClass(ModuleClassLoader.java:427) [jboss-modules.jar:1.2.0.Final-redhat-1]
at org.jboss.modules.ModuleClassLoader.loadClassLocal(ModuleClassLoader.java:260) [jboss-modules.jar:1.2.0.Final-redhat-1]
at org.jboss.modules.ModuleClassLoader$1.loadClassLocal(ModuleClassLoader.java:75) [jboss-modules.jar:1.2.0.Final-redhat-1]
at org.jboss.modules.Module.loadModuleClass(Module.java:526) [jboss-modules.jar:1.2.0.Final-redhat-1]
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:188) [jboss-modules.jar:1.2.0.Final-redhat-1]
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:444) [jboss-modules.jar:1.2.0.Final-redhat-1]
at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:432) [jboss-modules.jar:1.2.0.Final-redhat-1]
at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:399) [jboss-modules.jar:1.2.0.Final-redhat-1]
at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:399) [jboss-modules.jar:1.2.0.Final-redhat-1]
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:374) [jboss-modules.jar:1.2.0.Final-redhat-1]
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:119) [jboss-modules.jar:1.2.0.Final-redhat-1]
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:316) [rt.jar:1.6.0_17]
at java.lang.Class.forName0(Native Method) [rt.jar:1.6.0_17]
at java.lang.Class.forName(Class.java:247) [rt.jar:1.6.0_17]
at org.jboss.as.server.deployment.reflect.DeploymentClassIndex.classIndex(DeploymentClassIndex.java:54)
at org.jboss.as.ee.component.deployers.InterceptorAnnotationProcessor.processComponentConfig(InterceptorAnnotationProcessor.java:85) [jboss-as-ee-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]
at org.jboss.as.ee.component.deployers.InterceptorAnnotationProcessor.deploy(InterceptorAnnotationProcessor.java:77) [jboss-as-ee-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]
at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:120)
at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1811)
at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1746)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [rt.jar:1.6.0_17]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [rt.jar:1.6.0_17]
at java.lang.Thread.run(Thread.java:619) [rt.jar:1.6.0_17]
Caused by: java.lang.NoClassDefFoundError: org/springframework/context/ApplicationListener
at java.lang.ClassLoader.defineClass1(Native Method) [rt.jar:1.6.0_17]
at java.lang.ClassLoader.defineClass(ClassLoader.java:616) [rt.jar:1.6.0_17]
at org.jboss.modules.ModuleClassLoader.doDefineOrLoadClass(ModuleClassLoader.java:344) [jboss-modules.jar:1.2.0.Final-redhat-1]
at org.jboss.modules.ModuleClassLoader.defineClass(ModuleClassLoader.java:422) [jboss-modules.jar:1.2.0.Final-redhat-1]
... 22 more
tl;dr
Only if you want Spring to manage the lifecycle of your JAX-WS endpoint beans, which is no longer necessary.
No, not if you're trying to use Spring-based CXF features directly in your app. Refer to #1, but keep reading...
The easiest way is to let JBossWS manage your JAX-WS endpoints but have them extend SpringBeanAutowiringSupport to integrate with your app's ApplicationContext. Further details below.
Details
I faced the same problem - migrating an app with Spring-managed JAX-WS endpoints to JBoss EAP 6 (AS 7).
The problem is that JBossWS in EAP 6 is a double-edged sword. It makes it very easy to setup JAX-WS endpoints, abstracting away all knowledge of the underlying CXF engine from your app, but it requires you to relinquish some control over those endpoints.
Instead of using CXF's Spring namespace and defining your endpoints as Spring beans sitting behind a single servlet, you should now remove those beans from the Spring context and define each one as a servlet in web.xml (even though they are not actually servlets!).
JBossWS will auto-detect those pseudo-servlets at runtime and will build the necessary CXF infrastructure behind them.
This is all well-and-good, but what if you need to inject some Spring-managed dependencies into your endpoints?
SpringBeanAutowiringSupport to the rescue! Apparently this was the main reason for this class - to integrate Spring IoC with container-managed beans.
Have your endpoints extend this class, and then your dependencies can be injected via #Autowired (or the like).
Note that you should still use ContextLoaderListener as a listener-class in your web.xml to bootstrap your Spring ApplicationContext.
Note also that your app can now be totally agnostic of CXF - meaning you should not do any of the following:
extend or use any CXF classes directly
reference any CXF-provided Spring context files (e.g. classpath:META-INF/cxf/cxf.xml)
use any CXF namespace in your app's Spring config (e.g. xmlns:jaxws="http://cxf.apache.org/jaxws")
The downside is that your app can no longer use any advanced CXF-specific features, but hopefully this isn't necessary anyway.
Related
I'm using Vaadin 14.5.1 and Wildfly 17. I have several applications deployed in Wildfly. Now I'm implementing internationalization using Vaadin's I18nProvider interface.
So I created a TranslationProvider class which implements the interface in module A, and as per this guide I activate it using:
setProperty("vaadin.i18n.provider", TranslationProvider.class.getName());
After deployment, if I try to go to module B, it gives an error like:
Caused by: java.lang.ClassNotFoundException: my.module.A.TranslationProvider from [Module "deployment.B.war" from Service Module Loader]
The error is clear, my TranslationProvider is in module A, so of course module B can't find it. But the translation provider should be only for module A and nothing else. How should I go about this? Can I "disable" the system property once I exit from my module? Is there a way for other modules just to ignore it?
I am deploying an EAR with the below structure to Wildfly 9.0.2
my.ear
|-my.sar (it is a SAR archive)
|-lib
|-myPreferencesImpl.jar
I am able to load the classes in lib/myPreferencesImpl.jar from my.sar (like class.forname(com.my.PreferencesFactory) directly. However, java.util.prefs.Preferences.factory is not able to load com.my.PreferencesFactory. I am passing Djava.util.prefs.PreferencesFactory=com.my.PreferencesFactory as command line parameter during WildFly startup.
Below is the exception thrown.
Caused by: java.lang.ClassNotFoundException: com.my.PreferencesFactory from [Module "org.jboss.as.jmx:main" from local module loader #76a3e297 (finder: local module finder #4d3167f4 (roots: /CSA_wildfly/wildfly/modules,/CSA_wildfly/wildfly/modules/system/layers/base))]
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:205)
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:455)
at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:404)
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:385)
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:130)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at java.util.prefs.Preferences.factory(Preferences.java:254)
Please help me fix this.
UPDATE:
I finally fixed by migrating the startup service using JMX Service to a #Singleton + #Startup EJB. No other changes were required.
When you pass the arg Djava.util.prefs.PreferencesFactory=com.my.PreferencesFactory in command line, Wildfly is going to look for the class in the classes available to it, which is provided by way of modules . During the Wildfly bootup, it's not even going to know that there is a application with that class present, neither can it provide the same class to other deployments on the same container. So if you want the command line arg to work, make sure the deploy the Factory implementation as a Wildfly module.
I have very old aplication (10 years - sick) that I need to deploy on weblogic server 10.3.6. I have one ear file with few subdeployed jar's with EJB classes (they contain both weblogic-ejb-jar.xml + ejb-jar.xml). It deploys normally on sever and I can use "lookup" function in weblogic.
The problem is that there is another jar (much older) without ejb-jar.xml that is needed to run this aplication. It have for example ObjectHome.class which is called with "lookup" function in weblogic. For now I've added it in CLASSPATH in weblogic but I still need to somehow deploy it on server so it can be retrived by "lookup" function.
Any ideas how to achive that?
javax.naming.NameNotFoundException: While trying to lookup 'pl.com.project.ejb.IdentyficatorHome' didn't find subcontext 'IdentyficatorHome'. Resolved 'pl.com.project'; remaining name 'ejb/IdentyficatorHome'
at weblogic.jndi.internal.BasicNamingNode.newNameNotFoundException(BasicNamingNode.java:1139)
at weblogic.jndi.internal.BasicNamingNode.lookupHere(BasicNamingNode.java:247)
at weblogic.jndi.internal.ServerNamingNode.lookupHere(ServerNamingNode.java:182)
at weblogic.jndi.internal.BasicNamingNode.lookup(BasicNamingNode.java:206)
at weblogic.jndi.internal.BasicNamingNode.lookup(BasicNamingNode.java:214)
at weblogic.jndi.internal.BasicNamingNode.lookup(BasicNamingNode.java:214)
at weblogic.jndi.internal.BasicNamingNode.lookup(BasicNamingNode.java:214)
at weblogic.jndi.internal.BasicNamingNode.lookup(BasicNamingNode.java:214)
at weblogic.jndi.internal.BasicNamingNode.lookup(BasicNamingNode.java:214)
at weblogic.jndi.internal.WLEventContextImpl.lookup(WLEventContextImpl.java:254)
at weblogic.jndi.internal.WLContextImpl.lookup(WLContextImpl.java:412)
at javax.naming.InitialContext.lookup(Unknown Source)
How was the old JAR assembled and how was it used before in the old container? I would think, if it is a J2EE 1.x EJB, there must be a deployment descriptor for it somewhere?
If not, your only options are either creating a deployment descriptor according to your current weblogic server or - if possible - migrate the old code to a newer EE version.
I have a simple setup with a war file containing only a web.xml that specifies the javax.ws.rs.Application class to use in the servlet.
The jar that contains the implementation for javax.ws.rs.Application is also completely trivial. Both the web.xml and the implementation are based off the examples in jboss documentation
However, I get different behavior when I deploy the war + jar combination in jboss AS 7.1.1 Final versus jboss 4.0.4. Upon accessing the rest api I get the following exception in the jboss logs (snippet only):
06:33:59,540 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/wrapper]] (MSC service thread 1-2) StandardWrapper.Throwable: java.lang.RuntimeException: java.lang.ClassNotFoundException: com.projectgoth.provider.restapi.RestApiProvider from [Module "deployment.wrapper.war:main" from Service Module Loader]
at org.jboss.resteasy.spi.ResteasyDeployment.createFromInjectorFactory(ResteasyDeployment.java:271) [resteasy-jaxrs-2.3.2.Final.jar:]
at org.jboss.resteasy.spi.ResteasyDeployment.createApplication(ResteasyDeployment.java:259) [resteasy-jaxrs-2.3.2.Final.jar:]
If however, I change the scope of the jar from provided to runtime in the war's pom.xml - the error does indeed go away from jboss as 7.1.1.
For reference, I've uploaded the code use for both the war and jar to bitbucket (where provider = implementation for the javax.ws.rs.Application, and wrapper is the war deployable)
I think this is normal. Per class loader policy, a child class can always see the parent class not the vice verse. When you put the jar scope as runtime, the JAR is loaded in the classpath up in the stream than the WAR application and hence it's visible to the WAR classes.
When attempting to create a new InitialDirContext using the com.sun.jndi.dns.DnsContextFactory on JBoss AS 7, the following exception occurs:
Caused by: javax.naming.NamingException: Failed instantiate InitialContextFactory com.sun.jndi.dns.DnsContextFactory from classloader ModuleClassLoader for Module "deployment.test-case.ear.test-web.war:main" from Service Module Loader
at org.jboss.as.naming.InitialContextFactoryBuilder.createInitialContextFactory(InitialContextFactoryBuilder.java:58)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:664) [:1.6.0_26]
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288) [:1.6.0_26]
at javax.naming.InitialContext.init(InitialContext.java:223) [:1.6.0_26]
at javax.naming.InitialContext.(InitialContext.java:197) [:1.6.0_26]
at javax.naming.directory.InitialDirContext.(InitialDirContext.java:82) [:1.6.0_26]
at com.test.messaging.internal.resource.dns.DnsClientImpl.querySrv(DnsClientImpl.java:328) [dns-lookup-jar.jar:]
...
16:36:36,000 ERROR [org.apache.catalina.core.StandardContext] (MSC service thread 1-5) Error listenerStart
16:36:36,013 ERROR [org.apache.catalina.core.StandardContext] (MSC service thread 1-5) Context [/test] startup failed due to previous errors
16:36:36,023 INFO [org.jboss.web] (MSC service thread 1-5) registering web context: /test
Here is the relevant code snippet:
Hashtable env = new Hashtable();
env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
env.put("java.naming.authoritative", "false");
env.put("com.sun.jndi.dns.recursion", "true");
env.put("com.sun.jndi.dns.timeout.initial", timeoutProp);
env.put("com.sun.jndi.dns.timeout.retries", "1");
env.put("java.naming.provider.url", providerProp);
DirContext ctx = new InitialDirContext(env);
The code is invoked from within a ServletContextListener and therefore the exception prevents the module from starting. I've also removed the listener and have attempted to invoke the code from within a servlet, which produced the same results (javax.naming.NamingException: Failed instantiate InitialContextFactory com.sun.jndi.dns.DnsContextFactory).
I found this thread which seemed very similar to the problem that I am running into, but setting the "jboss.modules.system.pkgs" property to "com.sun.jndi.dns," as the thread mentions, had no effect.
The code works correctly on JBoss 6, WebSphere Application Server 7, and Geronimo 2.2.1 (on Tomcat 6), but is failing on JBoss 7 as described above. I'm running JBoss AS 7.0.0.Final and testing using the standalone server, using the 1.6.0_26 JRE. Any suggestions on how to resolve this problem would be greatly appreciated.
I also posted this question on the JBoss development community forum, but have not received any replies.
[UPDATE] It seems this problem is likely related to JBoss 7's new isolated, modular class loading policies. I found two workarounds/solutions to this problem, but I'm still interested in suggestions on the most appropriate, recommended approach, particularly if there is a way that we can avoid manual modifications to our applications or JBoss installations.
MANIFEST.MF
Create a com.sun.jndi.dns module, by copying $JBOSS_HOME/modules/com/sun/jndi/ldap to $JBOSS_HOME/modules/com/sun/jndi/dns and modify occurrences of "ldap" to "dns"
Add the following entry to the web module's MANIFEST.MF: Dependencies: com.sun.jndi.dns
Although this now allows the DnsContextFactory to instantiate properly, this doesn't seem to be a permanent solution since it requires modification of all JBoss installations as well as all applications that use the DnsContextFactory.
jboss-deployment-structure.xml
Add a jboss-deployment-structure.xml file to the EAR's META-INF directory, as follows:
<sub-deployment name="test-web.war">
<dependencies>
<module name="deployment.com.sun.jndi.dns" />
</dependencies>
</sub-deployment>
<module name="deployment.com.sun.jndi.dns">
<dependencies>
<module name="system" export="false">
<exports>
<include-set>
<path name="com/sun/jndi/dns"/>
</include-set>
</exports>
</module>
</dependencies>
</module>
This is slightly better than the previous "MANIFEST.MF" approach, since it only requires modification to the application, and not also the JBoss modules, but is unfortunate that all applications that use the DnsContextFactory must include this configuration.
I'm still looking for suggestions on the most appropriate, recommended approach, particularly if there is a way that we can avoid including more JBoss-specific configuration in our applications.
Thanks to some help on the JBoss forum, it's been confirmed that the workarounds I mentioned above may work, but the most appropriate solution requires a feature request from JBoss. I've logged this feature request, and in the meantime, another temporary solution is to add the "com/sun/jndi/dns" path to the sun.jdk module descriptor ($JBOSS_HOME/modules/sun/jdk/main/module.xml).