Jump to: navigation, search

Difference between revisions of "EclipseLink/Examples/JPA/JBoss Web Tutorial"

m (Download EclipseLink using SVN - developers only)
m (Replacing page with '=EclipseLink JPA Deployed on JBoss using Eclipse WTP=')
Line 1: Line 1:
==EclipseLink JPA Deployed on JBoss using Eclipse WTP==
+
=EclipseLink JPA Deployed on JBoss using Eclipse WTP=
 
+
If you want to get a small web application running quickly on JBoss use the services provided by the '''Web Tools Project''' plugin in the '''Eclipse IDE''' to take care of deployment details for you.
+
 
+
This basic example details how to use Eclipse to run/debug a minimum J2EE web application servlet using EclipseLink JPA as the persistence provider.  The goal of this example is to detail the minimum steps needed to run EclipseLink inside JBoss using the Eclipse IDE - at this point no presentation/controller layer such as JSF, Spring or Struts will be used beyond a basic HttpServlet so we can concentrate on the the integration layer JPA setup.
+
 
+
The DALI project was used to generate Entities from a schema with sequences already populated.
+
 
+
===Development Environment===
+
'''Hardware:''' Windows Vista SP1, HP Core2Quad, 2.4Ghz, 3Gb Ram
+
 
+
'''Software:''' [http://phoenix.eclipse.org/packages Eclipse IDE for Java EE 3.4 M5 Ganymede] (Feb 2008) with all 5 packages (DTP 1.6, EMF 2.4, GEF 3.4, WTP 3.0, XSD 2.4), Oracle 11g DB 11.1.0.6.0, Java JDK 1.5.0_11, JBoss 4.2.2
+
 
+
This example will run fine with Eclipse 3.3 and any DB that EclipseLink supports.
+
 
+
===Prerequisites===
+
*<font color="green">Install Eclipse</font>
+
**I installed a clean version of Eclipse Ganymede M5 with all of WTP 3.0
+
 
+
*<font color="green">Install a Database</font>
+
**In this example I am using Oracle 11g, the table schemas have already been created manually and all entity java classes have been generated using the Eclipse [http://wiki.eclipse.org/Dali DALI] tool.
+
 
+
*<font color="green">Install JBoss</font>
+
**See the following [http://www.jboss.org/jbossas/downloads/ jboss.org Application Server Downloads]
+
**Here I installed the 4.2.2 version to the following directory.
+
<pre>C:\opt\jboss422
+
Where
+
JBOSS_HOME=C:/opt/jboss422
+
</pre>
+
 
+
===JBoss Server Configuration Changes===
+
====JNDI JTA/non-JTA Server DataSource Setup====
+
*Copy $JBOSS_HOME\docs\examples\jca\oracle-*ds.xml to $JBOSS_HOME\server\default\deploy
+
*Edit oracle-ds.xml
+
*Enter the following into $JBOSS_HOME\server\default\deploy\oracle-ds.xml
+
<source lang="xml">
+
<datasources>
+
  <no-tx-datasource>
+
    <jndi-name>OracleDS</jndi-name>
+
<use-java-context>true</use-java-context>
+
    <connection-url>jdbc:oracle:thin:@localhost:1521:orcl</connection-url>
+
    <driver-class>oracle.jdbc.OracleDriver</driver-class>
+
    <user-name>username</user-name>
+
    <password>password</password>
+
    <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name>
+
      <metadata>
+
        <type-mapping>Oracle9i</type-mapping>
+
      </metadata>
+
  </no-tx-datasource>
+
</source>
+
 
+
*Edit oracle-xa-ds.xml
+
*Enter the following into $JBOSS_HOME\server\default\deploy\oracle-xa-ds.xml
+
<source lang="xml">
+
<datasources>
+
  <xa-datasource>
+
    <jndi-name>XAOracleDS</jndi-name>
+
    <use-java-context>true</use-java-context>
+
    <track-connection-by-tx>true</track-connection-by-tx>
+
<isSameRM-override-value>false</isSameRM-override-value>
+
    <xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>
+
    <xa-datasource-property name="URL">jdbc:oracle:thin:@localhost:1521:orcl</xa-datasource-property>
+
    <xa-datasource-property name="User">username</xa-datasource-property>
+
    <xa-datasource-property name="Password">password</xa-datasource-property>
+
    <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name>
+
    <no-tx-separate-pools/>
+
      <metadata>
+
        <type-mapping>Oracle9i</type-mapping>
+
      </metadata>
+
  </xa-datasource>
+
</source>
+
*Enter the following into $JBOSS_HOME\server\default\conf\login-config.xml
+
<source lang="xml">
+
<policy>
+
<application-policy name = "OracleDbRealm">
+
  <authentication>
+
      <login-module code = 
+
  "org.jboss.resource.security.ConfiguredIdentityLoginModule" flag = "required">
+
        <module-option name = "principal">sa</module-option>
+
        <module-option name = "userName">sa</module-option>
+
        <module-option name = "password"></module-option>
+
        <module-option name = "managedConnectionFactoryName">jboss.jca:service=LocalTxCM,name=OracleDS</module-option>
+
      </login-module>
+
  </authentication>
+
</application-policy>
+
</source>
+
 
+
====JNDI/JNP Port Conflict Workarounds====
+
You may get the following port 1099 conflict if you are also running an Oracle Database.
+
 
+
<pre>
+
14:56:41,597 ERROR [Naming] Could not start on port 1099
+
java.net.BindException: Address already in use: JVM_Bind
+
at java.net.PlainSocketImpl.socketBind(Native Method)
+
</pre>
+
 
+
Try changing the following jboss:service=Naming port to any available port, keep the RmiPort at 1098.  Use [netstat -a] to check free ports - in my case 1099 is taken by the 1521 orcl listener.
+
<pre>
+
  TCP    yourpc:1099      yourpc....com:1521  ESTABLISHED
+
</pre>
+
 
+
<JBOSS_HOME>\server\default\conf\jboss-service.xml|jboss-minimal.xml
+
 
+
<source lang="xml">
+
  <mbean code="org.jboss.naming.NamingService"
+
      name="jboss:service=Naming"
+
      xmbean-dd="resource:xmdesc/NamingService-xmbean.xml">
+
...
+
from
+
      <attribute name="Port">1199</attribute>
+
to
+
      <attribute name="Port">1099</attribute>
+
</source>
+
 
+
* Eclipse WTP Server configuration
+
Open the server configuration on the [servers] view and change [Server Properties/JNDI Port] to 1199
+
 
+
* <app>/JNDI.properties
+
You will also need to sync this port change in your jndi.properties file (mine is off my web application under src/ just above META-INF.
+
 
+
<pre>
+
from:
+
java.naming.provider.url=jnp://localhost:1099
+
to:
+
java.naming.provider.url=jnp://localhost:1199
+
</pre>
+
 
+
===Downloading EclipseLink Libraries===
+
====Download EclipseLink using HTTP - recommended====
+
*Proceed to the following URL and download the latest eclipselink.zip which contains everything you need.
+
**http://www.eclipse.org/eclipselink/downloads/index.php
+
***'''Click on the "EclipseLink 1.0.2 Installer Zip''' link which resolves to http://www.eclipse.org/downloads/download.php?file=/rt/eclipselink/releases/1.0.2/eclipselink-1.0.2.zip
+
*Expand the zip file and get the following 2 files
+
**eclipselink-1.0.2\eclipselink\jlib\eclipselink.jar
+
**eclipselink-1.0.2\eclipselink\jlib\jpa\javax.persistence_1.0.0.jar
+
 
+
====Download EclipseLink using Maven====
+
See the repository on http://www.eclipse.org/eclipselink/downloads/index.php
+
 
+
====Download EclipseLink using SVN - developers only====
+
*Get the following ''<font color="blue">eclipselink.jar</font>'' and ''<font color="blue">javax.persistence*.jar</font>'' from http://www.eclipselink.org ready for your EclipseLink shared library - ''(I am running rev 2.0.0.20090218-SNAPSHOT)''
+
**The following page details four different ways to either obtain the binary jars or download the source and build them yourself with an anon account.
+
**http://wiki.eclipse.org/EclipseLink/Source
+
 
+
===EclipseLink JAR location===
+
The eclipselink.jar should be placed off of ''$JBOSS_HOME/server/default/lib''
+
 
+
===JDBC JAR location===
+
Copy your jdbc driver jar to ''$JBOSS_HOME/server/default/lib''
+
 
+
===Create server in Eclipse===
+
Open the servers view
+
'''New | Server | JBoss | JBoss v4.2'''.
+
 
+
===Create J2EE application===
+
Check out the 3 example projects in the trunk '''(TBD)'' or create your own J2EE Enterprise Application as below.
+
'''File | new | project | J2EE | Enterprise Application Project '''
+
Select '''server''', use '''5.0''' Ear version
+
 
+
Create a new '''Web''' and an optional '''EJB''' project
+
 
+
Select ''generate deployment descriptor'' if you want to change the context-root
+
 
+
*Path changes
+
<pre>
+
<classpathentry combineaccessrules="false" kind="src" path="/eclipselink.core"/>
+
<classpathentry combineaccessrules="false" kind="src" path="/eclipselink.jpa"/>
+
</pre>
+
*After EAR project creation - reference eclipselink.core and eclipselink.jpa or include a reference to eclipselink.jar in your WAR project.
+
*If you don't reference the eclipselink.* projects then include a classpath reference to persistence.jar and an Oracle JDBC driver jar for your DB - You will need to put this JDBC driver jar in your JBoss ''/server/default/lib'' directory as well.
+
 
+
====@EJB Injection is not available to Servlets - use a JNDI lookup====
+
In JBoss the JEE @EJB annotation has no effect when trying to inject you session bean that holds the entitymanager.
+
<source lang="java">
+
  @EJB(beanName="ApplicationService") // No effect in JBoss
+
</source>
+
 
+
Use the following JNDI name and lookup in your Servlet where '''UnifiedJBossEAR''' is the name of your EAR project and '''ApplicationService''' is the name of your @Local @Stateless session bean.
+
 
+
<source lang="java">
+
public class FrontController extends HttpServlet implements Servlet {
+
  public static final String APPLICATION_SERVICE_JNDI_NAME = "UnifiedJBossEAR/ApplicationService/local";
+
  @EJB(beanName="ApplicationService") // No effect in JBoss
+
  public ApplicationServiceLocal applicationService;
+
 
+
 
+
  public ApplicationServiceLocal getApplicationService() {
+
    if(null == applicationService) {
+
      try {
+
        InitialContext ctx = new InitialContext();
+
        return (ApplicationServiceLocal) ctx.lookup(APPLICATION_SERVICE_JNDI_NAME);           
+
      } catch (Exception e) {
+
        e.printStackTrace();
+
        throw new RuntimeException("couldn't lookup DAO", e);
+
      }
+
    } else {
+
      return applicationService;
+
    }
+
  }
+
</source>
+
 
+
====Session Customizer====
+
*The client will require an implementation of SessionCustomizer that will set the lookupType on the JNDI connector to STRING_LOOKUP instead of Composite.
+
*Refer to the following [http://forums.oracle.com/forums/thread.jspa?messageID=3205242&tstart=0 post] for details on this issue with Catalina based containers.
+
*Refer to the following [http://bugs.eclipse.org/260383 260383 enhancement request] that will make this SessionCustomizer redundant by moving this functionality as standard procedure on the server platform.
+
 
+
 
+
<source lang="java">
+
import javax.naming.Context;
+
import javax.naming.InitialContext;
+
import javax.sql.DataSource;
+
 
+
import org.eclipse.persistence.config.SessionCustomizer;
+
import org.eclipse.persistence.sessions.server.ServerSession;
+
import org.eclipse.persistence.sessions.JNDIConnector;
+
import org.eclipse.persistence.sessions.Session;
+
 
+
/**
+
* See
+
* http://wiki.eclipse.org/Customizing_the_EclipseLink_Application_(ELUG)
+
* Use for clients that would like to use a JTA SE pu instead of a RESOURCE_LOCAL SE pu.
+
*/
+
public class JPAEclipseLinkSessionCustomizer implements SessionCustomizer {
+
  public static final String JNDI_DATASOURCE_NAME = "java:/XAOracleDS";
+
  /**
+
  * Get a dataSource connection and set it on the session with lookupType=STRING_LOOKUP
+
  */
+
  public void customize(Session session) throws Exception {
+
    JNDIConnector connector = null;
+
    // Initialize session customizer
+
    DataSource dataSource = null;
+
      try {
+
        Context context = new InitialContext();
+
        if (null == context) {
+
          throw new Exception("Context is null");
+
        }
+
        // Create a new org.jboss.resource.adapter.jdbc.WrapperDataSource
+
        //connector = new JNDIConnector(context, JNDI_DATASOURCE_NAME);
+
        connector = (JNDIConnector)session.getLogin().getConnector(); // possible CCE
+
        // Lookup this new dataSource
+
        dataSource = (DataSource) context.lookup(JNDI_DATASOURCE_NAME);
+
      } catch (Exception e) {
+
        e.printStackTrace();
+
      }
+
    connector.setDataSource(dataSource);
+
    // Change from COMPOSITE_NAME_LOOKUP to STRING_LOOKUP
+
    // Note: if both jta and non-jta elements exist this will only change the first one - and may still result in the COMPOSITE_NAME_LOOKUP being set
+
    // Make sure only jta-data-source is in persistence.xml with no non-jta-data-source property set
+
    connector.setLookupType(JNDIConnector.STRING_LOOKUP);
+
 
+
    // if you are specifying both JTA and non-JTA in your persistence.xml then set both connectors to be safe
+
    JNDIConnector writeConnector = (JNDIConnector) session.getLogin().getConnector();
+
    writeConnector.setLookupType(JNDIConnector.STRING_LOOKUP);
+
    JNDIConnector readConnector = (JNDIConnector) ((DatabaseLogin)((ServerSession)session).getReadConnectionPool().getLogin()).getConnector();
+
    readConnector.setLookupType(JNDIConnector.STRING_LOOKUP);
+
 
+
    // Set the new connection on the session
+
    session.getLogin().setConnector(connector);
+
  }
+
}
+
</source>
+
 
+
====Persistence.xml====
+
*Put persistence.xml in ''yourProjectEJB/ejbModule/META-INF'' with a reference to your SessionCustomizer or...
+
*If using a separate J2SE project for your business logic, put persistence.xml in ''yourProjectSE/src/META-INF/'' and export the SE jar to yourProjectWeb/WebContent/WEB-INF/lib/yourProjectSE.jar
+
<source lang="xml">
+
<persistence version="1.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_1_0.xsd">
+
  <persistence-unit name="unified" transaction-type="JTA">
+
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+
      <jta-data-source>java:/XAOracleDS</jta-data-source>
+
      <!-- non-jta-data-source>java:/OracleDS</non-jta-data-source-->
+
      <class>org.eclipse.persistence.example.unified.business.StatClass</class>
+
..other entities
+
      <properties>
+
        <!-- deprecated property name="eclipselink.server.platform.class.name" value="JBoss"/-->
+
        <property name="eclipselink.target-server" value="JBoss"/>
+
        <property name="eclipselink.weaving" value="false"/>
+
        <property name="eclipselink.session-name" value="default-session"/>           
+
        <property name="eclipselink.session.customizer" value="org.eclipse.persistence.example.unified.integration.JPAEclipseLinkSessionCustomizer"/>
+
        <property name="eclipselink.logging.level" value="FINEST"/>
+
        <property name="eclipselink.cache.size.default" value="500"/>
+
        <property name="eclipselink.cache.type.default" value="Full"/>
+
        <!--property name="eclipselink.orm.throw.exceptions" value="false"/-->
+
      </properties>     
+
    </persistence-unit>
+
</persistence>
+
</source>
+
 
+
*Note: the property '''server.platform.class.name''' has been deprecated - the '''target-server''' property should be used for EclipseLink release 1.0+
+
 
+
===Start Server===
+
*Steps: Select the EAR and [Run on Server].
+
*The first "Run on Server" may not start the server, in this case you "Start Server" and then "Run on Server".
+
 
+
===Publish EAR===
+
*Publishing to JBoss is very simple, once the server is setup you can just drop/remove an EAR in the deploy directory to deploy/undeploy an application.  Or use Eclipse to debug via the 5005 port if the server is managed through WTP.
+
*Eclipse WTP will take care of copying the EAR file to the live deploy directory when you either [re-publish] or modify any files while the server is running.
+
*You may also use any combination of running the JBoss server yourself in run or debug mode and using eclipse to publish EAR changes.
+
*Dynamic weaving is disabled for now because of [[http://jira.jboss.com/jira/browse/EJBTHREE-572 JIRA-572]] - Use [http://wiki.eclipse.org/EclipseLink/Examples/JPA/Migration/JBoss static weaving workaround] before deploying if required.
+
*Depending on your application you will see the following after running [start server]
+
**In your console window you will see one process both for the server and the deploy target.
+
<pre>
+
15:56:57,667 INFO  [Server] Starting JBoss (MX MicroKernel)...
+
15:56:57,668 INFO  [Server] Release ID: JBoss [Trinity] 4.2.2.GA (build: SVNTag=JBoss_4_2_2_GA date=200710221139)
+
15:57:08,630 INFO  [ConnectionFactoryBindingService] Bound ConnectionManager 'jboss.jca:service=DataSourceBinding,name=OracleDS' to JNDI name 'java:OracleDS'
+
15:57:08,634 INFO  [ConnectionFactoryBindingService] Bound ConnectionManager 'jboss.jca:service=DataSourceBinding,name=TXOracleDS' to JNDI name 'java:TXOracleDS'
+
15:57:08,690 INFO  [ConnectionFactoryBindingService] Bound ConnectionManager 'jboss.jca:service=DataSourceBinding,name=XAOracleDS' to JNDI name 'java:XAOracleDS'
+
15:57:08,806 INFO  [EARDeployer] Init J2EE application: file:/C:/opt/jboss422/server/default/deploy/unifiedEAR.ear
+
15:57:08,835 INFO  [TomcatDeployer] deploy, ctxPath=/unified, warUrl=.../tmp/deploy/tmp35385unifiedEAR.ear-contents/unifiedWeb-exp.war/
+
15:57:08,926 INFO  [EARDeployer] Started J2EE application: file:/C:/opt/jboss422/server/default/deploy/unifiedEAR.ear
+
15:57:09,026 INFO  [Server] JBoss (MX MicroKernel) [4.2.2.GA (build: SVNTag=JBoss_4_2_2_GA date=200710221139)] Started in 11s:350ms
+
</pre>
+
 
+
===Perform a JPQL query===
+
*At this time you can initialize your application in a browser - notice the use of the non-jta datasource
+
** Launch http://127.0.0.1:8080/unified/FrontController?action=init
+
** This url command gets an application managed EM factory via ApplicationService.getInstance().initialize()
+
<source lang="java">
+
    emf = Persistence.createEntityManagerFactory(puName);
+
</source>
+
*Console Output
+
<pre>
+
15:57:23,046 INFO  [STDOUT] [EL Finest]: 2008.04.14 15:57:23.031--ServerSession(28649942)--Thread(Thread[http-127.0.0.1-8080-2,5,jboss])--Begin predeploying Persistence Unit unifiedJBoss; state Initial; factoryCount 0
+
15:57:23,046 INFO  [STDOUT] [EL Finest]: 2008.04.14 15:57:23.046--ServerSession(28649942)--Thread(Thread[http-127.0.0.1-8080-2,5,jboss])--property=eclipselink.weaving; value=false
+
15:57:23,244 INFO  [STDOUT] [EL Config]: 2008.04.14 15:57:23.243--ServerSession(28649942)--Thread(Thread[http-127.0.0.1-8080-2,5,jboss])--The primary key column name for the mapping element [private org.eclipse.persistence.example.unified.business.StatClass org.eclipse.persistence.example.unified.business.StatInheritance.toClass] is being defaulted to: ID.
+
15:57:23,246 INFO  [STDOUT] [EL Finest]: 2008.04.14 15:57:23.246--ServerSession(28649942)--Thread(Thread[http-127.0.0.1-8080-2,5,jboss])--End predeploying Persistence Unit unifiedJBoss; state Predeployed; factoryCount 0</pre>
+
*Exercise your application in a browser by requesting a JPQL query
+
** Launch <pre>http://127.0.0.1:8080/unified/FrontController?action=query&jpql=select%20object(e)%20from%20StatLabel%20e%20where%20e.id<100</pre>
+
*Console Output
+
<pre>
+
15:57:41,175 INFO  [STDOUT] [EL Config]: 2008.04.14 15:57:41.175--ServerSession(28649942)--Connection(12593356)--Thread(Thread[http-127.0.0.1-8080-2,5,jboss])--Connected: jdbc:oracle:thin:@localhost:1521:orcl
+
User: username
+
Database: Oracle  Version: Oracle Database 11g Release 11.1.0.0.0 - Production
+
Driver: Oracle JDBC driver  Version: 11.1.0.0.0-Beta5
+
15:57:41,391 INFO  [STDOUT] [EL Finest]: 2008.04.14 15:57:41.391--UnitOfWork(5316732)--Thread(Thread[http-127.0.0.1-8080-2,5,jboss])--Execute query ReadAllQuery(org.eclipse.persistence.example.unified.business.StatLabel)
+
15:57:41,393 INFO  [STDOUT] [EL Fine]  : 2008.04.14 15:57:41.393--ServerSession(28649942)--Connection(32240107)--Thread(Thread[http-127.0.0.1-8080-2,5,jboss])--SELECT ID, DATE_STAMP FROM STAT_LABEL
+
15:57:41,582 INFO  [STDOUT] [EL Finest]: 2008.04.14 15:57:41.581--UnitOfWork(5316732)--Thread(Thread[http-127.0.0.1-8080-2,5,jboss])--Register the existing object org.eclipse.persistence.example.unified.business.StatLabel@10ae2bf</pre>
+
*Browser Output
+
[[Image:Eclipselink_example_jpa_jboss_web_jpql_action_cap.jpg]]
+
 
+
==References==
+
*See [[EclipseLink/UserGuide/Developing_JPA_Projects_%28ELUG%29|Developing JPA Projects]] in the EclipseLink User's Guide.
+
*See [http://wiki.eclipse.org/EclipseLink/Examples/JPA/Migration/JBoss migration procedure on how to run EclipseLink as JPA provider on the JBoss container.]
+

Revision as of 17:17, 24 March 2009

EclipseLink JPA Deployed on JBoss using Eclipse WTP