Multiple persistence units in Wildfly? - jpa

Is it possible to have two persistence units in a Wildfly (9.0.2) application?
I get "WFLYJPA0061: Persistence unitName was not specified and there are 2 persistence unit definitions in application deployment deployment "jasper-web.war". Either change the application deployment to have only one persistence unit definition or specify the unitName for each reference to a persistence unit."
I have unitName specified in the #PeristenceContext annotations. I read somewhere I could disable
<!--
<subsystem xmlns="urn:jboss:domain:jpa:1.1">
<jpa default-datasource="" default-extended-persistence-inheritance="DEEP"/>
</subsystem>
-->
in standalone.xml. This removed the error message, but also disabled injection of entityManagers (null pointer referencing them in code)
I have tried to split the persistence units over two different ejb-jars, each with their own persistence.xml, but as they're still included in the same war, Wildfly still complains.
The the two persistence units are used with hibernate, one with a postgresql database and one with a ucanaccess driver for ms access. They both work separately.

here an example of what works in our wildfly 8.x/9.x ejb app:
First of all define all the classes for each persistence-unit in the persistence.xml, unlisted classes can be turned off to disable autodiscovery.
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="primary">
<jta-data-source>java:jboss/datasources/primary_ds</jta-data-source>
<class>whatever.primary.model.SomeEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties> ... </properties>
</persistence-unit>
<persistence-unit name="secondary">
<jta-data-source>java:jboss/datasources/secondary_ds</jta-data-source>
<class>whatever.secondary.model.AnotherEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties> ... </properties>
</persistence-unit>
</persistence>
If you use JBoss Developer Studio ignore the warning (it is only an eclipse flaw):
Multiple persistence units defined - only the first persistence unit will be recognized
Resources.java
package whatever.util;
import javax.annotation.Resource;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.sql.DataSource;
public class Resources {
#Produces
#PersistenceContext(unitName = "primary")
private EntityManager emPrimary;
#Produces
#PersistenceContext(unitName = "secondary")
private EntityManager emSecondary;
#Produces
#Resource(lookup = "java:jboss/datasources/primary_ds")
private DataSource dsPrimary;
#Produces
#Resource(lookup = "java:jboss/datasources/secondary_ds")
private DataSource dsSecodnary;
}
Dao primary example
package whatever.dao;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
#Stateless
public class DaoPrimaryExample {
#PersistenceContext(unitName = "primary")
private EntityManager em;
public void create(SomeEntity entity) {
em.persist(entity);
}
}
Dao secondary example
package whatever.dao;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
#Stateless
public class DaoSecondaryExample {
#PersistenceContext(unitName = "secondary")
private EntityManager em;
public void create(AnotherEntity entity) {
em.persist(entity);
}
}
IMPORTANT: If you plan to use booth persistence units in same transaction than XA datasources should be used.

Adding this option for a persitence unit in the persistence.xml fixed the issue for me:
<property name="wildfly.jpa.default-unit" value="true"/>

As John Ament pointed out the error message actually indicates an injection point without unitName (that I had forgotten about in my source...) As soon as I got rid of that, everything worked as it should. I also got a bit confused googling this problem, when I actually found some old issues in jboss AS where this actually seems to have been a problem, once.

Related

Glassfish 4.1.1 / EAR / java.lang.IllegalStateException: Unable to retrieve EntityManagerFactory for unitName XYZ

