I would like to write a junit test for my stateless ejb + jpa demo code. I think it is actually not a junit test, it is an integration test.
I have a stateless ejb with an injected EntityManager and PostgreSQL database server is used. I use CDI (Spring is not used in my project) and EclipseLink with a persistent.xml file. My application will be executed on GlassFish server.
I would like to write a test which checks the full logic: calls a method on my example stateless ejb and persist data into a in-memory database. I want to start the in-memory database with my tests and stop it when my test class was executed.
ejb class:
#Stateless
public class PropertyServiceImpl implements PropertyService {
#PersistenceContext(name = "anything-jndi-em")
private EntityManager em;
public String getStringValue(final String key) {
Property property = em.createNamedQuery("Property.findByKey", Property.class)
.setParameter("key", key)
.getSingleResult();
return property.getValue();
}
}
enitity class:
#Entity
#Table(name = "APPLICATION_SETTING")
#NamedQueries({
#NamedQuery(name = "Property.findByKey", query = "select a from Property a where a.key = :key and a.status = 1")
})
public class Property
{
#Id
#SequenceGenerator(name = "APPLICATION_SETTING_SEQ", sequenceName = "APPLICATION_SETTING_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "APPLICATION_SETTING_SEQ")
#Column(name = "ID", unique = true, nullable = false)
private Long id;
#Column(name = "KEY", length = 200, nullable = false)
private String key;
...
}
If I am correct I need to follow the next steps:
create a new persistent.xml file with the proper jdbc connection parameters which will connect to the in-memory dadabase and put it under the /test/Resources/META-INF folder
add some pom dependencies for in-memory database (ex.: hsqldb) and embedded ejb container
create a simple PropertyServiceImplTest.java class
configure somehow that the /test/Resources/META-INF/persistent.xml file will be user by my test class
initialize the embedded ejb container and start the in-memory database
execute my juni test method:
#Test
public void testGetStringValue() {
PropertyService service = new PropertyServiceImpl();
assertNotNull(service.getStringValue("abc"));
}
Could you please help my to write a proper test java class for this scenario?
I highly recommend Arquillian. I use it with gradle on Wildfly 8, 9 and 10. Once setup properly, which can be a bit arduous, it works wonders.
You need only annotate your JUnit test like so:
#RunWith(Arquillian.class)
public class MRSInjectionServiceTests extends ...
And then provide a deployment archive which I do via JBoss ShrinkWrap:
#Deployment
public static WebArchive createDeployment() {
return ShrinkWrap.create(ZipImporter.class, "MRSInjectionServiceTests.war").importFrom(new File(ROOT_WAR_DEPLOYMENT_LOCATION)).as(WebArchive.class);
}
Then you can run these integration tests from maven or gradle. Arquillian will run your App server container (Wildfly, GLassfish, etcetera) based upon your configuration and will run the JUnit tests as a system test with your entire system running.
It is very nice. Well worth the effort.
In your actual test case boot up the javax.ejb.embeddable.EJBContainer. After that use its javax.naming.Context to lookup your stateless bean. The you can use your bean like you are used to and assert its behavior. Keep in mind that an embeddable container impl only has to support a subset (ejb lite) of functionality compared to a full blown ejb container. Here you find a pretty neat example.
Code snippet:
JBContainer ejbContainer = EJBContainer.createEJBContainer();
Context ctx = ejbContainer.getContext();
PropertyService service = (PropertyService) ctx.lookup("java:global/classes/PropertyServiceImpl");
assertNotNull(service.getStringValue("abc"));
I want to share with you my solution. According to your help I had a look at the Arquillian documentation and finally I was able to create a proper integration test.
My test uses GlassFish embedded EE container with HSQL in-memory database.
test java class:
#RunWith(Arquillian.class)
public class PropertyServiceImplTest {
#EJB
private PropertyService propertyService;
#Deployment
public static JavaArchive createTestArchive() {
return ShrinkWrap.create(JavaArchive.class, "test.jar").
.addPackage(Property.class.getPackage())
.addPackage(PropertyService.class.getPackage())
//.addPackage(PropertyServiceImpl.class.getPackage())
addAsResource("META-INF/persistence.xml");
}
#Test
public void testGetStringValue() {
assertNotNull(propertyService);
Property property = new Property();
property.setKey("aaa");
property.setValue("5");
propertyService.setStringValue(property);
assertEquals(propertyService.getStringValue("aaa"), "5");
}
}
persistence.xml
Valid values for target-database: eclipselink doc
<persistence-unit name="example" transaction-type="JTA">
<jta-data-source>jdbc/my-ds</jta-data-source>
<class>a.b.domain.Property</class>
<properties>
<property name="eclipselink.target-database" value="HSQL"/>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.logging.level" value="ALL"/>
</properties>
</persistence-unit>
arquillian.xml
How to eliminate the crazy "Potential problem found" warning message? DatatypeFactory properties has to be set.
WARNING: Potential problem found: The configured data type factory
'class org.dbunit.dataset.datatype.DefaultDataTypeFactory' might cause problems with the current database
'HSQL Database Engine' (e.g. some datatypes may not be supported properly). In rare cases you might see this
message because the list of supported database products is incomplete (list=[derby]). If so please request a
java-class update via the forums.If you are using your own IDataTypeFactory extending DefaultDataTypeFactory,
ensure that you override getValidDbProducts() to specify the supported database products.
DBUnit specific settings: jboss documentation
DataType factories: dbunit documentation
<engine>
<property name="deploymentExportPath">target/arquillian</property>
</engine>
<container default="true" qualifier="glassfish">
<configuration>
<property name="resourcesXml">myproject/src/test/resources/glassfish-resources.xml</property>
</configuration>
</container>
<extension qualifier="persistence">
<property name="defaultDataSource">jdbc/my-ds</property>
</extension>
<extension qualifier="persistence-dbunit">
<property name="datatypeFactory">org.dbunit.ext.hsqldb.HsqldbDataTypeFactory</property>
</extension>
glassfish-resources.xml
<resources>
<jdbc-connection-pool name="jdbc/my-pool"
res-type="javax.sql.DataSource"
datasource-classname="org.hsqldb.jdbc.JDBCDataSource">
<property name="PortNumber" value="9001" />
<property name="serverName" value="localhost" />
<property name="URL" value="jdbc:hsqldb:mem:arquillian" />
<property name="user" value="sa" />
<property name="password" value="" />
</jdbc-connection-pool>
<jdbc-resource jndi-name="jdbc/my-ds" pool-name="jdbc/my-pool" />
</resources>
Project structure:
src/test/java/a.b.PropertyServiceImplTest.java
src/test/resources/META-INF/persistence.xml
src/test/resources/arquillian.xml
src/test/resources/glassfish-resources.xml
I am so disappointed after I spent 3-4 days with arquillian.
I read documentation about this testing framework and I have created a nice environment with it. There were created beautiful xml files with placeholders for prod and test environments and pom files are done. Everything works fine with my simple ejb and entity java classes.
Today I have been started working on my real java 8 application. After a while something had happened because my tests have failed. When I removed lambda expression from my code then my tests worked fine again.
So when I use lambda expression then the injected ejb is always null:
#EJB
private ConfigurationService configurationService;
The last release of GlassFish Managed 3.1 Container is 1.0.0.CR4, release date: 2013-04-29. It is quite old :(
Arquillian GlassFish module is totally useless :(
I had that problem too, but you can fix it using Payara's embedded server.
<dependency>
<groupId>fish.payara.extras</groupId>
<artifactId>payara-embedded-all</artifactId>
<version>4.1.1.162</version>
<scope>test</scope>
</dependency>
Related
I can persist new data, but I cannot do updates. There are no errors, just no transactions committing the changes. I'm assuming this has something to do with the way that I've set up transactions. I'm trying a bunch of relatively new (to me) set of technologies. Below are the details.
I'm using the following tools/technologies:
Wildfly 8 and Java 7 (which is what my hosting service uses)
Annotations, with minimal XML being the goal
Struts 2.3 (using the convention plugin)
Spring 3.2
Hibernate 4.3
JTA (with container managed transactions (CMT))
JPA 2 (with a Container Managed Persistence Context)
EJBs (I have a remote client app that runs htmlunit tests)
Three WAR files and one EJB JAR file deployed
SpringBeanAutowiringInterceptor to autowire the EJBs (could there be an error in here where transactions don't commit?)
beanRefContext.xml (required by SpringBeanAutowiringInterceptor)
<beans>
<bean
class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg value="classpath:campaignerContext.xml" />
</bean>
</beans>
campaignerContext.xml
<beans>
<context:component-scan base-package="..." />
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/CampaignerDS"/>
<tx:annotation-driven/>
<tx:jta-transaction-manager/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="campaigner" />
</bean>
<bean id="ehCacheManager" class="net.sf.ehcache.CacheManager" factory-method="create">
<constructor-arg type="java.net.URL" value="classpath:/campaigner_ehcache.xml"/>
</bean>
</beans>
persistence.xml
<persistence>
<persistence-unit name="campaigner" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>java:/jdbc/CampaignerDS</jta-data-source>
<class>....UserRegistration</class>
...
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<properties>
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
</properties>
</persistence-unit>
</persistence>
SecurityServiceBean.java
#EnableTransactionManagement
#TransactionManagement(value = TransactionManagementType.CONTAINER)
#TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
#Stateless
#Interceptors(SpringBeanAutowiringInterceptor.class)
#DeclareRoles("Security Admin")
public class SecurityServiceBean extends AbstractCampaignerServiceImpl implements
SecurityServiceLocal, SecurityServiceRemote
{
#Override
#PermitAll
#Transactional(propagation = Propagation.REQUIRES_NEW)
public UserRegistration confirmRegistration(
String confirmationCode) throws ApplicationException
{
UserRegistration userRegistration = this.userRegistrationDAO
.find(new UserRegistrationQuery(null, confirmationCode)).uniqueResult(); // Should be attached now
...
userRegistration.setConfirmationDate(new Date());
userRegistration.setState(State.CONFIRMED);
userRegistration = this.userRegistrationDAO.saveOrUpdate(userRegistration);
...
}
}
UserRegistrationDAO.java
#Override
public UserRegistration saveOrUpdate(
UserRegistration obj) throws DAOException
{
log.debug("[saveOrUpdate] isJoinedToTransaction? "
+ (this.em.isJoinedToTransaction() ? "Y " : "N"));
try
{
if (obj.getId() == null)
{
this.em.persist(obj);
log.debug("[saveOrUpdate] called persist()");
return obj;
}
else
{
UserRegistration attached = this.em.merge(obj);
log.debug("[saveOrUpdate] called merge()");
return attached;
}
}
catch (PersistenceException e)
{
throw new DAOException("[saveOrUpdate] obj=" + obj.toString() + ",msg=" + e.getMessage(), e);
}
}
Are there any settings in Wildfly's standalone.xml that you need to see or that I should be setting?
BTW, this is incredibly annoying and frustrating. This should be an easy one-time setup that I can do and then forget about as I move on to creating my website, which should be where most of my time is spent. The lack of comprehensive documentation anywhere is AMAZING. Right now, development has been halted until this is solved
/rant
UPDATES
I tried switching to an XA data source, because some sites claimed that was necessary, but that didn't work (didn't think so but had to try). Also tried configuring emf with dataSource instead of persistenceUnitName as some other sites have. No joy.
I tried replacing the transactionManager with JpaTransactionManager, but that just led to this exception: A JTA EntityManager cannot use getTransaction()
The answer, thanks to M. Deinum, is that I was using the wrong #Transactional. I should have been using javax.transaction.Transactional but was using the Spring one instead. Note that the correct one will look like "#Transactional(TxType.REQUIRES_NEW)" instead of "#Transactional(propagation = Propagation.REQUIRES_NEW)"
I use entity beans and some Stateless ejb that provide my HomeLocal and HomeRemote interface, where I inject persistenceContext and obtain EntityManager.
As new requirement (migration on Karaf) I have to get rid of all EJB.
My question is how can I replace this stateless ejb with simple DAO classes and inject or obtain Entity manager in these classes?
My JPA provider is hibernate.
I need some example, tutorials or any kind of help.
You could use the Apache Aries project:
Amusing you will be using blueprint, declare your bean and define a service (assuming you want to use services)
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://aries.apache.org/xmlns/jpa/v1.0.0"
xmlns:tx="http://aries.apache.org/xmlns/transactions/v1.0.0">
<bean id="jpaDemo" init-method="init" class="org.demo.osgi.datasource.jpa.JpaComponentImpl">
<jpa:context unitname="demo" property="entityManager"/>
<tx:transaction method="*" value="Required"/>
</bean>
<service ref="jpaDemo" interface="org.demo.osgi.datasource.jpa.JpaComponent"/>
</blueprint>
The JpaComponent can then use the injected entityManager (code in Scala, but i'm sure you'll get the idea)
trait JpaComponent {
}
class JpaComponentImpl extends JpaComponent {
val logger = org.slf4j.LoggerFactory.getLogger(classOf[JpaComponent])
#BeanProperty
var entityManager : EntityManager = _
def init = {
logger.info(s"em=${entityManager}")
}
}
Place a persistence.xml in your bundle (e.g, META-INF/persistence.xml). Sample below:
<persistence-unit name="demo" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/jbtravel)</jta-data-source>
<mapping-file>META-INF/airport.xml</mapping-file>
</persistence-unit>
You will need the following features:
jpa
hibernate
jndi
transaction
And the following bundles
mvn:org.apache.aries/org.apache.aries.util/1.0.1
mvn:org.apache.aries.jpa/org.apache.aries.jpa.api/1.0.1
mvn:org.apache.aries.jpa/org.apache.aries.jpa.container.context/1.0.1
Plus set the following OSGI meta-data
Meta-Persistence: META-INF/persistence.xml
Service-Component: *
See also https://github.com/rparree/osgi-demos/tree/master/datasource for the sample from above
I have a java ee application with a web application and ejb module. There is some tables I want to be populated automatically when deployed. I have the entities set up and the sql file with the queries to be executed.
I feel it may be something to do with the persistence.xml file but not sure what to include. So, how do I get my server(wildfly) to execute the sql queries on deploy, similar to the way that you can specify the persistence.xml to drop and create as the table generation strategy.
If it makes a difference, I am using postgres for my database provider, java ee 7 and wildfly 8.2.0.Final for my server.
The solution I was looking for was like this, it belongs in the persistence.xml properties section.
<property name="javax.persistence.sql-load-script-source" value="META-INF/sql/data.sql" />
Database Schema Creation This link is useful for such techniques.
You could write a class extends from ServletContextListener which calls your method from the contextInitialized() method. You attach the listener to your webapp in web.xml, e.g.
<listener>
<listener-class>com.packages.Listener</listener-class>
</listener>
ServletListener code:
package com.packages;
public class Listener implements javax.servlet.ServletContextListener {
#Override
public void contextInitialized(ServletContext context) {
...
}
}
You can use Spring JDBC DataSource initializer feature or Instead of configuring DataSourceInitializer, you can use spring’s custom element jdbc:initialize-database element where jdbcnamespace xmlns:jdbc is set to http://www.springframework.org/schema/jdbc. You just need to point attribute data-source to the DataSource bean and configure the scripts using the child element jdbc:script and location attribute. For example, we can achieve the same result using the below configuration:
<jdbc:initialize-database data-source="dataSource" enabled="true">
<jdbc:script location="classpath:db-schema.sql" />
<jdbc:script location="classpath:db-load-data.sql" />
</jdbc:initialize-database>
At the very least you could use a servlet ContextListener to populate the database upon context start.
http://docs.oracle.com/javaee/7/api/javax/servlet/ServletContextListener.html
I've done such a trick for prototype applications in the past; just make sure to check if data doesn't already exist to prevent populating the database with duplicate data upon redeployments.
A rough example:
#WebListener
public class MyContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce){
// create manually, inject, whatever you're using
EntityManager em = ...;
Number cnt = (Number) em.createQuery("select count(d) from Data d").getSingleResult();
if(cnt.intValue() == 0){
insertFixtureData(em);
}
}
public void contextDestroyed(ServletContextEvent sce){
}
private void insertFixtureData(EntityManager em){
// insert data
}
}
I am getting this error in my spring webapp (spring 3.1), and I don't know why.
org.springframework.web.util.NestedServletException: Handler
processing failed; nested exception is java.lang.NoClassDefFoundError:
mypackage/TestCache$AjcClosure1
(the $AjcClosure1 is weird)
If I comment the annotation #Cacheable in the class below the error is gone.
public class TestCache {
#Cacheable(value ="myCache")
public List<String> getDummyList(){
Logger l = Logger.getLogger(this.getClass());
l.error("calling getDummyList");
ArrayList<String> foo = new ArrayList<String>();
foo.add("foo");
foo.add("bar");
return foo;
}
}
My controller class (simplified):
#Controller
#RequestMapping("/mypage")
public class MyController {
#RequestMapping
public String index(ModelMap model, Locale locale) {
TestCache tc = new TestCache();
...
}
}
Application Context (only cache part):
<cache:annotation-driven mode="aspectj"/>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="classpath:ehcache.xml"/>
I tried proxy and aspectj mode (in proxy mode less error but the cache was doing nothing)
This web application was built initially with roo and use spring mvc and webflow. So there is quite a lot of xml in the applicationContext.xml or webmvc-config.xml (and I am not able to understand what some beans are doing).
I am running the wepapps in eclipse with m2e-wtp and the pom.xml is using the plug-in aspectj-maven-plugin (but no idea what it does)
It looks like the issue is related with aspectj, but I never used aspectJ.
If anyone spring/java/aspectj guru can explain me what is making this error and how I can make my cache working it would be awesome! (I could find only tutorial but no sample project using the cacheable annotation).
It seems that the problem comes from the fact that all the class$AjcClosure[n].class aren't published and the only way to do it is remove, the webapps, clean start and republish the webapp.
One problem (may not the one that causes the NoClassDefFoundError) is that you can use Spring Functions like #Cacheable only for Spring Beans. So if you create an class via new (and this class it not annotated by #Configurable) then this is a normal class and not a Spring bean. Therefore the annotation is ignored in proxy mode. -- May this will also result in this stange error in AspectJ mode, but I don't know.
I have an application using Java servlets/JSP's. There are multiple clients using my app, however each client has a separate database. All the databases have the same schema. I would like to determine which database connection to use at the time when a user logs into the system.
For example client A logs in, I determine that client A belongs to database C, grab the connection for database C and continue on my merry way.
I am using JPA with Hibernate as my JPA provider. Is it possible to do this using multiple persistence units and determining which unit to use at login time? Is there a better/preferred way to do this?
Edited to add:
I am using annotations and EJB's so the Persistence Context is being set in the EJB with #PersistenceContext(unitName = "blahblah"), can this be determined at login time? Can I change the unitName at runtime?
Thanks
1) Create several persistent units in your persistence.xml with different names.
2) Create necessary number of EntityManagerFactorys (1 per persistence-unit) and specify which persistence-unit should be used for concrete factory:
<bean id="authEntityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="SpringSecurityManager"/>
</bean>
3) Create necessary number of TransactionManager s:
<bean id="authTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="authEntityManagerFactory" />
</bean>
4) In your DAO's classes specify with which persistence-unit (and so with which EntityManagerFactory) you want to work:
public class AbstractAuthDao<T> {
#PersistenceContext (unitName = "SpringSecurityManager")
protected EntityManager em;
...
}
5) In your service-objects specify which TransactionManager should be used (this feature is supported only in Spring 3.0):
#Transactional (value = "authTransactionManager", readOnly = true)
public class UserServiceImpl implements UserService {
...
}
6) If you have OpenEntityManagerInViewFilter in your web.xml, then specify in its init-param name of necessary EntityManagerFactory (or create several filters with correspondent init-blocks):
<init-param>
<param-name>entityManagerFactoryBeanName</param-name>
<param-value>authEntityManagerFactory</param-value>
</init-param>