Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
EclipseLink/Examples/Distributed
< EclipseLink | Examples
Contents
- 1 Distributed Enterprise App using JEE6 API - JPA 2.0, JSF 2.0, JAX-RS 1.1 and EJB 3.1
- 2 Requirements
- 3 Analysis
- 4 Use Cases
- 5 Design
- 6 Data Model
- 7 Implementation
- 8 Testing
- 8.1 GlassFish 3.1 Server Logs
- 8.2 TC1: Remote Session Bean Lookup on GlassFish 3.1 from SE Client on Same JVM
- 8.3 TC2:Remote Session Bean Lookup on GlassFish 3.1 from SE Client on Different JVM - Local Machine
- 8.4 TC3:Remote Session Bean Lookup on GlassFish 3.1 from SE Client on Different JVM - Remote Machine
- 9 Results
- 10 Status
- 11 TODO
- 12 References
Distributed Enterprise App using JEE6 API - JPA 2.0, JSF 2.0, JAX-RS 1.1 and EJB 3.1
- This tutorial describes the analysis, design, implementation and deployment of a distributed JEE6 application that makes use of the EJB 3.1, JPA 2.0, JSF 2.0, Servlet 3.0 and JAX-RS API implemented as part of the Oracle GlassFish Server 3.1 distribution. The Java IDE used for this tutorial is the tightly integrated SUN NetBeans 7.0 release that will be in beta until April 2011 but we are also able to use Eclipse Helios 3.6 as well.
- Why distributed? We need to investigate the concurrent behavior and exception handling of a near-real-world hammering of a server based JPA application from multiple clients. Specifically I am interested in how we implement 2-phase commit, handle OptimisticLockExceptions and design for a mix of transaction types involving REQUIRES(default)|REQUIRES_NEW|NOT_REQUIRED. We may also integrate different isolation levels.
- We will be concentrating on how to leverage the features of JPA 2.0 that are implemented by EclipseLink 2.x. These features should include con
Technology Summary
- Normally we do not decide on what APIs will be in use before we analyse the requirements. However, here is the list of technologies we are using - as we finalize the implementation.
- JPA 2.0 : All database interaction will be on the main server via a container managed @PersistenceContext on EJB session beans. The clients will modify detached entities and return them to the server for merging/persistence.
- JTA : We will continue to use container managed transactions via the dependency injected proxy so we do not have to manage transaction events ourselves
- EJB 3.1 : We will be using @Stateless @Remote beans but may be using @Singleton and/or container-managed JTA persistence units in the WAR for @Local beans
- JSF 2.0 : We will use the existing @ManagedBean and new .XHTML controller/view separation pattern
- JAX-RS 1.1 :
- JMS :
- JNI :(possible optimization via C++ using either IA32/64, SSE or even CUDA) - where the Java client is just the wrapper around the computation engine.
- We will not be using an L2 cache such as Coherence, ehCache or Terracotta at this point - we will be communicating using standard EJB beans such as session or message-driven beans.
- We will be presenting 2 identical implementations of this project
Problem
- Instead of the usual Employee demo or even the simple entity/jsp format of previous JPA tutorials - we will attempt at providing a usefull distributed java application that could be deployed to a live server that would be hosted outside our firewall.
- Our problem is how can we help prove the Collatz conjecture (or all integer paths lead to 1).
- The Collatz conjecture or (3n + 1) problem has not been proven yet. There have been attempts at verifying collatz up to 2^61 - however, massive amounts of scalar processing power is required to do this because the problem is non-linear and therefore must be brute force simulated even with optimizations.
- The algorithm is as follows for the set of positive integers to infinity.
odd numbers are transformed by 3n + 1 even numbers are divided by 2
- If you think in base 2, we see that for odd numbers we shift bits to the left, add the number to the result and set bit 0. For even numbers we shift bits to the right. We therefore have a simplified algorithm as follows.
odd: next binary = number << 1 + number + 1 even: next binary = number >> 1
- 'Observation 1: the maximum value remains at or around 2x the number of bits in the start number - at least so far in my own simulations up to 640 billion.
- We stop iteration and record the max path and max value when the sequence enters the 4-2-1 loop after the first 1 is reached. This sequence must be simulated for all positive integers up to the limit of the software being used. Fortunately, in Java (and .NET3) we can use BigInteger which supports unlimited length integers - as we would quickly overflow using a 64 bit long as soon as we started iterating numbers over 32 bits.
- Observation 2: I have determined - via a week of simulation distributed among 16 different machines in parallel - that we will need native computation.
Requirements
R1: Local Client Access
R2: Remote RMI Client Access Inside Firewall
R3: Remote WebService Client Access Outside Firewall
- We will implement this by generating a WSDL from the JPA model
R4: Browser based Interface to Client Data on Server
- We will implement this using JSF 2.0 to start.
R5: Separation of components and concerns
- The data model in the form of a JPA persistence context will be in a separate JAR project allowing us to share the model among the EJB beans, the WAR web project and the distributed clients of the business layer that includes the SE clients, the web services clients and any JMS client listeners.
R6: Full abstraction of the database
- We will use JPA 2.0 to manage the persistence of the model.
Analysis
AI2: Synchronous or Asynchronous access to session beans from clients
- We have the choice of getting a reference to a remote session bean and holding that reference for the duration of the client work packet until we return results to the server. Or, we can perform separate calls to separate references to get and put the work unit. It will depend on the length of time to process the unit, the bean lifetime and how many beans are in the server pool.
Use Cases
UC1: Request unit of work
UC2: Post completed unit of work
Variant Use Cases
UC101: Communication Errors
UC101.1: RMI Host not available
UC101.1: RMI Bean not available
UC101.1: RMI Host busy
UC102: Handle discarded unit of work
Design
DI 1: Distributed Communication to use
- How are we going to link the distributed clients? Are we linking the one-to-many or many-to-many where all clients communicate with each other (which would necessitate multiple EE servers).
- 1) Multiple SE clients linked to multiple SE clients - non EE
- 2) Multiple EE clients linked to multiple SE clients - overhead
- 3) Multiple SE clients linked to multiple EE clients - possible
- 4) Multiple EE clients linked to multiple EE clients - complex
- 5) Multiple SE clients linked to single SE server - non EE
- 6) Multiple SE clients linked to single EE server - in use
- This model is the most promising and offers the least overhead. The SE clients will get and post work packets. If any user or admin needs to check the data they can do so via a browser based interface to the server.
- 7) Multiple EE clients linked to single SE server - invalid
- 8) Multiple EE clients linked to single EE server - possible
DI 3: Remote RMI/EJB Communication type
Remote Session Beans on WebLogic 10.3.4.0
Remote Session Beans on GlassFish 3.1
DI 4: Type of client/server setup
- 1) multiple SE clients communicate to a single EE server
- 2) multiple EE clients communicate to a single EE server
Decision DI4:
- We will be using 1) and only run a single EE server with multiple SE clients
Data Model
- The following UML class diagram details the data model for the business objects. We will be using JPA entities and mappedsuperclass artifacts.
Implementation
EE Server
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="CollatzGF-ejbPU" transaction-type="JTA"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <!--provider>org.hibernate.ejb.HibernatePersistence</provider--> <jta-data-source>jdbc/Collatz2</jta-data-source> <class>org.dataparallel.collatz.business.ActiveProcessor</class> <class>org.dataparallel.collatz.business.CollatzRecord</class> <class>org.dataparallel.collatz.business.Maximum</class> <class>org.dataparallel.collatz.business.Parameters</class> <class>org.dataparallel.collatz.business.Path</class> <class>org.dataparallel.collatz.business.UnitOfWork</class> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties> <!-- EclipseLink --> <property name="eclipselink.target-server" value="SunAS9"/> <property name="eclipselink.target-database" value="Derby"/> <!-- turn off DDL generation after the model is stable --> <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/> <property name="eclipselink.ddl-generation.output-mode" value="database"/> <property name="eclipselink.logging.level" value="FINEST"/> <!-- enable SQL parameter binding visibility logging to override ER 329852 --> <property name="eclipselink.logging.parameters" value="true"/> <!-- http://netbeans.org/kb/docs/web/hibernate-jpa.html --> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> </properties> </persistence-unit> </persistence>
SE Client
- The SE client will need a reference to the EE libraries of the server, here are the locations of the relevant jars. In the case of GlassFish - the gf-client.jar' is a manifest only jar that references the other EE jars by relative paths (so do not move it). In the case of WebLogic - the wlfullclient.jar library must be generated at design-time.
- GlassFish 3.0.x
- C:\opt\nbglassfish301\glassfish\modules\gf-client.jar
- GlassFish 3.1
- C:\opt\nbgf31b41\glassfish\lib\gf-client.jar
- WebLogic 10.3.4.0
- '
- GlassFish 3.0.x
JNDI name for Remote Session Bean
- For a bean named
@Stateless(name="CollatzFacade",mappedName="ejb/CollatzFacade") // mappedName for ejb3.0 only
- The client must resolve the following name.
private static final String SESSION_BEAN_REMOTE_NAME = "java:global/CollatzGF/CollatzGF-ejb/CollatzFacade!org.dataparallel.collatz.business.CollatzFacadeRemote";
SE Client Classpath
- The following line will setup the InitialContext properties properly for GlassFish when it is not run in the same JVM as GlassFish.
c:\jdk1.6.0-32b\bin\java -cp .;C:/opt/gf31b40/glassfish/lib/gf-client.jar;CollatzModel-jar.jar;CollatzGF-ejb.jar -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory -Dorg.omg.CORBA.ORBInitialHost=127.0.0.1 -Dorg.omg.CORBA.ORBInitialPort=3700 org.dataparallel.collatz.presentation.SEClient
WebService Client
JMS Client
JAX-RS Client
Testing
GlassFish 3.1 Server Logs
- The EE server is the same for all test cases below
Server Logs
INFO: GlassFish Server Open Source Edition 3.1-b41 (41) startup time : Felix (7,984ms), startup services(750ms), total(8,734ms) INFO: EclipseLink, version: Eclipse Persistence Services - 2.2.0.v20110202-r8913 CONFIG: Connected: jdbc:derby://localhost:1527/collatz2 INFO: file:/C:/_Netbeans691Projects/CollatzGF/dist/gfdeploy/CollatzGF/CollatzGF-ejb_jar/_CollatzGF-ejbPU login successful INFO: Portable JNDI names for EJB CollatzFacade : [java:global/CollatzGF/CollatzGF-ejb/CollatzFacade, java:global/CollatzGF/CollatzGF-ejb/CollatzFacade!org.dataparallel.collatz.business.CollatzFacadeRemote] INFO: Glassfish-specific (Non-portable) JNDI names for EJB CollatzFacade : [ejb/CollatzFacade, ejb/CollatzFacade#org.dataparallel.collatz.business.CollatzFacadeRemote] ... FINER: client acquired: 16292112 FINER: TX binding to tx mgr, status=STATUS_ACTIVE FINER: acquire unit of work: 30797517 ... INFO: Creating new org.dataparallel.collatz.business.ActiveProcessor[id=1] FINE: INSERT INTO ACTIVEPROCESSOR (ID, CATEGORY, CORES, IDENT, PERFORMANCE, RANK, THREADS, VERSION, ACTIVEUNITOFWORK_ID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) bind => [1, 0, null, xps435, null, null, 2, 1, null] INFO: _collatz: requestUnitOfWork(2147483648-2148532224) FINE: INSERT INTO UNITOFWORK (ID, ENDTIMESTAMP, EXTENT, INITIAL, MAXPATH, MAXVALUE, RETRIES, STARTTIMESTAMP, VERSION, KNOWNMAX_ID, KNOWNPATH_ID, PROCESSOR_ID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) bind => [5, null, 2148532224, 2147483649, 1, 1, 0, 1297284064640, 1, 3, 4, 1] FINE: INSERT INTO PARAMETERS (ID, BESTITERATIONSPERSECOND, GLOBALDURATION, GLOBALSTARTTIMESTAMP, MAXPATH, MAXVALUE, NEXTNUMBERTOSEARCH, PARTITIONLENGTH, VERSION) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) bind => [2, null, null, 1297284064640, 1, 1, 2148532224, 1048576, 1] INFO: Processing UOW: org.dataparallel.collatz.business.UnitOfWork[id=5] FINER: client acquired: 15148865 ... FINEST: Connection released to connection pool [read]. INFO: New max path : 967 INFO: New max value: 6694105047793216
TC1: Remote Session Bean Lookup on GlassFish 3.1 from SE Client on Same JVM
- As you can see above, we let a single remote client run for a couple seconds so that it reported a completed UnitOfWork entity packet back to the session bean that holds the dependency injected persistence context on the server.
SE Client Logs
run: 9-Feb-2011 4:11:01 PM com.sun.enterprise.v3.server.CommonClassLoaderServiceImpl findDerbyClient Context for xps435 : javax.naming.InitialContext@18fd984 INFO: Cannot find javadb client jar file, derby jdbc driver will not be available by default. Remote Object: org.dataparallel.collatz.business._CollatzFacadeRemote_Wrapper@498cb673 Narrowed Session Bean: org.dataparallel.collatz.business._CollatzFacadeRemote_Wrapper@498cb673 UnitOfWork from: xps435 = org.dataparallel.collatz.business.UnitOfWork[id=5] 2147483649-2148532224 Range: 2147483649 to: 2148532224 M,1048575,0,2148041982,693 ,6694105047793216 ,8666 , P,1048575,0,2148398424,967 ,966616035460 ,14359 , UnitOfWork from: xps435 = org.dataparallel.collatz.business.UnitOfWork[id=8] 2148532225-2149580800 Range: 2148532225 to: 2149580800 BUILD STOPPED (total time: 27 seconds)
TC2:Remote Session Bean Lookup on GlassFish 3.1 from SE Client on Different JVM - Local Machine
SE Client Logs
- This naming error is all over the internet - it means that the JNDI bean name below was not found (this exact code without the InitialContext parameters work when run inside NetBeans).
- @Stateless(name="CollatzFacade",mappedName="ejb/CollatzFacade")
C:\_experiment\Collatz>c:\jdk1.6.0\bin\java -cp .;C:/opt/nbgf31b41/glassfish/lib/gf-client.jar;CollatzModel-jar.jar;CollatzGF-ejb.jar -Djava .naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory -Dorg.omg.CORBA.ORBInitialHost=127.0.0.1 -Dorg.omg.CORBA.ORBInitialPort=3700 o rg.dataparallel.collatz.presentation.SEClient Context for xps435 : javax.naming.InitialContext@122cdb6 javax.naming.NameNotFoundException [Root exception is org.omg.CosNaming.NamingContextPackage.NotFound: IDL:omg.org/CosNaming/NamingContext/N otFound:1.0] at com.sun.jndi.cosnaming.ExceptionMapper.mapException(ExceptionMapper.java:44) at com.sun.jndi.cosnaming.CNCtx.callResolve(CNCtx.java:485) at com.sun.jndi.cosnaming.CNCtx.lookup(CNCtx.java:524) at com.sun.jndi.cosnaming.CNCtx.lookup(CNCtx.java:502) at javax.naming.InitialContext.lookup(InitialContext.java:392)
TC3:Remote Session Bean Lookup on GlassFish 3.1 from SE Client on Different JVM - Remote Machine
SE Client Logs
Results
EclipseLink 2.2 on GlassFish 3.1 within the same JVM in NetBeans 6.9.1
Status
- Document start on 09 Feb 2011 - estimated completion 5-15 days
TODO
- According to http://jazoon.com/Portals/0/Content/slides/tu_a6_1630-1650_champenois.pdf the OEPE plugin supports EJB 3.1 @Singleton beans - however I was under the impression that this EJB 3.1 part and EJB Lite were not yet in WebLogic 10.3.4.0 - need to verify this by example
- Get the JNDI name working for remote session bean lookup from an SE client in another JVM for GlassFish (this is working for WebLogic). Currently I can only get the case where the SE client is run in the same JVM as the server to work (where we use the no-arg constructor of InitialContext())