I have a huge problem deploying an EAR project on my Payara/Glassfish 4.1.1 server, which I can't solve since days.
Hope somebody can help me!
My setup ->
I have one EJB/JPA eclipse project "CommonPersistanceAndService" that contains my JPA entities, my Databaseproducer, and some basic serviceclasses.
I have a webproject that uses this EJB/JPA project so I know that my databaseproducer works correctly:
#Singleton
#Startup
public class DatenbankProducer implements Serializable{
private static final long serialVersionUID = 2605227297803488033L;
#PersistenceContext(unitName="XYZdb")
EntityManager emXYZProd;
#PersistenceContext(unitName="XYZtest")
EntityManager emXYZTest;
#Inject ApplicationConfig appConfig;
#Inject Logger logger;
public XYZDatenbankProducer() { }
#Produces
#XYZDatenbank
public EntityManager getEntityManager(){
if(appConfig.isBetriebsmodusTest())
return emXYZTest;
return emXYZProd;
}
#PostConstruct
public void initDBConnection(){
Query q = getEntityManager().createNativeQuery("select * from zconnectiontest");
q.getSingleResult();
logger.info("=== Connection to Database established");
}
}
Now using this same EJB/JPA project in an EAR project together with a project "Batchjobs" that only has a serviceclass with a scheduler
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" version="6">
<display-name>Batchjobs-EAR</display-name>
<module>
<ejb>Batchjobs.jar</ejb>
</module>
<module>
<ejb>CommonPersistanceAndService.jar</ejb>
</module>
</application>
I also copied all jar file dependencies from my EJB/JPA project to the EAR/lib directory. The EAR deploys correctly, but when the scheduler calls the service I get the following error:
Caused by: java.lang.IllegalStateException: Unable to retrieve EntityManagerFactory for unitName XYZtest
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.init(EntityManagerWrapper.java:138)
at com.sun.enterprise.container.common.impl.EntityManagerWrapper._getDelegate(EntityManagerWrapper.java:171)
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.createNativeQuery(EntityManagerWrapper.java:557)
at com.isg.kis.application.XYZDatenbankProducer.initDBConnection(XYZDatenbankProducer.java:48)
... 122 more
When I debug the programm the object for emXYZTest, a EntityManagerWrapper, doesn't get an EntityManagerFactory injected!? When I do the same in my Webproject there is an EntityManagerFactory.
So the question is - why does the EntityManagerFactory not get injected in the EAR deployment!?
Nothing I tried so far worked. Any ideas what causes this problem?
thanks in advance
Thomas

In JBoss/WildFly should I enable JTA on data source to use with JPA?

In JBoss/WildFly, when configuring a data source, there is a JTA option, which is disabled by default:
<datasource jta="false" jndi-name="java:/wt/testds" pool-name="testds" enabled="true" use-ccm="false">
...
</datasource>
Now I want to associate this data source with JPA using JTA transaction type:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="test" transaction-type="JTA">
<jta-data-source>java:/wt/testds</jta-data-source>
</persistence-unit>
</persistence>
Do I also need to enable JTA on the data source?
Yes, of course you need to enable JTA on a datasource if you want to have jta transactions!
Your XML/JBoss/Wildfly config file will look like this:
<datasource jta="true" ...
In our webapp persistence-unit, the datasource looks like this:
<jta-data-source>java:jboss/datasources/CoreDS</jta-data-source>
The transaction-type="JTA" isn't necessary, at least not in my setup (Wildfly 8.1).
In your Java code you can go like this to use transactions:
#TransactionManagement(TransactionManagementType.CONTAINER) // class level
public class ...
...
#PersistenceContext(unitName = "CoreJPA")
EntityManager em;
#Resource
private EJBContext ejbContext;
...
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) // method level
public void doSomething(...)
And if you need to rollback, you do this:
try {
...
} catch (Throwable t) {
log.error("Exception in create work order: " + t.getMessage());
ejbContext.setRollbackOnly();
throw t;
}
There are a lot of resources about this that can be found using Google.
I've just experienced a problem related to this issue.
I was running a container managed transaction involving approximately 20,000 inserts into a MySQL database.
The transaction failed randomly, sometimes after around 3,500 inserts, other times after around 6,000 inserts, etc.
After investigation I found that the JTA option on the WildFly datasource definition was set to false.
Changing this setting to true fixed the problem, so I would agree with #user3472929 that JTA should be set to true in the datasource definition unless you have some specific reason not to.
I think you should use jta. And if you set jta to false in the container configuration file, jta will be disabled for JPA, so the transaction-type for JPA will be "RESOURCE_LOCAL", which has some nasty side effect. By the way, jta is true in the container configuration file by default.

