I have a OSGI (Equinox-based) platform running a bundle. This bundle connects to Hazelcast for retrieving some data with:
ClientConfig clientConfig = new XmlClientConfigBuilder(configIs).build();
clientConfig.setClassLoader(com.MyClass.class.getClassLoader());
HazelcastInstance instance = com.hazelcast.client.HazelcastClient.newHazelcastClient(clientConfig);
But at runtime (instance.getMap(map).values()), during the deserialization of com.MyClass, I got the followin exception:
com.hazelcast.nio.serialization.HazelcastSerializationException: java.lang.ClassNotFoundException: com.MyClass
I don't really understand why Hazelcast would not be able to find com.MyClass, especially with the way I am calling the setClassLoader() method. The com.MyClass btw implements Serializable interface.
I know integrating Hazelcast with OSGI seems to be a common difficulty but I've not been able to find a resolution so far..
Any help would be appreciated :)
Edit:
Hazelcast version: 3.7.1
When I use the OBJECT in memory map format, I got the error during serialization & deserialization. With BINARY in memory map format, I got the error only during deserialization
Apparently this is not related to OSGI. I am facing the very same issue with a "normal" Java app. I just face the issue when I am using the values() method using a Predicate.
I solved my issue. If one day someone faces the very same one, please not that Predicate are managed on server side. It means you must import the bean class in the Hazelcast classpath.
Related
I am porting an old IBM Process Server application to IBM WebSphere Liberty. It contains a lot of code based on Service Data Objects (SDO). I have some good working code, running as standalone Java, using JDK8. I am using eclipselink 2.7.7, specifically 2 jar files;
eclipselink.jar
commonj.sdo_2.1.1v20111051852.jar
I have built this code into a Servlet to handle SOAP requests, and packaged it, along with other code, into an EAR file, which I deployed under IBM WebSphere Liberty 20. It doesn't work. There seems to be a clash with the Liberty version of EclipseLink.
If I deploy the code as a WAR file, and add a classloader of "PARENT_LAST", the code works fine.
However, if I try to deploy the code in an EAR file, and set a classloader of "PARENT_LAST" for the ear file, I get this error;
[ERROR ] CWWKZ0106E: Could not start web application S21.
[ERROR ] CWWKZ0002E: An exception occurred while starting the application S21. The exception message was: com.ibm.ws.container.service.state.StateChangeException: java.lang.LinkageError: loader constraint violation in interface itable initialization: when resolving method "org.eclipse.persistence.jpa.PersistenceProvider.getProviderUtil()Ljavax/persistence/spi/ProviderUtil;" the class loader (instance of com/ibm/ws/classloading/internal/ParentLastClassLoader) of the current class, org/eclipse/persistence/jpa/PersistenceProvider, and the class loader (instance of org/eclipse/osgi/internal/loader/EquinoxClassLoader) for interface javax/persistence/spi/PersistenceProvider have different Class objects for the type javax/persistence/spi/ProviderUtil used in the signature
Does anyone know whether I can replace the IBM Liberty implementation of EclipseLink with my version 2.7.7 version?
My application also uses JPA, which is working fine under Liberty, so I don't want to break that.
Any help / guidance appreciated... it's been a very long saturday.
PS:
I tried running the java code using only the SDO library (commonj.sdo_2.1.1v20111051852.jar), and relying on the WebSphere Liberty runtime jars to provide Eclipselink functionality, and I got the following errors, which is why I then moved to adding the "matching pair" of Eclipselink / SDO jars mentioned above;
Caught Exception : org.eclipse.persistence.internal.security.PrivilegedAccessHelper.getSystemPropertyBoolean(Ljava/lang/String;Z)Z
java.lang.NoSuchMethodError: org.eclipse.persistence.internal.security.PrivilegedAccessHelper.getSystemPropertyBoolean(Ljava/lang/String;Z)Z
at org.eclipse.persistence.sdo.helper.SDOHelperContext.<init>(SDOHelperContext.java:93)
at org.eclipse.persistence.sdo.helper.SDOHelperContext$DefaultHelperContextResolver.getHelperContext(SDOHelperContext.java:1432)
at org.eclipse.persistence.sdo.helper.SDOHelperContext.getHelperContext(SDOHelperContext.java:492)
at org.eclipse.persistence.sdo.helper.SDOHelperContext.getHelperContext(SDOHelperContext.java:471)
at org.eclipse.persistence.sdo.helper.SDOHelperContext.getHelperContext(SDOHelperContext.java:456)
at org.eclipse.persistence.sdo.helper.delegates.SDOXMLHelperDelegator.getXMLHelperDelegate(SDOXMLHelperDelegator.java:178)
at org.eclipse.persistence.sdo.helper.delegates.SDOXMLHelperDelegator.load(SDOXMLHelperDelegator.java:78)
at com.ebs.solas2021.port.adapter.ui.SOAPRequestHandler.main(SOAPRequestHandler.java:237)
It's amazing what you find whgen you re-read the documentation in the cold light of a new day. It turns out that it's possible to install a JPA 2.2 Container on Liberty, while supplying one's own implementation of EclipseLink. Works like a charm.
Documented here: https://openliberty.io/blog/2018/06/29/full_java_ee_8_liberty_18002.html
I just tried to run an OptaPlanner project in Spring Boot, but there's only very simple text in OptaPlanner User Guide for Spring.
Actually, I think it is very easy to copy all domain objects, configuration files and drools files from an OptaPlanner project to Spring Boot project without any changes, but the only question is how to call Solver's solve method.
I made it run after Spring Boot startup with a class (named CommandLineAppStartupRunner) which implements CommandLineRunner interface, and I called solve method in its run method. Finally, I got an exception like follows:
Caused by: java.lang.IllegalArgumentException: Can not set org.optaplanner.core.api.score.buildin.hardmediumsoft.HardMediumSoftScore field springbootcloudbalance.domain.CloudBalance.score to springbootcloudbalance.domain.CloudBalance
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
at java.lang.reflect.Field.get(Field.java:393)
at org.optaplanner.core.impl.domain.common.accessor.ReflectionFieldMemberAccessor.executeGetter(ReflectionFieldMemberAccessor.java:54)
at org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor.getScore(SolutionDescriptor.java:1071)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.cloneSolution(AbstractScoreDirector.java:212)
at org.optaplanner.core.impl.solver.scope.DefaultSolverScope.setWorkingSolutionFromBestSolution(DefaultSolverScope.java:230)
at org.optaplanner.core.impl.solver.AbstractSolver.solvingStarted(AbstractSolver.java:75)
at org.optaplanner.core.impl.solver.DefaultSolver.solvingStarted(DefaultSolver.java:210)
at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:190)
at springbootcloudbalance.CommandLineAppStartupRunner.run(CommandLineAppStartupRunner.java:55)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:818)
... 10 common frames omitted
I checked the code, and found the exception throws because the object from field.getDeclaringClass() is a different instance from the one from var1.getClass(). I'm afraid it due to the implementation of java reflection conflicts between OptaPlanner and Spring Boot.
The version I used is as follows:
OptaPlanner 7.11.0.Final
Spring Boot 2.0.5.RELEASE
JVM 1.8.0_181
Removing the spring-boot-devtools dependency fixes this error. Another SO question similar to this one explains it has something to do with different classloaders: Optaplanner's Drools working memory is empty. The accepted answer also mentions a possible fix:
To fix it, configure spring dev tools to load Drools libraries in the RestartClassLoader, together with the project's classes: using-boot-devtools-customizing-classload
Nick's answer is correct. This is just to figure out what's going on.
This line means that optaplanner is extracting CloudBalance.getScore():
at org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor.getScore(SolutionDescriptor.java:1071)
This line means that it's using a ReflectionFieldMemberAccessor for that, which is just way to read a field through reflection (including private fields):
at org.optaplanner.core.impl.domain.common.accessor.ReflectionFieldMemberAccessor.executeGetter(ReflectionFieldMemberAccessor.java:54)
Now the error message is where it gets interesting:
Can not set ...HardMediumSoftScore field ...CloudBalance.score to ...CloudBalance
It looks like basically doing:
CloudBalance cloudBalance2 = cloudBalance.getScore();
Huh?
Musa provided this answer, but someone deleted it, despite that the JIRA link is extremely relevant, as it points out which version of OptaPlanner will deal better with this problem:
"An issue was submitted to OptaPlanner to provide better error messages for such cases: https://issues.jboss.org/browse/PLANNER-1586. Feel free to add any comments or suggestions."
I know this is a common problem, but creating a new thread just in case if some one is stuck like me even after trying some of the options already explained in documentions.
I have deployed an osgi bundle (Say Bundle B) which have all the code related to Data layer access. Basically when a service method from this bundle is accessed, it creates a JDBC connection for the very first time only, by loading the driver. The Driver is deployed as another wrapped bundle of sqljdbc 4.0. (Say Bundle C)
Now I have Bundle TestApp (Say Bundle A) which creates an instance the above said service method from Bundle B. So the flow here is Bundle A code creates an instance of Bundle B's exported service which in turn access Bundle C's Driver class.
Caused by: java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver not found by DataServices [417]
at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1556)
at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:77)
at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1993)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
The individual classloader is making the probelm here, but how to overcome is the situation here for me. I tried adding DynamicImport-Package to bundles A, B, tried creating a Fragment bundle as expained here https://gist.github.com/rotty3000/1291842 but still the same exception. Continues.
If anyone came across such an issue, it would be a great help if you could give me a step by step approach to get rid of this issue.
Thank you in advance and Happy new year of all.
The Driver approach is not working well in OSGi. Instead use a DataSource.
See example at msdn. You can simply create a datasource using new. This avoids any classloading problems.
If you want to decouple from the actual DB provider then you can use the OSGi jdbc spec which defines that db providers should expose a DataSourceFactory that can create a DataSource for you.
Pax-jdbc supports this spec for a big range of db providers. It allows has a pax-jdbc-config module that allows to create a DataSource as an OSGi service using just a config. So in you code you can just inject the service and are done. Additionally pax-jdbc-config also can take care of pooling and making the DataSource XA aware. So it produces a fully production ready DataSource.
I'm using Hazelcast 3.6.2 and cant get the classloader to work when in a multi-bundle environment. What is the approach on this? Setting the classloader in the config only works if the class to load is in the same bundle. In my case the class to load is in another bundle than the one creating the hazelcast instance.I world like you to use the HazelcastOsgiService and HazelcastOsgiInstance.
Any input is appreciated.
You have to provide your own classloader trick by writing a Delegating ClassLoader that keeps track of installed bundles. I did one of those "hacks" in the past to test it. You can find some code for the same issue, solved using a custom Serializer, on github (https://github.com/noctarius/hazelcast-mapreduce-demo/blob/master/musicdb-model/src/main/java/com/hazelcast/example/musicdb/server/ModelMapReduceActivator.java), anyhow Hazelcast does not yet officially support that out of the box.
I'm currently working on an OSGi application running under apache Karaf that uses JPA and QueryDSL.
I was wondering if I could use Spring Data with QueryDSL instead of the current approach.
The reason for this is that I find Spring repositories to be quite useful and having a template for NoSQL database accesses might be useful in the future.
I have tried to start a normal spring application without a web context with OSGi but I get a ClassNoutFoundException when it tries to load the applicationContext.xml or the ApplicationContext.class.
I don't want to use Spring DM since it is discontinued.
Basically the sole reason for wanting to try this integration is for the Spring Repositories, but if you think this is not necessary please tell me. Any information regarding how to achive this or if it's ok to persue this would be more than welcome.
Thank you
Update
I've managed to make spring work by starting the application context with org.eclipse.gemini.blueprint.context.support.OsgiBundleXmlApplicationContext. The applicationContext is exported in OSGi as a service and I can get all the beans that I need by calling it.
The problem I'm having right now is that when I declare <jpa:repositories base-package="x.y.z" /> I get the following exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0' defined in URL [bundle://251.13:0/META-INF/spring/applicationContext.xml]: Initialization of bean failed; nested exception is java.lang.IllegalStateException: No persistence exception translators found in bean factory. Cannot perform exception translation.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527)[185:org.springframework.beans:3.1.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)[185:org.springframework.beans:3.1.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)[185:org.springframework.beans:3.1.4.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)[185:org.springframework.beans:3.1.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)[185:org.springframework.beans:3.1.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)[185:org.springframework.beans:3.1.4.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1109)[187:org.springframework.context:3.1.4.RELEASE]
at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.registerBeanPostProcessors(AbstractDelegatedExecutionApplicationContext.java:502)[193:org.eclipse.gemini.blueprint.core:1.0.0.RELEASE]
at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.registerBeanPostProcessors(AbstractDelegatedExecutionApplicationContext.java:451)[193:org.eclipse.gemini.blueprint.core:1.0.0.RELEASE]
at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext$4.run(AbstractDelegatedExecutionApplicationContext.java:306)[193:org.eclipse.gemini.blueprint.core:1.0.0.RELEASE]
at org.eclipse.gemini.blueprint.util.internal.PrivilegedUtils.executeWithCustomTCCL(PrivilegedUtils.java:85)[193:org.eclipse.gemini.blueprint.core:1.0.0.RELEASE]
at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.completeRefresh(AbstractDelegatedExecutionApplicationContext.java:290)[193:org.eclipse.gemini.blueprint.core:1.0.0.RELEASE]
at org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor$CompleteRefreshTask.run(DependencyWaiterApplicationContextExecutor.java:137)[194:org.eclipse.gemini.blueprint.extender:1.0.0.RELEASE]
at java.lang.Thread.run(Thread.java:662)[:1.6.0_37]
Caused by: java.lang.IllegalStateException: No persistence exception translators found in bean factory. Cannot perform exception translation.
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.java:142)[195:org.springframework.transaction:3.1.4.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.<init>(PersistenceExceptionTranslationInterceptor.java:79)[195:org.springframework.transaction:3.1.4.RELEASE]
at org.springframework.dao.annotation.PersistenceExceptionTranslationAdvisor.<init>(PersistenceExceptionTranslationAdvisor.java:70)[195:org.springframework.transaction:3.1.4.RELEASE]
at org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor.setBeanFactory(PersistenceExceptionTranslationPostProcessor.java:103)[195:org.springframework.transaction:3.1.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1475)[185:org.springframework.beans:3.1.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1443)[185:org.springframework.beans:3.1.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)[185:org.springframework.beans:3.1.4.RELEASE]
As a JPA provider I'm using OpenJPA. The entityManagerFactory is a service which I can get by using the blueprint. I think I need to reference it in <jpa:repositories base-package="x.y.z" />, but how do I do that since the applicationContext.xml is read by spring and not the blueprint?
I would really appreciate any hint in the right direction.
Thank you
Use Querydsl-SQL directly in your code and
it will work well within OSGi as it does not use class loading, weaving, enhancing, caching and other tricks that sound really good but causes chaos
your code will run much faster than with any of the "cache-enhanced" JPA engines
others will be able to understand your code (not like JPA Criteria API queries)
you will know exactly what SQL commands run on the Database Server that minimizes problem-solving time
your code will be as database independent as with any ORM tool
Do not use Spring, spring-data, JPA and other monoholitic technologies together with OSGi as
they were designed to work within monoholitic systems where everything is in one application context, not in separate bundles
by using these technologies together with OSGi you will spend most of your time to fix bugs like this and looking for workarounds
People who argue with this, already spent lots of time on finding such workarounds. They managed to implement some business logic. They hope that they now truly found workarounds for every conceptual issue and they do not have to spend the same amount of work next time. They are in a bidding fee auction. Be honest guys! Somewhere deep you know I am right ;-).
I am saying this with the experience that I
tried the perfect stack based on Hibernate and Don't repeat the DAO article of IBM (much before Spring-Data hype began). Twice
wrote hibernate-osgi-adapter for Hibernate 4.1.x
Re-implemented the complete JPA chapter of OSGi Enterprise specification
Well you have a couple of choices here, try to get it to run with blueprint (probably the hardest - since you need to call spring beans, but I think could still be done), use Karaf 3.0.0.RC1 it also supports Blueprint Geminin which does have a tighter support for Spring and last but not least use Spring-DM, even if it is discontinued you are able to use and probable the best approach is to use spring-dm for certain Spring specific parts and std. Blueprint for the rest. Because you just use services through both frameworks everything will work, just don't mix the spring and blueprint descriptors in one bundle.