My team inherited an old codebase built on top of Apache Karaf, and it has some JAX-WS services. We're currently having a problem with this object not always being injected to the Bean.
Our service is defined as:
#WebService(serviceName = "XXXSoapService", portName = "XXXSoapPort", endpointInterface = "com.XXX.service.XXXSoapInterface", targetNamespace = "http://xxx.xx/")
#BindingType(value=SOAPBinding.SOAP12HTTP_BINDING)
public class XXXSoapService implements XXXSoapInterface {
#Resource
WebServiceContext context;
public void doXXX() {
context.getMessageContext(); // throws nullpointerexception
}
}
We have already tried several options we found online. We tried setter injection, we tried to specify a name for the Resource, and we made sure the endpointInterface was set.
However, no matter what we do, most of the times, the service is instantiated without injecting the WebServiceContext. Some times, it works, which leads us to believe it may have to do with how KARAF works, and it tries to inject the WebServiceContext before it's available.
We have CXF in the org.apache.karaf.features.xml, in a featuresBoot section.
My understanding of OSGI and Karaf is very basic, so I don't really know what to look for.
Does anybody have any idea of why the WebServiceContext is not injected most of the time, but it is injected some times?
EDIT: I've been reading about it, and it seems an exception I'm having with Apache Blueprint might have something to do with it:
[Blueprint Extender: 3] ERROR org.apache.aries.blueprint.container.BlueprintContainerImpl - Unable
to start blueprint container for bundle
io.hawt.hawtio-karaf-terminal/2.0.0 due to unresolved dependencies
[(objectClass=org.apache.felix.service.threadio.ThreadIO),
(objectClass=org.apache.felix.service.command.CommandProcessor)]
java.util.concurrent.TimeoutException
at org.apache.aries.blueprint.container.BlueprintContainerImpl$1.run(BlueprintContainerImpl.java:371)
at org.apache.aries.blueprint.utils.threading.impl.DiscardableRunnable.run(DiscardableRunnable.java:48)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
I'll look into the dependencies for this module, but can this be the reason? Any other ideas?
Found a fix, however, I doubt it is the solution. It's more of a work around.
I've added javaee-api-7.0.jar to a folder of dependencies we always load when Karaf is starting, and it suddenly started working every time. It now injects the WebServiceContext as expected.
What it doesn't explain is why it worked some times before. If it was a missing dependency, it would never work. My guess is that some dependencies were loaded too late, and it would fail most of the times, and now because I'm including it in this folder of dependencies, it's loaded at startup or early enough in the process. I honestly don't understand what's happening.
I'm posting this answer because it might help somebody else, but I won't mark it as solved, because I don't believe it is the actual fix. If anyone has a proper solution, please fire away.
Related
I've successfully started Hibernate in an OSGi context, and now I want to add Envers.
The documentation claims that's possible. I don't believe it anymore. There is no documentation of any kind for this subject and nobody seems to have actually done it. Moreover even with a Blueprint implementation I had to hack the classloader to make Hibernate even find Envers:
osgiClassLoader = new org.hibernate.osgi.OsgiClassLoader();
osgiClassLoader.addBundle(requestingBundle);
osgiClassLoader.addBundle(FrameworkUtil.getBundle(SessionFactory.class));
osgiClassLoader.addBundle(FrameworkUtil.getBundle(HibernateEntityManagerFactory.class));
osgiClassLoader.addBundle(FrameworkUtil.getBundle(EnversService.class));
Thread.currentThread().setContextClassLoader(osgiClassLoader);
(I feel like I should be asking: "Is Envers in OSGi even possible?" So if you have a definite answer for that question, please let me know. I've been spending way too much time on these issues.)
However the actual problem has nothing to do with Hibernate / Envers and all with OSGi. Both want to access the entities and enums used. With reflection nonetheless. Of course they can't. And of course I can't add Import-Packages.
The relevant stack trace looks something like this:
Caused by: java.lang.ClassNotFoundException: org.acme.project.MyEnum cannot be found by org.hibernate.core_5.1.0.Final
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:461)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:372)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:364)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:161)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at org.hibernate.internal.util.ReflectHelper.classForName(ReflectHelper.java:151)
at org.hibernate.type.EnumType.setParameterValues(EnumType.java:105)
... 62 more
Normally with OSGi-agnostic frameworks I'd just add something like this to the MANIFEST.MF:
// to org.hibernate.core
Eclipse-BuddyPolicy: registered
// to org.acme.project
Eclipse-RegisterBuddy: org.hibernate.core
However I can't add anything to Hibernate's manifest. I tried contributing the line via fragment, but that did not work either.
I even tried adding the entire Hibernate dependencies as JAR into a plug-in to add the above. It won't work.
How to resolve these classloader issues?
If your #Audited class references an Enum, org.hibernate.core needs to import the classes package. The best way to do this is to register a fragment bundle.
Also, it is wise to make sure your start level for hibernate bundles is lower than the start levels for entity bundles.
Here is a snippet from a sample Gradle script to create a fragment bundle. Make sure your change the org.hibernate.core bundle version to the one you are using, and also update the 'your.package' to the one that contains your Enum.
/*
When using Envers, entities that reference Enum classes must be imported (Import-Package) by the org.hibernate.core bundle.
*/
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'biz.aQute.bnd:biz.aQute.bnd.gradle:3.2.0'
}
}
apply plugin: 'biz.aQute.bnd.builder'
jar {
manifest {
attributes(
'Fragment-Host': 'org.hibernate.core;' + 'bundle-version=' + '5.2.9.Final',
'Import-Package': 'your.package'
)
}
}
Late to the party, but throwing this here in case anyone else needs it:
Hibernate bootstrapping looks fairly different in OSGi than it does in SE/EE land. We have numerous tickets in JIRA tracking enhancements, especially to make things more dynamic and to reduce the brittleness of startup ordering (Steven is absolutely correct that hibernate-core, hibernate-envers, etc. must currently be started first prior to your bundle).
I'd highly advise against the bundle fragment approaches, but I'll comment why on Steven's answer.
Our hibernate-demos project has a few OSGi quickstarts, all of which include Envers setup. This one is probably more of what you're looking for: https://github.com/hibernate/hibernate-demos/tree/master/hibernate-orm/osgi/unmanaged-native
So I was loosely following the Amdatu JPA video tutorial and I almost got it working...
At a glance everything seems to be fine, only DataSource service is not resolved and I don't know why. It seems to me that it is registered. So how would I go debugging this, there should be some way to debug this, right?
When starting I have this in msg log:
[CM Configuration Updater (Update: pid=org.amdatu.jpa.datasourcefactory.dd8bf61e-01b1-4732-9b0c-bba96e1f5aff)] DEBUG org.amdatu.jpa.datasourcefactory - ServiceEvent REGISTERED - [javax.sql.DataSource] - org.amdatu.jpa.datasourcefactory
Output of "dm":
[5] org.amdatu.jpa.datasourcefactory
org.osgi.service.cm.ManagedServiceFactory(service.pid=org.amdatu.jpa.datasourcefactory) registered
org.osgi.service.log.LogService service optional available
javax.sql.DataSource(validationQuery=SELECT 1,name=ManagedDS,driverName=postgresql,serviceName=ManagedDS) registered
org.osgi.service.log.LogService service optional available
org.osgi.service.jdbc.DataSourceFactory (osgi.jdbc.driver.class=org.postgresql.Driver) service required available
javax.transaction.TransactionManager service required available
So the output above should mean that DataSource is registered, right?
[31] org.amdatu.jpa.extender
org.amdatu.jpa.extender.PersistenceBundleManager() registered
org.osgi.service.log.LogService service optional available
javax.persistence.spi.PersistenceProvider service required available
active (Meta-Persistence=*) bundle optional available
java.lang.Object(bundle=32) registered
org.osgi.service.log.LogService service optional available
org.amdatu.jpa.extender.PersistenceBundleManager service required available
org.amdatu.jpa.extender.PersistenceUnitInfoImpl#7175ee92 unregistered
javax.persistence.spi.PersistenceProvider (javax.persistence.provider=org.eclipse.persistence.jpa.PersistenceProvider) service required available
javax.sql.DataSource (name=ManagedDS) service required unavailable
Everything further that depends on DataSource is obviously not resolved
javax.persistence.EntityManager service required unavailable
So what I don't get is why is DataSource not resolved there? I checked and it seems it is registered with property name=ManagedDS, but I am quite new to Felix DS so I am not really sure what is happening here.
I also tried adding this
#ServiceDependency(filter="(name=ManagedDS)")
private volatile DataSource ds;
to one of my services, but that too cannot be resolved. Thanks for any help regarding this, but what I would be most grateful of would be a way to debug and solve this myself.
So, Amdatu video tutorial suggested I should add
Import-Package: javax.sql;version=1.0.0
to my bundles. I tried removing that and it works (I did that when it stopped resolving that import after I set all versions to small ranges. Still don't know why it did that and wish that I tried that sooner)
So my guess as to why it works now - packages in my OSGi container were probably using two different versions/instances of javax.sql.DataSource. Probably one from postgres package and other someplace else (system?). Maybe one of the OSGi gurus can comment on this and clear it up?
Another sub-question is as that video suggested it is a good thing to add that import, what can I do to make it work or if it not important should I just not bother?
I have a WAR application as follows:
JPA/Hibernate 4.1.9.Final
Hibernate Envers 4.1.9.Final
Spring 3.1.3.RELEASE
Spring MVC with JSON/REST
My frontend (web page) makes a request, this leads to a new entity to be saved (this seems to succeed in any case) and then Envers will save corresponding revision info.
Typical deployment is in Tomcat 7, where this works just fine.
For unit testing I spin up a Jetty (8.1.9.v20130131) programmatically, which fails. It baffles me why this behavior is different. I can only imagine that Jetty has a different (lesser standard, perhaps) transaction management on board than Tomcat, but I've failed to pin it down or otherwise work around this.
Below is how I create the web application programmatically:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({"classpath:applicationContext.xml" })
public class AddCustomerTest {
And:
server = new Server(serverPort);
WebAppContext webAppContext = new WebAppContext();
webAppContext.setContextPath("/webapp");
webAppContext.setWar("src/main/webapp");
webAppContext.setServer(server);
server.setHandler(webAppContext);
Below is the essential exception that I'm getting:
Caused by: org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:357)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:334)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at com.sun.proxy.$Proxy115.getByUuid(Unknown Source)
at com.totaalsoftware.incidentmanager.entity.audit.RevisionEntityListener.setUser(RevisionEntityListener.java:53)
at com.totaalsoftware.incidentmanager.entity.audit.RevisionEntityListener.instanceNewRevision(RevisionEntityListener.java:40)
at com.totaalsoftware.incidentmanager.entity.audit.RevisionEntityListener.newRevision(RevisionEntityListener.java:34)
at org.hibernate.envers.revisioninfo.DefaultRevisionInfoGenerator.generate(DefaultRevisionInfoGenerator.java:95)
at org.hibernate.envers.synchronization.AuditProcess.getCurrentRevisionData(AuditProcess.java:124)
at org.hibernate.envers.synchronization.AuditProcess.executeInSession(AuditProcess.java:106)
at org.hibernate.envers.synchronization.AuditProcess.doBeforeTransactionCompletion(AuditProcess.java:155)
at org.hibernate.engine.spi.ActionQueue$BeforeTransactionCompletionProcessQueue.beforeTransactionCompletion(ActionQueue.java:662)
... 80 more
My RevisionEntityListener looks up some user data (from the database, using Hibernate of course). Clearly there's no transaction available, but only when running in Jetty. I've tried marking the RevisionEntityListener transactional in various ways, to no avail.
Let me know if you need any other info. Your help much appreciated!
Stupid me...
The following two lines were copied over from some other test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({"classpath:applicationContext.xml" })
These two lines served no purpose since the entire application was loaded through the instantiation and configuration of Jetty. But somehow the above clashed with the application in the Jetty server, probably due to being in the same JVM. Removing the above two lines from the test class fixed it!
Spring MVC web app:
I have a stack trace w/o line numbers (shown at bottom).
I presume that this is due to CGLib running on the controller. But this is odd to me, the actual exception occurs in ServerBatchRemoteRequestAcceptor, a pojo that is not injected, not the controller. It is only created in the Controller object.
Example:
#Controller
class MyController {
MyPojo pojo = new MyPojo();
#RequestMapping("myaction")
public void doMyAction(){
pojo.methodToCauseNullPointerException()
}
}
java.lang.NullPointerException
at mycommons.services.batchremoteprocessor.ServerBatchRemoteRequestAcceptor.acceptRequest(Unknown Source)
at com.proxyandvpn.web.controllers.RESTServicesController.handleGenericClientRequest(Unknown Source)
at com.proxyandvpn.web.controllers.RESTServicesController$$FastClassByCGLIB$$dff24f0f.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:688)
Can someone explain this behavior to me? Will every call under my Controllers be without line numbers due to CGLib?
Should I write my Controllers to an interface so that proxies are used? Is that normal? I do it for services, but have done the controllers as simple POJOs.
Spring uses CGLIB to generate proxy objects that sit in front of some of your components/controllers. Calls to those components pass through the CGLIB proxies. These proxies are generated a runtime, with no source code, so they have no line numbers.
You can pretty much ignore the stack trace lines that mention CGLIB, though - pretend they're not there, they should be transparent.
In your stack trace, the call to RESTServicesController.handleGenericClientRequest has been proxied, but the call is still getting there. The NPE is occurring within ServerBatchRemoteRequestAcceptor, which is being invoked from RESTServicesController.handleGenericClientRequest.
However, the source code you posted has no relation to the stack trace, so it's hard to comment as to why it happened.
I will add to this answer as I now know my problem. As is common when you don't understand a problem, I didn't ask the right question.
I had recently switched to using ANT builds instead of Eclipse builder. I didn't realize that I needed to expressly enable debugging information in the task. I unwittingly blamed CGLib when I saw it sitting in front of this error, but all that was necessary was an ANT build modification.
I'm using the Tapestry5 tapx template library to send an html email, as per this example.
When I run the example I get the following error:
Caused by: java.lang.RuntimeException: No service implements the interface org.springframework.context.ApplicationContext.
at org.apache.tapestry5.ioc.internal.RegistryImpl.getService(RegistryImpl.java:560)
at org.apache.tapestry5.ioc.internal.ObjectLocatorImpl.getService(ObjectLocatorImpl.java:44)
All the tapestry-* jars, including tapestry-spring-5.1.05.jar are in my classpath.
Any clues as to what I'm missing?
Figured it out. SpringIOC loads all modules it find on the classpath. The SpringModule, in tapestry-spring.jar, attempts to initialise the ApplicactionContext service, which causes the problem.
Removing tapestry-spring.jar from the classpath fixes the problem.
Follow the directions on the web site carefully; my guess is that you are not using the special TapestrySpringFilter (instead of the normal TapestryFilter).
It's been a while since I looked at this code; I can't remember if the ApplicationContext is exposed as a service or injectable object. Seems like it should be.
Fair enough; not sure what you situation is, but you should look in more detail at what TapestrySpringFilter does in terms of set up and replicate it into your standalone app's startup. There's some special bootstrapping magic that you will want to leverage.