In java EE 6: When could I change properties on EntityManager?

I want to use proxy authentication to an Oracle Express database in a simple web app with java EE 6 on Glassfish. Eclipselink 2.3.0 doc here says:
If a JEE and JTA managed EntityManager is used, specifying a proxy user/password can be more difficult, as the EntityManager and JDBC connection is not under the applications control. The persistence unit properties can still be specified on the EntityManager. As long as this is done before the EntityManager has established a database connection, this will still work.
My code is as below, but I guess the database connection is already established when the #Postconstruct init() method is called, since the last property is not changed from default true to false.
Also, I get ORA-00942: table or view does not exist from the save() method. The user pool in the jdbc connection pool defined in glassfish-resources.xml has not acces to the tables, as has proxy user user_a.
#Stateless
public class Boundary {
#PersistenceContext EntityManager em;
#PostConstruct
private void init() {
em.setProperty("eclipselink.oracle.proxy-type", OracleConnection.PROXYTYPE_USER_NAME);
em.setProperty(OracleConnection.PROXY_USER_NAME, "pool[user_a]");
em.setProperty(OracleConnection.PROXY_USER_PASSWORD, "pool");
em.setProperty(OracleConnection.PROXY_ROLES, "pool_user");
em.setProperty("eclipselink.jdbc.exclusive-connection.mode", "Always");
em.setProperty("eclipselink.jdbc.exclusive-connection.is-lazy", "false");
}
public void save() {
em.merge(new AnEntity());
}
}
I have not much experience here, but it would be really useful if proxy authentication could be made that simple, so I spent some time trying.
In a JavaEE managed context, is it possible to set properties on an EntityManager before it gets connected?
My persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" 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">
<persistence-unit name="ProxyUserPU" transaction-type="JTA">
<jta-data-source>SecondTry</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<properties>
<property name="eclipselink.target-database" value="Oracle"/>
<property name="eclipselink.jdbc.exclusive-connection.is-lazy" value="true"/>
</properties>
</persistence-unit>
</persistence>
I don't think PostConstruct is the correct place for this.
A new EntityManager is bound to the persistence context on every transaction boundary, so you need to set these property at the start of every transactional SessionBean method. You could probably also use SessionEvents in EclipseLink to configure the properties.
If you properties are fixed, you could also put them in your persistence.xml.
See,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/Auditing#Use_Oracle_proxy_authentication_to_allow_a_shared_connection_pool_and_a_user_context

Spring batch with Annotation

