Posts Tagged ‘JPA’
09
Mar

After setting up a data source in your AppServer, e.g. for WebLogic Server, you want to use it in your application with JPA.

Basically there are three ways to connect to a db with JPA:

  • JDBC data source with JTA transactions (not supported by a Servlet-Container like Tomcat)
  • JDBC data source with self-managed transactions, i.e. transaction-type=”RESOURCE_LOCAL”
  • direct JDBC connection

The first and second are well discussed in the www. So we give an example on the second with provider Hibernate:

<persistence-unit name="PU_ResourceLocal_WithDS" transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>

  <!-- the JNDI name as specified in your AppServer -->
  <non-jta-data-source>jdbc/mh_orcl</non-jta-data-source>

  <properties>
    <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
    <property name="hibernate.max_fetch_depth" value="5" />
  </properties>
</persistence-unit>

For Tomcat 6 and EclipseLink this is well explained in http://wiki.eclipse.org/EclipseLink/Examples/JPA/Tomcat_Web_Tutorial.

, , , , , ,

09
Mar

To use a data source in WLS (e.g. to benefit from the built-in connection pooling, XA transactions etc.) you have to configure it from the WLS admin console.
Prior to this post, we installed the Oracle DB and Oracle WLS.

  1. start the admin console, e.g. http://localhost:7001/console
  2. in the left tree menu named ‘Domain Structure’ go to ‘Services’ -> ‘JDBC’ -> ‘Data Sources’
  3. click ‘New’ and enter your data:
    • name:     mh_JDBC_DS_orcl (just a unique name in WLS to identify your ds)
    • JNDI Name:     jdbc/mh_orcl
    • Database Type:    Oracle
    • Database Driver:     oracle.jdbc.xa.client.OracleXADataSource (use the XA version if your App participates in global/distributed transactions)
    • Database Name:     orcl (the name you specified in the db installation)
    • Host Name:     localhost (or your IP where the db listens)
    • Port:     1521 (port where the db listens)
    • Database User Name:  mh (user to login)
    • Password:     <pwd>
    • under ‘Targets’: check the server, e.g. ‘AdminServer’ where you want to use this ds
  4. You can explore your settings also on the file system:
    • C:\Oracle\Middleware\user_projects\domains\mh_domain\config\jdbc\mh_JDBC_DS_orcl-5723-jdbc.xml, and an entry to this file in
    • C:\Oracle\Middleware\user_projects\domains\mh_domain\config\config.xml

Alternatively, if you need to make multiple installations/configurations, there is the possibility to use the silent installation and WLST (WebLogic Scripting Tool).

Now you can call the ds in your application via JNDI or if you use JPA you need to specify the JNDI name in persistence.xml.

, , , ,

14
Feb

When you need to retrieve the plain Connection from JPA, unfortunately, there is no JPA standard way (unless you get a configured datasource with JNDI). This is needed when you use libraries or legacy applications which use JDBC instead of JPA.

Hibernate 3.x and JPA 1.0

With Hibernate you can get the org.hibernate.session. In pre Hibernate 4.o there was the connection() method which now is removed.

EntityManager em = ...;
Session session = (Session) em.getDelegate();
Connection conn = session.connection();

Hibernate 3.x and JPA 2.0

EntityManager em = ...;
Connection conn = em.unwrap(Session.class).connection();

Hibernate 4.x and JPA 2.0

Session session = em.unwrap(Session.class);
SessionFactoryImplementor sfi = (SessionFactoryImplementor) session.getSessionFactory();
ConnectionProvider cp = sfi.getConnectionProvider();
Connection conn = cp.getConnection();

JNDI-Lookup

If you are running inside a container, you could also perform a JNDI lookup on the configured DataSource.

, , , ,

24
Jan

Meanwhile annotations are preferrred to XML configuration in Java EE. One still can use XML to override annotations. The same is true in JPA: one configures the object-relational mapping via entity annotations. I was in the situtation to make some mappings of the JPA entities and the database tables configurable, when deploying in different environments.

