Persistence unit not injected in webservice - jpa

I have an application that was working on Java 6 + Glassfish 3. I am migrating this project to run on Glassfish 5.1 with oracle java 8.
The application builds without problems. During deployment the only jpa/eclipselink related lines are
Info: EclipseLink, version: Eclipse Persistence Services - 2.7.4.v20190115-ad5b7c6b2a
Info: /file:/home/eelke/NetBeansProjects/MplusLicentieService/build/web/WEB-INF/classes/_MplusLicentieServicePU login successful
However when a soap call is performed a NullPointerException is triggered. I have verified with the debugger that the pointer that is null is in fact the persistence unit. Here is the definition of the webservice, the EntitiyManager and one of the methods that failed. Within the method em == null. Left out other statements and variables.
#WebService(serviceName = "LicentieWebService")
public class LicentieWebService {
#PersistenceContext(unitName = "MplusLicentieServicePU")
private EntityManager em;
#Resource
private javax.transaction.UserTransaction utx;
#WebMethod(operationName = "getLicentie2")
public QLicentieAntwoord getLicentie2(
#WebParam(name = "licentieNr") String licentieNr,
#WebParam(name = "filiaalNr") int filiaal,
#WebParam(name = "werkplekNr") int werkplek,
#WebParam(name = "codewoord") String codewoord) {
try {
Licentie lic = em.find(Licentie.class, licentieNr);
...
} catch (ApplicationError ex) {
...
}
}
I also tried redefining the persistence unit in netbeans but this didn't change anything.
Some additional findings
In the same project is also a statelesss EJB which has a function that is called by a timer schedule. Into this EJB a second stateless EJB is injected with #Inject, this works. Into this second EJB the same persistent context is injected as in the webservice. This works, it is injected and queries are executed as expected.
Found some log lines which might be related
Info: JAX-WS RI specific descriptor (WEB-INF/sun-jaxws.xml) is found
in the archive web and hence Enterprise Web Service (109) deployment
is disabled for this archive to avoid duplication of services.

Related

UnknownServiceException: Unknown service requested [EnversService]

I want to run Hibernate in OSGi. I have added the standard Hibernate OSGi bundle and a Blueprint implementation, so that Envers gets registered right on startup.
Even without any kind of documentation I found out you have to start Envers, because... I doubt there is a logical reason, it does not work otherwise.
However now, even though Envers was registered in Blueprint, I get the following exception:
org.hibernate.service.UnknownServiceException: Unknown service requested [org.hibernate.envers.boot.internal.EnversService]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:184)
at org.hibernate.envers.boot.internal.TypeContributorImpl.contribute(TypeContributorImpl.java:22)
at org.hibernate.boot.internal.MetadataBuilderImpl.applyTypes(MetadataBuilderImpl.java:280)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.populate(EntityManagerFactoryBuilderImpl.java:798)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.<init>(EntityManagerFactoryBuilderImpl.java:187)
at org.hibernate.jpa.boot.spi.Bootstrap.getEntityManagerFactoryBuilder(Bootstrap.java:34)
at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilder(HibernatePersistenceProvider.java:165)
at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilderOrNull(HibernatePersistenceProvider.java:114)
at org.hibernate.osgi.OsgiPersistenceProvider.createEntityManagerFactory(OsgiPersistenceProvider.java:78)
at org.acme.project.Main.startSession(PersistenceUnitJpaProvider.java:38)
The stack trace starts at PersistenceProvider#createEntityManagerFactory in the following snippet:
public class Main {
private EntityManagerFactory entityManagerFactory;
public void startSession(Map<String, Object> config) {
BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
ServiceReference<PersistenceProvider> serviceReference = context.getServiceReference(PersistenceProvider.class);
PersistenceProvider persistenceProvider = context.getService(serviceReference);
this.entityManagerFactory = persistenceProvider.createEntityManagerFactory("persistenceUnit", config);
context.ungetService(serviceReference);
}
I found this bug, and maybe this issue is fixed in the current version of Hibernate. But since the bundle IDs are broken, I have to use 5.1.
So Envers is registered, but not really. What could be the reason for such a strange error message?

Spring Boot with application managed persistence context

I am trying to migrate an application from EJB3 + JTA + JPA (EclipseLink). Currently, this application makes use of application managed persistent context due to an unknown number of databases on design time.
The application managed persistent context allows us to control how to create EntityManager (e.g. supply different datasources JNDI to create proper EntityManager for specific DB on runtime).
E.g.
Map properties = new HashMap();
properties.put(PersistenceUnitProperties.TRANSACTION_TYPE, "JTA");
//the datasource JNDI is by configuration and without prior knowledge about the number of databases
//currently, DB JNDI are stored in a externalized file
//the datasource is setup by operation team
properties.put(PersistenceUnitProperties.JTA_DATASOURCE, "datasource-jndi");
properties.put(PersistenceUnitProperties.CACHE_SHARED_DEFAULT, "false");
properties.put(PersistenceUnitProperties.SESSION_NAME, "xxx");
//create the proper EntityManager for connect to database decided on runtime
EntityManager em = Persistence.createEntityManagerFactory("PU1", properties).createEntityManager();
//query or update DB
em.persist(entity);
em.createQuery(...).executeUpdate();
When deployed in a EJB container (e.g. WebLogic), with proper TransactionAttribute (e.g. TransactionAttributeType.REQUIRED), the container will take care of the transaction start/end/rollback.
Now, I am trying to migrate this application to Spring Boot.
The problem I encounter is that there is no transaction started even after I annotate the method with #Transactional(propagation = Propagation.REQUIRED).
The Spring application is packed as an executable JAR file and run with embadded Tomcat.
When I try to execute those update APIs, e.g. EntityManager.persist(..), EclipseLink always complains about:
javax.persistence.TransactionRequiredException: 'No transaction is currently active'
Sample code below:
//for data persistence
#Service
class DynamicServiceImpl implements DynamicService {
//attempt to start a transaction
#Transactional(propagation = Propagation.REQUIRED)
public void saveData(DbJndi, EntityA){
//this return false that no transaction started
TransactionSynchronizationManager.isActualTransactionActive();
//create an EntityManager based on the input DbJndi to dynamically
//determine which DB to save the data
EntityManager em = createEm(DbJndi);
//save the data
em.persist(EntityA);
}
}
//restful service
#RestController
class RestController{
#Autowired
DynamicService service;
#RequestMapping( value = "/saveRecord", method = RequestMethod.POST)
public #ResponseBody String saveRecord(){
//save data
service.saveData(...)
}
}
//startup application
#SpringBootApplication
class TestApp {
public static void main(String[] args) {
SpringApplication.run(TestApp.class, args);
}
}
persistence.xml
-------------------------------------------
&ltpersistence-unit name="PU1" transaction-type="JTA">
&ltproperties>
&lt!-- comment for spring to handle transaction??? -->
&lt!--property name="eclipselink.target-server" value="WebLogic_10"/ -->
&lt/properties>
&lt/persistence-unit>
-------------------------------------------
application.properties (just 3 lines of config)
-------------------------------------------
spring.jta.enabled=true
spring.jta.log-dir=spring-test # Transaction logs directory.
spring.jta.transaction-manager-id=spring-test
-------------------------------------------
My usage pattern does not follow most typical use cases (e.g. with known number of DBs - Spring + JPA + multiple persistence units: Injecting EntityManager).
Can anybody give me advice on how to solve this issue?
Is there anybody who has ever hit this situation that the DBs are not known in design time?
Thank you.
I finally got it work with:
Enable tomcat JNDI and create the datasource JNDI to each DS programmatically
Add transaction stuff
com.atomikos:transactions-eclipselink:3.9.3 (my project uses eclipselink instead of hibernate)
org.springframework.boot:spring-boot-starter-jta-atomikos
org.springframework:spring-tx
You have pretty much answered the question yourself: "When deployed in a EJB container (e.g. WebLogic), with proper TransactionAttribute (e.g. TransactionAttributeType.REQUIRED), the container will take care of the transaction start/end/rollback".
WebLogic is compliant with the Java Enterprise Edition specification which is probably why it worked before, but now you are using Tomcat (in embedded mode) which are NOT.
So you simply cannot do what you are trying to do.
This statement in your persistence.xml file:
<persistence-unit name="PU1" transaction-type="JTA">
requires an Enterprise Server (WebLogic, Glassfish, JBoss etc.)
With Tomcat you can only do this:
<persistence-unit name="PU1" transaction-type="RESOURCE_LOCAL">
And you need to handle transactions by your self:
myEntityManager.getTransaction.begin();
... //Do your transaction stuff
myEntityManager.getTransaction().commit();