I am new to Spring batch, looking for some example developed Spring batch with Annotation concept.
This link (click) talks about Spring batch, but not Spring batch with annotation concept. As discussed in given link documentation is not clear. I am using latest Spring framework. I want to avoid xml configuration.
Is Spring batch is very good tool for batch processing? or Is there any better tools available for batch processing instead of Spring batch?
Is there any limitations in Spring batch?
Spring batch supports only limited functionality which you can configure using annotations. Mainly these are listener callbacks, like #BeforeStep or #AfterChunk. Using these annotations provides you a choice either to implement corresponding interfaces or to use annotated methods. Annotated bean has to be injected into job, step or chunk (reader, processor, writer, retry-policy, skip-policy or listeners) in XML configuration, which you cannot avoid.
Have you look at http://www.joshlong.com/jl/blogPost/java_configuration_with_spring_batch.html
If you defined all the necessary "bean" object, in the main method, you can just get them in the application context.
ApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
job = (Job) ctx.getBean("SOME JOB");
jobLauncher = (JobLauncher) ctx.getBean("jobLauncher");
jobLauncher.run(job, jobParams);
I've worked with Spring Batch for about 2.5 years and I will suggest you to use xml files for configuration of your jobs not annotations. Of course you can use annotations for so many configurations, like step and job definition, job launcher and job repository definition, tasklet and listeners, deciders and so many other necessary components. But unfortunately I've found it so hard to connect components together specially when you are forced to use partitioners. You can gain profits with annotations in case of debugging but it will be much more easier to track your job's flow in case of xml cause you have all your configurations in one xml file (and maybe more files if you like to make it more readable).
I used following technologies for this example :
Spring batch 3.0.5.RELEASE,
JDK 1.7,
Eclipse Mars Release (4.5.0),
Maven 3.3.3,
Springframework 4.0.5.ReLEASE.
Step 1: Create simple POJO, Employee.java
public class Employee {
private String name;
private String empId;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmpId() {
return empId;
}
public void setEmpId(String empId) {
this.empId = empId;
}
#Override
public String toString() {
return "Employee [name=" + name + ", empId=" + empId + "]";
}
}
Step 2: Create java class, ClassReader.java
package com.batch.main;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.batch.beans.Employee;
#Component("classReader")
public class ClassReader implements ItemReader<Employee> {
#Override
public Employee read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
Employee emp=new Employee();
//Set values in Employee object
emp.setEmpId("123456");
emp.setName("Manohar");
System.out.println("Inside ClassReader..." + emp);
return emp;
}
}
Step 3: Create java class, ClassProcessor.java
package com.batch.main;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.batch.beans.Employee;
#Component("classProcesser")
public class ClassProcessor implements ItemProcessor<Employee, Employee>{
#Override
public Employee process(Employee emp) throws Exception {
System.out.println("Inside ClassProcessor..." + emp);
return emp;
}
}
Step 4: Create java class, ClassWriter.java
package com.batch.main;
import java.util.List;
import org.springframework.batch.item.ItemWriter;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.batch.beans.Employee;
#Component("classWriter")
public class ClassWriter implements ItemWriter<Employee> {
#Override
public void write(List<? extends Employee> arg0) throws Exception {
System.out.println("Inside ClassWriter..." + arg0);
}
}
Step 5: Create context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd">
<bean id="transactionManager"
class="org.springframework.batch.support.transaction.
ResourcelessTransactionMana ger" />
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.
MapJobRepositoryFactoryBean">
<property name="transactionManager" ref="transactionManager" />
</bean>
<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
</beans>
Step 6: Create job.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:batch="http://www.springframework.org/schema/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:crypt="http://springcryptoutils.com/schema/crypt"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://springcryptoutils.com/schema/crypt http://springcryptoutils.com/schema/crypt.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd">
<import resource="/context.xml" />
<context:component-scan base-package="com.batch" />
<batch:job id="loadJob" xmlns="http://www.springframework.org/schema/batch">
<batch:step id="step1" >
<batch:tasklet>
<batch:chunk reader="classReader" writer="classWriter"
processor="classProcesser" commit-interval="1" />
</batch:tasklet>
</batch:step>
</batch:job>
<!-- <bean id="classReader" class="com.batch.main.ClassReader" >
</bean>
<bean id="classWriter" class="com.batch.main.ClassWriter" ></bean>
<bean id="classProcesser" class="com.batch.main.ClassProcessor" > </bean>-->
Step 7: Finally create Main.java
package com.batch.main;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
#Configuration
#ImportResource({"classpath:/com/spring/job/job.xml"})//load configuration file from classpath
public class Main {
public static void main(String[] args) throws JobExecutionAlreadyRunningException,
JobRestartException,
JobInstanceAlreadyCompleteException, JobParametersInvalidException {
#SuppressWarnings("resource")
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(Main.class);
context.refresh();
//load jobLauncher details from context.xml file
JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");
//load Job details from job.xml file
Job job = (Job) context.getBean("loadJob");
//run job
JobExecution execution = jobLauncher.run(job, new JobParameters());
System.out.println("Exit Status : " + execution.getStatus());
}
}
Now Run above program as Java application, you will see the output on console.
Please refer http://manohark.com/simple-spring-batch-example-using-annotations/ for complete details.
Please take a look at my tutorial together with the github repo, maybe it will be useful for you.
Spring Batch as any other tool has its own limitation but still is quite flexible. I'm using it in a real project with 1500 different jobs running and I think it's pretty good and covers a lot of use cases in the batch processing applications.
I faced the same problem when I was reading about Spring batch Annotations. The best place where you can read about Spring annotations is the reference documentation. The concepts are the same for batch, whether or not XML or Java is used.
I would suggest following these steps:
Study about the batch concepts
Try to make simple batch applications (reading from a database and saving to CSV)
Once confortable with basic concepts, study from books like Spring Batch Pro.
If you encounter a problem, look online for code and then cross-reference that with the aforementioned Spring documentation.
I have a experience of creating and maintaining the spring batch applications from scratch. Annotations based configuration is preferred over XML based configuration for many reasons.
Spring batch is well suited for processing records or transactions in bulk because of the performance and the features it provides.
Most of the readers and writers are available built-in which will reduce your work. For example reading and writing into CSV files, reading and writing into the database. And it will give multiple task executors, partitioners for multi threading and parallel processing. You will also be able to trace the issues or monitor the application using different JobExecution and StepExecution listeners and methods which are there to be performed after and before read or write operation in batch. Like AfterRead, BeforeRead, AfterStep etc.
Performance-wise too good for read, process and write operations.
Go for it. Thanks for the question.