In my situation I needed to switch the ID generation strategy, auto vs. sequence, in all 30+ entites back and forth (building up different database structures for different environments in the same project is a bad thing, but happens in real life…). Either I could change the annotations in each entity file, like I did a few times, or:

  1. Specify with annotations the standard behavior.
  2. Override the annotations with orm.xml.

I will give an example to my situation. In the entity I specified the sequence generation via annotations:

@Id
@SequenceGenerator(name="TABLENAME_ID_GENERATOR", sequenceName="SEQUENCENAME_IN_DB")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="TABLENAME_ID_GENERATOR")
@Column(name="TABLE_ID")
private Long id;

If you start overwriting a property, all annotations on the given property are ignored. So you also have to specify e.g. the @Column-configuration in the xml:
So to overwrite this with strategy=GenerationType.AUTO:

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings  version="1.0"
  xmlns="http://java.sun.com/xml/ns/persistence/orm"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemalocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd">

  <description>Override Annotations...</description>

  <!-- Set the default to FIELD-access, if you like -->
  <persistence-unit-metadata>
    <persistence-unit-defaults>
      <access>FIELD</access>
    </persistence-unit-defaults>
  </persistence-unit-metadata>

  <entity>
    <attributes>
      <id name="id">
        <column name="TABLE_ID" unique="true" nullable="false" precision="20"/>
        <generated-value strategy="AUTO" />
      </id>
    </attributes>
  </entity>

</entity-mappings>

You are done if you use the default location for this xml, beside the persistence.xml: META-INF/orm.xml.

If you want another name or another location you can register this file in the persistence unit in the persistence.xml:
We rename the file idGenerationStrategyAUTO.xml and then have to specify the mapping-file:

<?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="bigDevPersistenceUnit_DEV" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>

    <mapping-file>META-INF/idGenerationStrategyAUTO.xml</mapping-file>

    <properties>
      ...
    </properties>
  </persistence-unit>
</persistence>

Finally, in the sense of “continous delivery” you could declare different persistence units, e.g. bigDevPersistenceUnit_DEV, bigDevPersistenceUnit_PROD, and create the right entity manager factory by using the detected environment DEV, PROD, see here.

, , ,

18
Jan

This should work theoretically with every Servlet 2.5 / JSP 2.1 container, but tested with Tomcat 6 only…

Intro

If your customer forces you to run your WebApps in an old Servlet 2.5 / JSP 2.1 container ;-) , but you want to kick off using new JEE 6 stuff, then heres how you get started:

JSF 2.0

JSF 2.0 just needs Servlet 2.5 / JSP 2.1 container (JSF 2.1+ needs alredy Servlet 3.0). Download the reference implementation Mojarra or Apache MyFaces and put the two jars into the WEB-INF/lib:

jsf-api.jar
jsf-impl.jar

EL 2.2 or JBoss EL

Have you ever wished to pass an argument to your JSF-actions in your view? Like

<h:commandButton value="edit" action="#{bean.edit(user)}" />

with backing bean method

public void edit(User user) {...}

JBoss EL 2.0.1.GA

This is possible with JBoss EL implementation, see http://docs.jboss.org/seam/2.0.1.GA/reference/en/html/elenhancements.html. Add to your pom:

<dependency>
  <groupId>org.jboss.el</groupId>
  <artifactId>jboss-el</artifactId>
  <version>2.0.1.GA</version>
  <exclusions>
    <exclusion>
      <groupId>javax.el</groupId>
      <artifactId>el-api</artifactId>
    </exclusion>
  </exclusions>
</dependency>

and to your web.xml

<context-param>
  <param-name>com.sun.faces.expressionFactory</param-name>
  <param-value>org.jboss.el.ExpressionFactoryImpl</param-value>
</context-param>

EL 2.2

Or use EL 2.2, which is a component of the JSP 2.2 spec. You need to put the two EL JARs into the WEB-INF/lib: el-api-2.2.0.jar, el-impl-2.2.0.jar. Add to your web.xml:

<context-param>
  <param-name>com.sun.faces.expressionFactory</param-name>
  <param-value>com.sun.el.ExpressionFactoryImpl</param-value>
</context-param>