IllegalStateException while using UserTransaction (Java EE)

I am trying to make my first Java Enterprise Application and use UserTransactions.
Therefore I use JNDI Lookup with java:comp/UserTransaction to get my UserTransaction Object.
public void myMethod(MyEntity e) throws ApplicationException {
try {
this.ut = getUserTransaction();
this.ut.begin();
this.myStatefulBean.myBusinessMethod(e);
} catch ...
When I start my Transaction with .begin() and try to invoke any method in my stateful Bean (which works properly before starting a UserTransaction) I get an EJBTransactionRolledbackException which leads me to the following error:
java.lang.IllegalStateException: cannot add non-XA Resource to global JTS transaction
The Bean I am using is annotated with #DataSourceDefinition having className = "org.apache.derby.jdbc.ClientXADataSource" thus there is imo no non-XA Resource.
What am I doing wrong?
I am using openjpa 2.2.1, Java EE Version 6
Solved the problem by myself. I used in my DataSourceDefinition name = "java:global/jdbc/testDB" as name, but in my persistence.xml the DataSource name was defined as <jta-data-source>testDB</jta-data-source>
This seems to work in CMTs but not in a UserTransaction. Correcting the entry in persistence.xml to <jta-data-source>java:global/jdbc/testDB</jta-data-source> fixed the problem.

Connect to a running JBoss AS7 instance for test purposes

I already have a integration-test phase, when I ran the selenium tests. I also want to run some unit tests in this phase, because the app is too much complex and have a lot of dependencies between his modules (a hell), so, after a week fighting against OpenEJB and Arquillian, I believe that this would be easier.
The thing is: how do I made it work?
I have the instance already running, if I instantiate an InitialContext and try to lookup some bean, I got an exception telling me that I have not set the java.naming.initial.factory, and I don't know what to put in there.
I'm also complaining about the annotated beans.
Suppose a Bean like this:
#Stateless
public class ABeanImpl implements ABean {
#EJB
private BBean;
}
Will the container automatically get right the BBean?
Thanks in advance
How to connect to JBoss 7.1 remote JNDI:
Here is the code snippet that I use for JBoss 7.1:
Properties props = new Properties();
String JBOSS_CONTEXT = "org.jboss.naming.remote.client.InitialContextFactory";
props.put("jboss.naming.client.ejb.context", true);
props.put(Context.INITIAL_CONTEXT_FACTORY, JBOSS_CONTEXT);
props.put(Context.PROVIDER_URL, "remote://localhost:4447");
props.put(Context.SECURITY_PRINCIPAL, "jboss");
props.put(Context.SECURITY_CREDENTIALS, "jboss123");
InitialContext ctx = new InitialContext(props);
Resolution of ambiguous ejb references:
According to JBoss EJB 3 reference, if at any level of your EJB environment (EJB/EAR/Server) are duplicates in used interfaces, exception will be thrown during resolution of injected beans.
Based on above, if you have got a reference to EJB bean which interface:
has two implementations in your EJB module (JAR/WAR) - exception will be thrown
has two implementations in your application (other EJB JAR's in same EAR) - exception will be thrown
has two implementations, one in module with bean ABeanImpl, second somewhere else - implemetation from current module is used.

JTA controlled transactions in JBoss AS7 using EclipseLink, Transaction is required

Environment
Application server: JBoss AS7 (7.1.1 Final)
JPA implementation: EclipseLink (2.4.1)
OS: Windows 7 DB: PostgreSQL 8.4
Update 2, solved
The problem was that i instantiated the AccountService class instead of injecting it using #EJB. After fixing that EntityManager was inected correctly in the service and a transaction was available when doing em.persist(account);
Update
I made a minimal project that shows my problems. Posted to Github:
https://github.com/gotling/jboss-eclipselink-problem
I have two problems that are probably related and due to me not understanding the use of EJB's correct.
I can not get EnityManager to be injected in AccountService.java in persistance JAR, resulting in NullPointerException.
If sending EntityManager in constructor to AccountService no tranasaction is found when doing em.persist.
Project structure
EJB
lib/persistanceunit.jar
web-service.war
Problem
I'm trying to get JBoss to manage transactions in my Java EE service. Problem is that EclipseLink does not seem to pick up the transaction managed by JBoss when trying to persist an entity.
I have followed the guide https://community.jboss.org/wiki/HowToUseEclipseLinkWithAS7 (Alternative 1 and Alternative 2 Step 4) on how to configure JBoss with EclipseLink.
Setup
WAR
Entity manager is injected like this in web-service.war:
#WebService(....)
public class NotificationConsumerImpl implements NotificationConsumer {
#PersistenceContext(unitName="foo")
EntityManager em;
public void notify(Notify notify) {
AccountService accountService = new AccountService(em);
accountService.create(notify);
}
}
There is actually a controller class between the class above and the service class, where transformation of the Account object is done, removed it to shorten code.
Persistance Unit
Entity is created like this
AccountService.java in persistanceunit.jar
#Stateless
public class AccountService {
private EntityManager em;
public AccountService(EntityManager em) {
this.em = em;
}
public void create(Account account) {
em.persist(account);
}
}
Stack trace
When calling a WS that should persist the Account entity I get an exception on em.persist(account);
...
Caused by: javax.persistence.TransactionRequiredException: JBAS011469: Transaction is required to perform this operation (either use a transaction or extended persistence context)
at org.jboss.as.jpa.container.AbstractEntityManager.transactionIsRequired(AbstractEntityManager.java:692) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.as.jpa.container.AbstractEntityManager.persist(AbstractEntityManager.java:562) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
at se.magos.service.AccountService.create(AccountService.java:50) [persistenceunit-0.0.1-SNAPSHOT.jar:]
Questions
I've enabled Trace logging. Should not id.au.ringerc.as7.eclipselinkpersistence be visible in the log?
Is it somehow possible to get the EntityManager injected inside the service class inside the persistanceunit.jar?
In which JBoss / EclipseLink version should this wor out of the box?
You should annotate the bean with #TransactionManagement(TransactionManagementType.CONTAINER) and the create method with #TransactionAttribute(TransactionAttributeType.REQUIRED).
The first annotation is required in order to let the application server know that transactions are managed by the container, the latter to let the method start a transaction, if there is no current one, as soon as it is invoked.
The problem was that AccountService class was instantiated instead of injected using #EJB annotation. After fixing that EntityManager was injected correctly in the service and a transaction was available when doing em.persist(account);
Before
#WebService(....)
public class NotificationConsumerImpl implements NotificationConsumer {
#PersistenceContext(unitName="foo")
EntityManager em;
public void notify(Notify notify) {
AccountService accountService = new AccountService(em);
accountService.create(notify);
}
}
After
#WebService(....)
public class NotificationConsumerImpl implements NotificationConsumer {
#PersistenceContext(unitName="foo")
EntityManager em;
#EJB
AccountService accountService;
public void notify(Notify notify) {
accountService.create(notify);
}
}