How to configure dependencies for DataNucleus AppEngine plugin v3? - google-app-engine

In my project (Spring Framework + Google App Engine + DataNucleus + JPA) I get the following exception on the server startup:
WARNING: Nestedin org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMappingContext': Invocation of init method failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in ServletContext resource [/WEB-INF/spring/db.xml]: Invocation of init method failed;
nested exception is java.lang.NoSuchMethodError: org.datanucleus.metadata.MetaDataUtils.parsePersistenceFiles(Lorg/datanucleus/plugin/PluginManager;Ljava/lang/String;ZLorg/datanucleus/NucleusContext;)[Lorg/datanucleus/metadata/PersistenceFileMetaData;:
java.lang.NoSuchMethodError: org.datanucleus.metadata.MetaDataUtils.parsePersistenceFiles(Lorg/datanucleus/plugin/PluginManager;Ljava/lang/String;ZLorg/datanucleus/NucleusContext;)[Lorg/datanucleus/metadata/PersistenceFileMetaData;
at org.datanucleus.api.jpa.JPAEntityManagerFactory.<init>(JPAEntityManagerFactory.java:342)
at org.datanucleus.api.jpa.PersistenceProviderImpl.createEntityManagerFactory(PersistenceProviderImpl.java:91)
Obviously this exception is throwed during persistence.xml parsing. Spring tries to invoke method MetaDataUtils#parsePersistenceFiles(PluginManager,String,NucleusContext,nucCtx), but it is absent. This method is a part of org.datanucleus:datanucleus-core. At first I thought that I have a missing or duplicate dependency somewhere. I've executed
gradle dependencies
carefully scanned output and found nothing suspicious: only a single version of the dependency.
According to the documentation MetaDataUtils has only one parsePersistenceFiles method:
public static PersistenceFileMetaData[] parsePersistenceFiles(
PluginManager pluginMgr, String persistenceFilename, boolean validate, ClassLoaderResolver clr);
If you are observant, you've probably noticed that it differs in arguments: there is an extra boolean validate argument. Odd thing is that there is no such method in any version of DataNucleus. Why is DataNucleus looking for the method that haven't even existed? I can't get it.
Please help DataNucleus and me find the missing method!
UPDATE
As Neil Stockton pointed out it's because I'm using inconsistent versions of datanucleus-core and datanucleus-api-jpa. But I don't know the right combination of dependencies. And I'm starting to think, that DataNucleus App Engine Plugin 3.0 is not currently ready for usage.
I want to use DataNucleus App Engine Plugin 3.0 because of this issue (fixed in DataNucleus versions 3.2.6 and 3.3.3) and because I need JPA 2.1 features (fetch groups / entity graphs). The DataNucleus App Engine Plugin 3.0 is compatible with the mentioned versions of DataNucleus, but unreleased. I've checked out the plugin from SVN, packaged it, and added to my project as jar (an identical jar is available for download, if you want to repeat this setup yourself).
build.gradle:
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'appengine'
dependencies {
// App Engine
compile fileTree(dir: 'libs', include: ['*.jar']) // There is datanucleus-appengine-3.0.0-20140128.jar in libs
appengineSdk 'com.google.appengine:appengine-java-sdk:1.9.19'
compile 'com.google.appengine:appengine-api-1.0-sdk:1.9.19'
// persistence
// App Engine and DataNucleus compatibility:
// https://code.google.com/p/datanucleus-appengine/wiki/Compatibility
compile 'org.eclipse.persistence:javax.persistence:2.1.0'
runtime 'org.datanucleus:datanucleus-core:3.2.15'
compile 'org.datanucleus:datanucleus-api-jpa:3.1.3'
compile 'javax.jdo:jdo-api:3.1'
compile 'org.datanucleus:datanucleus-jodatime:3.2.1'
// Spring Framework
compile("org.springframework:spring-webmvc:4.1.6.RELEASE")
compile ("org.springframework.data:spring-data-jpa:1.8.0.RELEASE")
providedCompile 'javax.annotation:javax.annotation-api:1.2'
compile 'com.google.code.gson:gson:2.3.1'
providedCompile 'org.projectlombok:lombok:1.16.+'
}
appengine {
downloadSdk = true
httpAddress = "0.0.0.0"
}
Spring context:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"
default-autowire="byName">
<jpa:repositories base-package="<my.package.name>.repositories" />
<!-- The simplest and the most limited form of JPA deployment -->
<!-- For details see http://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html#orm-jpa -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="transactions-optional" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
Persistence unit
<persistence-unit name="transactions-optional">
<provider>org.datanucleus.api.jpa.PersistenceProviderImpl</provider>
<properties>
<property name="datanucleus.NontransactionalRead" value="true" />
<property name="datanucleus.NontransactionalWrite" value="true" />
<property name="datanucleus.ConnectionURL" value="appengine" />
<property name="datanucleus.appengine.datastoreEnableXGTransactions" value="true" />
</properties>
</persistence-unit>
UPDATE:
If I put datanucleus-api-jpa of another version on CLASSPATH, for example
compile 'org.datanucleus:datanucleus-api-jpa:3.2.2'
I get an exception during enhancement:
java.lang.RuntimeException: Unexpected exception
at com.google.appengine.tools.enhancer.Enhancer.execute(Enhancer.java:76)
at com.google.appengine.tools.enhancer.Enhance.<init>(Enhance.java:71)
... 1 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
... 5 more
Caused by: org.datanucleus.exceptions.NucleusException:
Plugin (Bundle) "org.datanucleus.api.jpa" is already registered.
Ensure you dont have multiple JAR versions of the same plugin in the classpath.
The URL "file:/<GRADLE_HOME>/appengine-sdk/appengine-java-sdk-1.9.19/lib/opt/tools/datanucleus/v2/datanucleus-api-jpa-3.1.3.jar" is already registered,
and you are trying to register an identical plugin located at URL "file:/<GRADLE_HOME>/caches/modules-2/files-2.1/org.datanucleus/datanucleus-api-jpa/3.2.2/c24c14634c39b5b9a59dcd379dbb6d93da97f3e7/datanucleus-api-jpa-3.2.2.jar."
at org.datanucleus.plugin.NonManagedPluginRegistry.registerBundle(NonManagedPluginRegistry.java:541)
at org.datanucleus.plugin.NonManagedPluginRegistry.registerBundle(NonManagedPluginRegistry.java:395)
From documentation:
The App Engine Java SDK includes version 2.x of the DataNucleus plugin for App Engine. This plugin corresponds to version 3.0 of the DataNucleus Access Platform, which enables you to use the App Engine Datastore via JPA 2.0.
JPA presents a standard interface for interacting with relational databases, but the App Engine datastore is not a relational database. As a result, there are features of JPA that App Engine simply cannot support.

The simple fact is that you have to use consistent versions of the various jars. If using Google's "datanucleus-appengine" v3.0 (SVN) then you MUST have DataNucleus project "datanucleus-core", "datanucleus-api-jpa" v3.2.x (or 3.3.x of the datanucleus-api-jpa) and no other versions. If you get some message about
Plugin (Bundle) "org.datanucleus.api.jpa" is already registered.
then you have multiple versions of that plugin in the CLASSPATH and you should FIX your CLASSPATH (just print out what is in the CLASSPATH and it will tell you ... something like System.getProperty("java.class.path")).
In your case you have
file://appengine-sdk/appengine-java-sdk-1.9.19/lib/opt/tools/datanucleus/v2/datanucleus-api-jpa-3.1.3.jar
and
file://caches/modules-2/files-2.1/org.datanucleus/datanucleus-api-jpa/3.2.2/c24c14634c39b5b9a59dcd379dbb6d93da97f3e7/datanucleus-api-jpa-3.2.2.jar
so get rid of the first one

Related

Accessing OpenMQ JMS Broker from ServiceMix+Camel

I am trying to get ServiceMix+Camel talking to OpenMQ JMS Broker. I have a Camel route definition defined in Blueprint DSL which posts messages into an ActiveMQ JMS Queue. This is working fine, but I am now trying to convert this to post messages to an instance of OpenMQ running inside a Glassfish4 container.
I'm running the following configuration:
JDK 1.7.0_60
ServiceMix 5.1.1 (so Camel 2.13.2)
The documentation on this topic is somewhat minimal, but I've gathered various snippets from Google searches here and here and come up with the following (relevant parts only):
....
<!-- Post over JMS into Manager -->
<to uri="openmq:queue:resman"/>
</route>
</camelContext>
<bean id="openmq" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory">
<bean class="com.sun.messaging.ConnectionFactory">
<property name="imqAddressList" value="localhost:7676"/>
</bean>
</property>
</bean>
I have the following JMS related "features" enabled in Servicemix/OSGI:
[installed ] [3.2.4.RELEASE ] spring-jms
[installed ] [2.13.2 ] camel-jms
and I have the following OSGI bundles installed and active:
[ 89] [Active ] [ ] [ ] [ 50] geronimo-jms_1.1_spec (1.1.1)
[ 126] [Active ] [ ] [ ] [ 50] camel-jms (2.13.2)
The problem I have is a ClassNotFoundException at the point I deploy the Came Route Blueprint into ServiceMix. Here are the relevant snippets from the Stacktrace logged:
org.osgi.service.blueprint.container.ComponentDefinitionException: Unable to instantiate components
Caused by: java.lang.NoClassDefFoundError: javax/jms/JMSContext
Caused by: java.lang.ClassNotFoundException: javax.jms.JMSContext not found by org.apache.geronimo.specs.geronimo-jms_1.1_spec [89]
So on the assumption this is an OSGI bundling issue, I've dug down into the Camel "features" just to confirm the dependencies:
karaf#root> features:info camel-jms
Description of camel-jms 2.13.2 feature
----------------------------------------------------------------
Feature has no configuration
Feature has no configuration files
Feature depends on:
spring [3.2,4)
spring-jms [3.2,4)
camel-core 2.13.2
Feature contains followed bundles:
mvn:org.apache.geronimo.specs/geronimo-jta_1.1_spec/1.1.1 start-level=50
mvn:commons-pool/commons-pool/1.6 start-level=50
mvn:org.apache.geronimo.specs/geronimo-jms_1.1_spec/1.1.1 start-level=50
mvn:org.apache.camel/camel-jms/2.13.2 start-level=50
So it appears that it is the "geronimo-jms_1.1_spec" that is causing the stack trace as it can't find JMSContext. I making a big assumption that as ApacheMQ must be using the same JMS class, so it must be in the environment somewhere. Also, JMSContext seems to be a JMS 2.0 API interface, so is the issue here that the geronimo-jms_1.1_spec bundle is trying to reference a JMS2 API?
I also have the issue of getting the client JARs for OpenMQ installed into the environment. The OpenMQ client JARs shipped with Glassfish4 are plain JARs and not OSGI bundles (see https://java.net/jira/browse/MQ-328), so I plan to either use the "file:wrap" feature to deploy this into ServiceMix, or otherwise unpack and re-pack into the JAR containing my Beans. I don't think this is related to this problem, but I could be wrong.
OK, managed to work this one out finally. The clue was in the reference to javax.jms.JMSContext which is new in the JMS 2.0 API. I was attempting to use the OpenMQ client libraries (imq.jar and jms.jar) taken from the Glassfish4 distribution, which is at JEE7 and hence JMS v1.1. ServiceMix 5.1.1 is still at JMS V1.1, hence the ClassNotFoundException.
Solution:
When connecting to an instance of OpenMQ running under Glassfish4, you need to download and use the OpenMQ client libraries from the previous Glassfish 3.2.2 release. You can obtain this release release from the Glassfish project archives here.
Tests so far show this to be working fine, so if I find anything of relevance going forward I'll come back and update this post.

Jboss RestEasy web service connection pooling

Getting error
NoSuchMethodError: org.apache.http.impl.conn.DefaultClientConnectionOperator.(Lorg/apache/http/conn/scheme/SchemeRegistry;Lorg/apache/http/conn/DnsResolver;)
Using httpclient-4.2-alpha1.jar
Configuration :
<!-- Rest easy connection pooling -->
<bean id="poolingClientConnectionManager" class="com.auction.acp.rest.impl.ConnectionManager" >
</bean>
<bean id="httpClient" class="org.apache.http.impl.client.DefaultHttpClient" >
<constructor-arg name="conman" ref="poolingClientConnectionManager"> </constructor-arg>
</bean>
When I explore jar this constructor is already there.
First thing which is coming in my mind is some other library [I'm using JBoss] is in use.
Tried with exclusions in jboss-deployment-structure.xml but no luck.
<exclusions>
<module name="org.apache.httpcomponents" />
<module name="org.apache.http.impl.conn" />
</exclusions>
If the constructor exists in the JAR you're "exploring" but JBoss can't find it, it means JBoss is not using the JAR you want it to. I suggest using Logback for logging, as it'll add the name of the JAR to the stacktrace in your logs so you know which JAR JBoss is using.

Why does Persistence.createEntityManagerFactory("transactions-optional") errors when appengine is deployed

I have created an appengine which runs fine and returns records from my Google cloud SQL db in debug mode. When I deploy the appegine and run the endpoint it errors. And the error I get in the appengine log is:
Caused by: org.datanucleus.exceptions.NucleusUserException: There is no available StoreManager of type "jdbc". Make sure that you have put the relevant DataNucleus store plugin in your CLASSPATH and if defining a connection via JNDI or DataSource you also need to provide persistence property "datanucleus.storeManagerType".
Here is a list or the jars in war\WEB-INF\lib directory:
appengine-api-1.0-sdk-1.7.6
appengine-api-labs
appengine-endpoints
appengine-jsr107cache-1.7.6
asm-4.0
com.sun.tools.xjc_2.2.0
com.sun.xml.bind_2.2.0.v201004141950
datanucleus-api-jdo-3.1.3
datanucleus-api-jpa-3.1.3
datanucleus-appengine-2.1.2
datanucleus-core-3.1.3
eclipselink
eclipselink-jpa-modelgen_2.4.1.v20121003-ad44345
gcm-server
geronimo-jpa_2.0_spec-1.0
javax.activation_1.1.0.v201108011116
javax.mail_1.4.0.v201005080615
javax.persistence_2.0.4.v201112161009
javax.xml.bind_2.2.0.v201105210648
javax.xml.stream_1.0.1.v201004272200
jdo-api-3.0.1
json_simple-1.1
jsr107cache-1.1
jta-1.1
org.eclipse.persistence.jpars_2.4.1.v20121003-ad44345
Here is my persistence.xml:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
<persistence-unit name="transactions-optional" transaction-type="RESOURCE_LOCAL">
<provider></provider>
<class>com.example.myapp.Class1</class>
<class>com.example.myapp.Class2</class>
<properties>
<property name="datanucleus.NontransactionalRead" value="true"/>
<property name="datanucleus.NontransactionalWrite" value="true"/>
<property name="javax.persistence.jdbc.driver" value="com.google.appengine.api.rdbms.AppEngineDriver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:google:rdbms://something.com:someproj:someapp/somedb"/>
<property name="javax.persistence.jdbc.user" value=""/>
<property name="javax.persistence.jdbc.password" value=""/>
</properties>
</persistence-unit>
</persistence>
Using:
cloud sql
JPA
Datanucleous v2
SDK 1.7.6
Jre7
As it works fine in debug mode I dont understand what the problem might be as I am new to appengine. Please let me know if you need more information.
Thanks guys.
Make your mind up which JPA provider you're using ... for Cloud SQL (not AppEngine, so you don't need "datanucleus-appengine", nor do you need "datanucleus-api-jdo" either FWIW). You have DataNucleus JPA (version 3 actually, but omitting datanucleus-rdbms jar for some reason, yet CloudSQL needs it), and you have EclipseLink also. You then don't set the persistence provider in persistence.xml so leave it all to chance which one it tries to give you ... and it tries DataNucleus JPA but you haven't included the datanucleus-rdbms jar so you can't persist to an RDBMS without that.

Cloud Foundry + JPA + Spring + EntityManager

I want to deploy a Web based WAR into CloudFoundry using a cloud datasource.
I have defined a bean like this:
<cloud:data-source id="dataSource"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="myPersistenceUnit" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
</bean>
</property>
</bean>
</beans>
....but when i try to deploy I obtain a Java Agent exception :
Cannot apply class transformer without LoadTimeWeaver specified
But i can't specfy a Java Agent whithout uploading a jar instrument agent.....
Any solution??
I'm not that familiar with EclipseLink, so I'm not even sure that the weaver requirement comes from EclipseLink, BUT
One way of doing this would be to deploy your app as a standalone app (i.e. deploy your own tomcat around it), that way you can put the extra weaver jar in lib/.
Have a look at http://blog.cloudfoundry.org/2012/06/18/deploying-tomcat-7-using-the-standalone-framework/ and https://github.com/ericbottard/cloudfoundry-tomcat-7
Also, if you only have one DataSource, you can avoid using the cloudfoundry-specific <cloud:datasource /> namespace by just uploading your regular app and have Cloud Foundry auto reconfigure your app (info here: http://blog.springsource.org/2011/11/04/using-cloud-foundry-services-with-spring-part-2-auto-reconfiguration/) As a matter of fact, this may be the way to have EclipseLink work seamlessly on Cloud Foundry (my guess here)
And of course, there's also the option of switching to another provider that doesn't require class instrumentation, but that's a bit extreme.
Again, I'm not an Eclipse Link guru, so I may be missing something here...

JPA entity manager factory creation failing; JBoss, Hibernate and SQL Server

Running JBoss 5.1, with Hibernate as the JPA provider. Backed with SQL Server 2008.
I'm receiving an error at server startup, which is java.lang.ClassCastException: org.hibernate.dialect.SQLServerDialect cannot be cast to org.hibernate.dialect.Dialect. Pretty clear message, but I'm baffled as to the underlying cause. I have hibernate-core-3.5.1-Final.jar on the classpath, and the necessary class files are present.
This dialect setting was giving no error in the project when it was being used as a property being passed to a Spring AnnotationSessionFactoryBean, but I'm trying to refactor a piece to straight EJB/JPA. For what it's worth, here's my persistence config:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
version="1.0">
<persistence-unit name="[my name here]">
<jta-data-source>java:jdbc/[my name here]</jta-data-source>
<properties>
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
<property name="hibernate.cache.use_query_cache" value="true" />
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.EhCacheProvider" />
</properties>
</persistence-unit>
I hate these kind of "here's my config and my stacktrace" questions, but I've been poking around on this for an hour and a half and am failing to come up with any new ideas.
The ClassCastException is caused by having two copies of the javax.persistence APIs in your system. When running on JBoss, you are just not supposed to package persistence jar in your application. Remove all the persistence related jar's from your application and the exception should go away.

Resources