Note: If you also use CDI with Weld, this ends up in an exception:
LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;"
One way out is to replace in the apache-tomcat/lib the el-api.jar with el-api-2.2.jar and el-impl-2.2.jar and put in your pom.xml:

<dependency>
  <groupId>javax.el</groupId>
  <artifactId>el-api</artifactId>
  <version>1.0</version>
  <scope>provided</scope>
</dependency>

If you cannot change the server itself then stick to JBoss EL.

CDI

If you want to use CDI managed beans (@Named) instead of JSF managed beans (@ManagedBean) in a plain Servlet container, then you can use the reference implementation Weld: http://seamframework.org/Weld,
CDI is the new JEE 6-standardized way for managing beans: it’s more robust, and the same as in an EJB context. Furthermore you can use a conversation scope. I still like the JSF view scope, so maybe drop JSF management totally, or mix it.
For setup refer to http://docs.jboss.org/weld/reference/1.0.0/en-US/html/environments.html. There it is explained:

Just drop into WEB-INF/lib

weld-servlet.jar

and add to your web.xml:

org.jboss.weld.environment.servlet.Listener
<listener>
  <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>
<resource-env-ref>
  <description>Object factory for the CDI Bean Manager</description>
  <resource-env-ref-name>BeanManager</resource-env-ref-name>
  <resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resource-env-ref-type>
</resource-env-ref>

Bean Validation

“Declare once, validate anywhere!” is the advertisement for Bean validation: Don’t put your validation in the views, DAOs/DTOs, etc., but put your validation only at one place:
your beans (although in real life in the database remain ranges, constraints, etc., so some redundancy remains…). If you have different pages with input data to the same data, then this is a big advantage for maintenance: change at one place.

public class Bean {
@Size(min=1)
private String name;
}

Again use the RI from Hibernate https://validator.hibernate.org/ and drop it to WEB-INF/lib:

hibernate-validator-4.0.2.GA.jar
all JARs in the lib directory of the downloaded zip file.

Note: JSF 2.0 directly supports Bean Validation. In JSF 1.2 you could use RichFaces 3.3.3.

JPA 2.0

Some drawbacks without a real AppServer is that

  • manage your transactions by yourself with EntityTransaction (no JTA transactions).
  • direct resource handling, i.e. use the persistence factory EntityManagerFactory to obtain an EnitityManager (no injections possible, because of the lack of EJBs), also don’t forget to close your EntityManager…

Get a JPA provider, e.g. Hibernate and EclipseLink. For EclipseLink, see http://wiki.eclipse.org/EclipseLink/Examples/JPA/Tomcat_Web_Tutorial. For Hibernate just get the zip from http://www.hibernate.org/ and follow the good documentation.

You need to setup your persistence.xml and make some provider and database specific configurations.

, , , , , , , , , , , , , ,

18
Jan

To install and run a HSQLDB in server mode proceed as follows:

  • Download the release from http://hsqldb.org.
  • Unzip it, e.g. C:\hsqldb-2.2.5\.
  • The HSQLDB-jar is then found at C:\hsqldb-2.2.5\hsqldb\lib\hsqldb.jar.
  • Create a batch file for starting the HSQLDB in server mode, e.g. C:\hsqldb-2.2.5\hsqldb\bin\hsqldbServer_start.bat with content:

@java -classpath ../lib/hsqldb.jar org.hsqldb.server.Server --database.0 file:../data/MH --dbname.0 MH_DB

  • This creates and starts a db with name MH_DB with db-files in the directory C:\hsqldb-2.2.5\hsqldb\data. You can start several databases at once, replace the batch file content with:

@java -classpath ../lib/hsqldb.jar org.hsqldb.server.Server --database.0 file:../data/MH1 --dbname.0 MH_DB1 --database.1 file:../data/MH2 --dbname.1 MH_DB2

  • You then can reach the HSQLDB via JDBC / JPA

driver: 'org.hsqldb.jdbcDriver'
url: 'jdbc:hsqldb:hsql://localhost/MH_DB'
user: 'SA'
pwd: ''

  • When using JPA with Hibernate then you can specify a dialect in persistence.xml (for other JPA providers, check the documentation):

<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />

, , , , , ,