How to get Container Managed Transactions (CMT) working with EJB 3.1, Hibernate 3.6, JPA 2.0 , JBoss and MySQL

I was trying to get CMT working with JPA EntityManagers and EJBs, but came up with the error below. (stack trance truncated):
Caused by: java.lang.RuntimeException: **Could not resolve #EJB reference: [EJB Reference: beanInterface 'com.mydomain.beans.TestBean2', beanName 'testBean2', mappedName 'null', lookupName 'null',** owning unit 'AbstractVFSDeploymentContext#2008455195{vfs:///Users/willtardy/Documents/workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_6.0_Runtime_Server1300532851414/deploy/mydomainWeb.war}']
for environment entry: env/com.mydomain.action.SearchAction/testBean in unit AbstractVFSDeploymentContext#2008455195{vfs:///Users/willtardy/Documents/workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_6.0_Runtime_Server1300532851414/deploy/mydomainWeb.war}
My classes:
Servlet that access the Session Bean:
public class SearchActionExample extends Action {
#EJB
private static TestBeanServiceInterface testBean;
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
testBean.addSource("TEST SOURCE NAME", 88, 99);
Service service = testBean.findService("HBA", "MEL");
return mapping.findForward("success");
}
}
Remote interface:
#Remote
public interface TestBeanServiceInterface {
// Source is my own custom entity
void addSource(String sourceName, int newthreadsleeptime, int maxactivehttpclients);
// Service is my own Custom entity
Service findService(String departureAirportCode, String arrivalAirportCode);
}
Stateless Session Bean definition:
#Stateless
public class TestBeanService implements TestBeanServiceInterface {
#PersistenceContext(unitName="mydomainJPA")
private EntityManager em;
public void addSource(String sourceName, int newthreadsleeptime, int maxactivehttpclients) {
Source source = new Source();
source.setName(sourceName);
source.setNewThreadSleepTime(newthreadsleeptime);
source.setMaxActiveHttpClients(maxactivehttpclients);
em.persist(source);
}
public Service findService(String departureAirportCode, String arrivalAirportCode) {
String queryString = "from Service where departureairportcode = '" + departureAirportCode + "' and arrivalairportcode = '" + arrivalAirportCode + "'";
Service service = (Service)em.createQuery(queryString).getSingleResult();
return service;
}
}
file persistnce.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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="mydomainJPA" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/MySqlDS</jta-data-source>
<class>com.mydomain.entities.Service</class>
<class>com.mydomain.entities.Source</class>
<properties>
<property name="hibernate.query.factory_class" value="org.hibernate.hql.classic.ClassicQueryTranslatorFactory"/>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
<property name="hibernate.current_session_context_class" value="jta"/>
</properties>
</persistence-unit>
When it says "cannot resolve reference", where else can I define the beans? ejb-jar.xml isn't needed with EJB3. Is there some other config file that I'm missing?
UPDATE:
I have updated the code segments above so that the bean is created as the interface type instead, as per the answer below.
Do the EJBs need to be defined or mapped in web.xml?
Assuming that a reference is required in web.xml, I have added an EJB ref to web.xml (see below), but now I'm receiving a new error (see below)
lines added to web.xml:
<ejb-ref>
<ejb-ref-name>ejb/TestBeanEJBname</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<home>com.mydomain.action.TestBeanService</home>
<remote>com.mydomain.action.TestBeanServiceInterface</remote>
</ejb-ref>
new error message now being received:
12:11:00,980 ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController] Error installing to PostClassLoader: name=vfs:///Users/willtardy/Documents/workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_6.0_Runtime_Server1300532851414/deploy/purejetWeb.war state=ClassLoader mode=Manual requiredState=PostClassLoader: org.jboss.deployers.spi.DeploymentException: java.lang.IllegalStateException: Failed to find ContainerDependencyMetaData for interface: au.com.purejet.action.TestBeanServiceInterface
Caused by: java.lang.IllegalStateException: Failed to find ContainerDependencyMetaData for interface: com.mydomain.action.TestBeanServiceInterface
at org.jboss.deployment.MappedReferenceMetaDataResolverDeployer.resolveEjbInterface(MappedReferenceMetaDataResolverDeployer.java:1255) [:6.0.0.Final]
at org.jboss.deployment.MappedReferenceMetaDataResolverDeployer.resolveEjbRefs(MappedReferenceMetaDataResolverDeployer.java:1099) [:6.0.0.Final]
at org.jboss.deployment.MappedReferenceMetaDataResolverDeployer.resolve(MappedReferenceMetaDataResolverDeployer.java:807) [:6.0.0.Final]
at org.jboss.deployment.MappedReferenceMetaDataResolverDeployer.internalDeploy(MappedReferenceMetaDataResolverDeployer.java:181) [:6.0.0.Final]
... 39 more
Update:
"Local" interface works just fine (i.e. doesn't have to be Remote)
I got it to work by deploying within an Enterprise Application Project within Eclipse. No references to beans are required within web.xml, ejb-jar.xml, or application.xml.
Contents of application.xml within EAR being deployed to Jboss:
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" id="Application_ID" version="6">
<display-name>myprojects</display-name>
<module>
<web>
<web-uri>myproject.war</web-uri>
<context-root>myproject</context-root>
</web>
</module>
<module>
<ejb>myprojectsEJB.jar</ejb>
</module>
</application>
SessionBean class:
#Stateless
#Local(SessionBeanLocal.class)
public class SessionBean implements SessionBeanLocal {
#PersistenceContext(unitName="JPAtestProjectPersistenceUnit")
private EntityManager em;
Interface class:
#Local
public interface SessionBeanLocal {
TestTiger addTestTiger(String testTigerName);
MOST IMPORTANT change that got things working: inside the class that holds the session been local variable, a setting was required for the container (JBoss AS) to create the bean:
#EJB()
private TestBean3Local beanVariable;
public void setBeanVariable(TestBean3Local beanVariable) {
System.out.println("=====\n\nSET BEAN VARIABE SETTER WAS CALLED. (BY CONTAINER?) \n\n=======");
this.beanVariable = beanVariable;
}
You need to inject the remote interface and not the Bean
public class SearchActionExample extends Action {
#EJB
private static TestBean2Remote testBean;
public class SearchActionExample extends Action {
#EJB
private static TestBeanServiceInterface testBean;
Don't do injections into static field, injections are instance members and happen when object is created, whereas static field is a class member. This is most probably the cause for exception.
I have obtained a working solution:
#Local interface works just fine (i.e. doesn't have to be Remote)
No references to beans are required within web.xml, ejb-jar.xml, application.xml, or any jboss config file.
I got it to work by deploying within an "Enterprise Application Project" (EAP) within Eclipse. This project contains "Deployment Assembly" that contains the .jar containing JPA Entity Classes, and another .jar that contains other business-logic classes. The EAP has those two projects PLUS the EJB project and the "Dynamic Web Project" (creates a .war) for a total of 4 projects on it's build path. Jboss AS tool within Eclipse publishes/deploys the EAP to the Jboss server. Contents of application.xml within EAP being deployed to Jboss:
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" id="Application_ID" version="6">
<display-name>myprojects</display-name>
<module>
<web>
<web-uri>myproject.war</web-uri>
<context-root>myproject</context-root>
</web>
</module>
<module>
<ejb>myprojectsEJB.jar</ejb>
</module>
</application>
Local Interface class:
package com.myproject.beans;
import javax.ejb.Local;
import com.myproject.entities.Lion;
#Local
public interface SessionBeanLocal {
Lion addLion(String lionName);
}
SessionBean class:
package com.myproject.beans;
import javax.ejb.Local;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import com.myproject.Lion;
#Stateless
#Local(SessionBeanLocal.class)
public class SessionBean implements SessionBeanLocal {
#PersistenceContext(unitName="PersistenceUnitNameInPersistenceXML")
private EntityManager em;
public Lion addLion(String lionName) {
Lion lion = new Lion(lionName);
em.persist(lion);
}
MOST IMPORTANT change that got things working: inside the class that holds the session been variable (e.g. inside a Struts action servlet, but could be any servlet), a setter method was required for the container (JBoss AS) to create the bean:
#EJB()
private SessionBeanLocal bean;
public void setBean(SessionBeanLocal bean) {
System.out.println("setBean setter was called by container (e.g. Jboss)");
this.bean = bean;
}
public exampleStrutsServletMethod(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
PrintWriter out = response.getWriter();
Lion lion = bean.addLion("Simba"); // this will persist the Lion within the persistence-context (and auto-generate an Id), and the container will manage when it's flushed to the database
out.print("<html>LION ID = " + lion.getLionId() + "<html>");
}
file persistnce.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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="PersistenceUnitNameInPersistenceXML" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/MySqlDS</jta-data-source>
<properties>
</properties>
</persistence-unit>
mysql-dx.xml (in directory jboss-server-dir/server/default/deploy):
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>MySqlDS</jndi-name>
<connection-url>jdbc:mysql://localhost:3306/myProjectDatabase</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>username</user-name>
<password>mypassword</password>
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>
NOTE: Classes do not need to be defined in persistence.xml (via "< class >") if "Persistence Class Management" is set to "Discover annotated classes automatically" in "Java Persistence" project property panel for the Eclipse JPA project (i.e. the project that containers your JPA 2.0 Entity classes and persistence.xml)
NOTE: This solution is based on: EJB3.1, Eclipse Helios SR2, Hibernate 3.6, JPA 2.0, JBoss 6, MySQL 5.5.10
NOTE: Regarding "Container Managed Transactions" (CMT). The Hibernate manual references them, and indicates that you need to set persistence.xml properties such as "hibernate.transaction.factory_class" to value of: "org.hibernate.transaction.CMTTransactionFactory". This is not the case if you are using JPA EntityManager instead of native hibernate. I didn't required any such custom CMT properties in persistence.xml. This is where Hibernate gets confusing, between the two ways to implement it (i.e. SessionFactory vs EntityManager). Please feel free to comment more on this part of my solution as I'm still just wrapping my head around it! Will