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.
Difference between revisions of "EclipseLink/Bugs/305331"
< EclipseLink | Bugs
m (→Results 1:) |
m (→Specifying @Remote @Stateless Session Bean using Defaults) |
||
(24 intermediate revisions by the same user not shown) | |||
Line 2: | Line 2: | ||
* [http://bugs.eclipse.org/305331 Bugzilla Bug 305331 Unsigned eclipselink.jar doesn't work with signed ejb3-persistence.jar for JPA testing on JBOSS EAP 5.0.0 GA ] | * [http://bugs.eclipse.org/305331 Bugzilla Bug 305331 Unsigned eclipselink.jar doesn't work with signed ejb3-persistence.jar for JPA testing on JBOSS EAP 5.0.0 GA ] | ||
+ | * [http://bugs.eclipse.org/305330 Bugzilla Bug 305330 EclipseLink JPA tests failed On JBOSS EAP 5.0.0 GA JNDI lookup failure of Proxy FactoryA ] | ||
+ | |||
== Document History == | == Document History == | ||
{|{{BMTableStyle}} | {|{{BMTableStyle}} | ||
Line 12: | Line 14: | ||
| Michael O'Brien | | Michael O'Brien | ||
| 1.0 Initial investigation of solution scenarios | | 1.0 Initial investigation of solution scenarios | ||
+ | |- | ||
+ | | 20100318 | ||
+ | | Michael O'Brien | ||
+ | | 1.1 Issue #2 - the EJB ProxyFailure issue is resolved by using a 3 part JNDI lookup that includes a prefixed application name | ||
+ | |- | ||
+ | | 20100319 | ||
+ | | Michael O'Brien | ||
+ | | 1.2 With Yiping Zhao and Peter Krogh - Solution for Issue #1 - the signing issue | ||
|} | |} | ||
== Status == | == Status == | ||
− | * | + | *Issue 1: Signing: Override signed '''%SERVER/common/lib/ejb3-persistence.jar''' with the lower unsigned '''%SERVER/jboss-as/server/default/lib/'''' ''ejb3-persistence.jar (CE edition)'', ''trunk/plugins/javax.persistence_unsigned_for_testing_1.0.0.jar'' or ''trunk/jpa/plugins/javax.persistence_2.0.0.v201002051058.jar'' |
+ | *<font color="green">Currently recommending '''[[EclipseLink/Bugs/305331#Option_7:_Override_common.2Flib_with_default.2Flib_for_both_eclipselink_and_javax.persistence_jars|Option 7]]'''</font> | ||
+ | *Issue 2: EJB ProxyFactory Exception: Use 3-part '''(app_name/bean_name/remote)''' or '''(app_name/remote-bean_name/qualified_bean_name)'''. | ||
+ | |||
== Overview == | == Overview == | ||
− | *The EAP 5.0.0 GA version of the JBoss Application Server ships with signed library jars. This presents a problem for users of EclipseLink that place our unsigned implementation jar '''eclipselink.jar''' beside the JPA 1.0 ''javax specification'' jar - '''ejb3-persistence.jar''' in the '''common/lib''' library folder off the server. On | + | ===Issue 1: Signed JAR=== |
+ | *The EAP 5.0.0 GA version of the JBoss Application Server ships with signed library jars. This presents a problem for users of EclipseLink that place our unsigned implementation jar '''eclipselink.jar''' beside the JPA 1.0 ''javax specification'' jar - '''ejb3-persistence.jar''' in the '''common/lib''' library folder off the server. On deployment in EAP 5.0.0 GA we receive a '''Security Exception''' because of the difference in security levels. | ||
*The Community Edition of JBoss 5.1.0 and 6.0.0 M1 do not have these issues because their library jars are unsigned. | *The Community Edition of JBoss 5.1.0 and 6.0.0 M1 do not have these issues because their library jars are unsigned. | ||
*This document details several possible solutions to this ''signed jar'' issue and recommends the best approach. | *This document details several possible solutions to this ''signed jar'' issue and recommends the best approach. | ||
+ | *JBoss '''[https://jira.jboss.org/jira/browse/JBPAPP-2971 JIRA JBPAPP-2971]''' is encountering the same issue with cglib.jar - one of the alternatives for this JIRA are the same as [[EclipseLink/Bugs/305331#Option_1:_Replace_signed_ejb3-persistence.jar_with_an_unsigned_version_from_JBoss_5.1.0_community_edition_-_valid|Option 1]] | ||
+ | |||
+ | ===Issue 2: EJB ProxyFactory Exception=== | ||
+ | *Outside of Eclipse we are not resolving an EJB Stateless Session bean Proxy properly - specifically in 5.0 EAP version of the JBoss server (The 5.1 and 6.0 version of the Community edition are working fine | ||
+ | *The solution is to use a more strict JBoss specific JNDI format that is required of JBoss EAP but is optional in JBoss CE | ||
+ | **Prepend the application(EAR) name in front of the bean_name/remote-qualified_bean_name JNDI lookup. | ||
+ | **Both the JNDI lookup and narrow work fine and return a session bean proxy. | ||
+ | **https://bugs.eclipse.org/bugs/show_bug.cgi?id=305330#c9 | ||
+ | ====Exception==== | ||
+ | <pre> | ||
+ | javax.naming.NamingException: Could not dereference object [Root exception is java.lang.RuntimeException: Exception while trying to locate proxy factory in JNDI, | ||
+ | at key ProxyFactory/eclipselink-advanced-field-access-model/TestRunner/TestRunner] | ||
+ | at org.jnp.interfaces.NamingContext.getObjectInstanceWrapFailure(NamingContext.java:1504) | ||
+ | at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:822) | ||
+ | at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:686) | ||
+ | at javax.naming.InitialContext.lookup(InitialContext.java:392) | ||
+ | at org.eclipse.persistence.testing.framework.junit.JUnitTestCase.runBareClient(JUnitTestCase.java:480) | ||
+ | at org.eclipse.persistence.testing.framework.junit.JUnitTestCase.runBare(JUnitTestCase.java:455) Caused by: java.lang.RuntimeException: Exception while trying to locate proxy factory in JNDI, | ||
+ | at key ProxyFactory/eclipselink-advanced-field-access-model/TestRunner/TestRunner | ||
+ | at org.jboss.ejb3.proxy.impl.objectfactory.ProxyObjectFactory.getProxyFactoryFromJNDI(ProxyObjectFactory.java:235) | ||
+ | at org.jboss.ejb3.proxy.impl.objectfactory.ProxyObjectFactory.getObjectInstance(ProxyObjectFactory.java:153) | ||
+ | at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:304) | ||
+ | at org.jnp.interfaces.NamingContext.getObjectInstance(NamingContext.java:1479) | ||
+ | at org.jnp.interfaces.NamingContext.getObjectInstanceWrapFailure(NamingContext.java:1496) Caused by: javax.naming.NameNotFoundException: ProxyFactory not bound at org.jnp.server.NamingServer.getBinding(NamingServer.java:771) | ||
+ | at org.jnp.server.NamingServer.getBinding(NamingServer.java:779) | ||
+ | at org.jnp.server.NamingServer.getObject(NamingServer.java:785) | ||
+ | at org.jnp.server.NamingServer.lookup(NamingServer.java:396) | ||
+ | at org.jnp.server.NamingServer.lookup(NamingServer.java:399) | ||
+ | at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:305) | ||
+ | at sun.rmi.transport.Transport$1.run(Transport.java:159) | ||
+ | at java.security.AccessController.doPrivileged(Native Method) | ||
+ | at sun.rmi.transport.Transport.serviceCall(Transport.java:155) | ||
+ | at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535) | ||
+ | at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790) | ||
+ | at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649) | ||
+ | at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) | ||
+ | at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) | ||
+ | at java.lang.Thread.run(Thread.java:619) | ||
+ | at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255) | ||
+ | at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233) | ||
+ | at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:142) | ||
+ | at org.jnp.server.NamingServer_Stub.lookup(Unknown Source) | ||
+ | at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:726) | ||
+ | at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:686) | ||
+ | at org.jboss.ejb3.proxy.impl.objectfactory.ProxyObjectFactory.getProxyFactoryFromJNDI(ProxyObjectFactory.java:226) | ||
+ | </pre> | ||
+ | |||
+ | ====Code Details of the fix==== | ||
+ | <source lang="java"> | ||
+ | properties.put("java.naming.provider.url", "jnp://localhost:1099/"); | ||
+ | //properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); | ||
+ | Context context = new InitialContext(properties); | ||
+ | TestRunner runner; | ||
+ | testrunner = "eclipselink-advanced-field-access-model/TestRunner/remote-org.eclipse.persistence.testing.framework.server.TestRunner"; | ||
+ | System.out.println("_lookup: " + testrunner); | ||
+ | Object reference = context.lookup(testrunner); | ||
+ | System.out.println("_reference:" + reference); | ||
+ | runner = (TestRunner) PortableRemoteObject.narrow(reference, TestRunner.class); | ||
+ | System.out.println("_narrowed:" + runner); | ||
+ | </source> | ||
+ | |||
+ | ====JNDI Output Logs==== | ||
+ | =====Previously not working with truncated JNDI lookup that is missing the EAR name===== | ||
+ | <source lang="java"> | ||
+ | //testrunner = "eclipselink-advanced-field-access-model/TestRunner/remote-org.eclipse.persistence.testing.framework.server.TestRunner"; | ||
+ | [junit] _lookup: TestRunner/remote-org.eclipse.persistence.testing.framework.server.TestRunner | ||
+ | </source> | ||
+ | |||
+ | =====Working===== | ||
+ | <source lang="java"> | ||
+ | testrunner = "eclipselink-advanced-field-access-model/TestRunner/remote-org.eclipse.persistence.testing.framework.server.TestRunner"; | ||
+ | [junit] _lookup: eclipselink-advanced-field-access-model/TestRunner/remote-org.eclipse.persistence.testing.framework.server.TestRunner | ||
+ | [junit] _reference:Proxy to jboss.j2ee:ear=eclipselink-advanced-field-access-model.ear,jar=eclipselink-advanced-field-access-model_ejb.jar,name=TestRunner,service=EJB3 implementing [interface org.eclipse.persistence.testing.framework.server.TestRunner] | ||
+ | [junit] _narrowed:Proxy to jboss.j2ee:ear=eclipselink-advanced-field-access-model.ear,jar=eclipselink-advanced-field-access-model_ejb.jar,name=TestRunner,service=EJB3 implementing [interface org.eclipse.persistence.testing.framework.server.TestRunner] | ||
+ | </source> | ||
+ | |||
+ | ====Summary:==== | ||
+ | *The fix is to follow the more strict JBoss specific JNDI format of ''EAR_name/EJB_name/remote-qualified''_EJB_name instead of ''EJB_name/remote-qualified_EJB_name'' | ||
+ | |||
+ | ====EJB 3.0 Specification details on JNDI lookup of EJB reference==== | ||
+ | *The specification only mentions the standard 2 part format | ||
+ | **3.6.1 p51 | ||
+ | <source lang="java">CartHome cartHome = (CartHome)ctx.lookup(“com.acme.example.MySessionBean/cartHome”);</source> | ||
+ | |||
== Concepts == | == Concepts == | ||
===JPA Specification Notes=== | ===JPA Specification Notes=== | ||
Line 56: | Line 154: | ||
===Prerequisites=== | ===Prerequisites=== | ||
===Data Model=== | ===Data Model=== | ||
− | *The testing models for reproduction are based off of the [http://wiki.eclipse.org/EclipseLink/Examples/JPA/JBoss_Web_Tutorial JBoss server example] in the SVN trunk. | + | *The standalone testing models for reproduction are based off of the [http://wiki.eclipse.org/EclipseLink/Examples/JPA/JBoss_Web_Tutorial JBoss server example] in the SVN trunk. |
+ | *The formal testing model is the '''TestRunnerBean''' in the JPA test suite | ||
+ | ====EJB JNDI Specification Defaults==== | ||
+ | *There are 2 primary ways of defining a stateless session bean and it's remote interface, one involves using defaults, the other has annotation overrides. | ||
+ | *The way that you define these classes will determine what the JNDI name is when looking up the Proxy from the ProxyFactory on JBoss. | ||
+ | =====Specifying @Remote @Stateless Session Bean using Defaults===== | ||
+ | *The following scenario specifies @Remote on the remote interface and @Stateless on the stateless session bean. | ||
+ | **This results in the following JNDI name emitted by the server on EAR deploy | ||
+ | <source lang="java"> | ||
+ | |||
+ | |||
+ | @Stateless(name="ApplicationService", mappedName="ApplicationService") | ||
+ | @Remote(ApplicationServiceRemote.class) | ||
+ | public class ApplicationService implements ApplicationServiceRemote { | ||
+ | @PersistenceContext(unitName="example", type=PersistenceContextType.TRANSACTION) | ||
+ | private EntityManager entityManager; | ||
+ | ... | ||
+ | } | ||
+ | |||
+ | public class FrontController extends HttpServlet implements Servlet { | ||
+ | public static final String APPLICATION_SERVICE_JNDI_NAME = "org.eclipse.persistence.example.jpa.server.jboss.EnterpriseEAR/ApplicationService/remote-org.eclipse.persistence.example.jpa.server.business.ApplicationServiceRemote"; | ||
+ | |||
+ | /** | ||
+ | * Get the SSB ApplicationService bean - using a JNDI context lookup (no EJB injection was used on this servlet) | ||
+ | * @param viaJNDILookup | ||
+ | * @return | ||
+ | */ | ||
+ | public ApplicationServiceRemote getApplicationService(boolean viaJNDILookup) { | ||
+ | if(null == applicationService && viaJNDILookup) { | ||
+ | try { | ||
+ | Hashtable<String, String> env = new Hashtable<String, String>(); | ||
+ | env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); | ||
+ | env.put(Context.PROVIDER_URL, "localhost"); | ||
+ | env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces" ); | ||
+ | InitialContext ctx = new InitialContext(env); | ||
+ | System.out.println("FrontController.getApplicationService() JNDI lookup of " + APPLICATION_SERVICE_JNDI_NAME); | ||
+ | return (ApplicationServiceRemote) ctx.lookup(APPLICATION_SERVICE_JNDI_NAME); | ||
+ | } catch (Exception e) { | ||
+ | e.printStackTrace(); | ||
+ | throw new RuntimeException("Exception looking up session bean: ", e); } | ||
+ | } else { | ||
+ | return applicationService; | ||
+ | } | ||
+ | } | ||
+ | ... | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | =====Specifying @Remote @Stateless Session Bean using Overrides===== | ||
+ | <source lang="java"> | ||
+ | public interface TestRunner { ... } | ||
+ | |||
+ | @Stateless(name="TestRunner", mappedName="TestRunner") | ||
+ | @Remote(TestRunner.class) | ||
+ | @TransactionManagement(TransactionManagementType.BEAN) | ||
+ | public class TestRunnerBean implements TestRunner { | ||
+ | @PersistenceContext | ||
+ | private EntityManager entityManager; | ||
+ | ... | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | ===Servlet Client for Local Stateless Session Bean=== | ||
+ | *The following JNDI context lookup is used to get a reference to the local interface of the stateless session bean deployed in the ejb.jar of the EAR. | ||
+ | ===SE Client for Remote Stateless Session Bean=== | ||
+ | *The following JNDI context lookup will get a standalone SE client a reference to the stateless session bean running in the example EAR. | ||
+ | <source lang="java"> | ||
+ | </source> | ||
+ | |||
===Use Case 1: Container managed Persistence Unit injected on a Stateless Session Bean invoked via a Servlet client=== | ===Use Case 1: Container managed Persistence Unit injected on a Stateless Session Bean invoked via a Servlet client=== | ||
*This use case is valid for options 1, 2, 5 | *This use case is valid for options 1, 2, 5 | ||
Line 66: | Line 232: | ||
===<font color="green">Option 1: Replace signed ejb3-persistence.jar with an unsigned version from JBoss 5.1.0 community edition - valid</font>=== | ===<font color="green">Option 1: Replace signed ejb3-persistence.jar with an unsigned version from JBoss 5.1.0 community edition - valid</font>=== | ||
====Server Configuration 1:==== | ====Server Configuration 1:==== | ||
− | * replace 5.0.0 (ejb3-persistence.jar) with version from 5.1.0 (community edition) - both JPA 1.0 versions in '''common/lib''' | + | * place '''eclipselink.jar''' into '''common/lib'''. |
+ | * replace the signed JBoss EAP 5.0.0 (ejb3-persistence.jar) with the unsigned version from JBoss 5.1.0 (community edition) - both JPA 1.0 versions in '''common/lib''' | ||
*restart server, deploy EAR | *restart server, deploy EAR | ||
====Client Configuration 1:==== | ====Client Configuration 1:==== | ||
+ | * Remove the JPA 2.0 API in the stateless session bean and revert persistence.xml from a JPA 2.0 to JPA 1.0 level before running the example project in trunk | ||
* Client EAR runs out of the box using default HSQL TX datasource - https://bugs.eclipse.org/bugs/attachment.cgi?id=161810 | * Client EAR runs out of the box using default HSQL TX datasource - https://bugs.eclipse.org/bugs/attachment.cgi?id=161810 | ||
+ | * Client is a Servlet with JNDI injection via | ||
+ | <source lang="java"> | ||
+ | public static final String APPLICATION_SERVICE_JNDI_NAME = "org.eclipse.persistence.example.jpa.server.jboss.EnterpriseEAR/ApplicationService/local"; | ||
+ | ... | ||
+ | Hashtable<String, String> env = new Hashtable<String, String>(); | ||
+ | env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); | ||
+ | env.put(Context.PROVIDER_URL, "localhost"); | ||
+ | env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces" ); | ||
+ | InitialContext ctx = new InitialContext(env); | ||
+ | return (ApplicationServiceLocal) ctx.lookup(APPLICATION_SERVICE_JNDI_NAME); | ||
+ | </source> | ||
+ | * Need to test SE client | ||
+ | |||
====Results 1:==== | ====Results 1:==== | ||
*JPA 1.0 application runs fine | *JPA 1.0 application runs fine | ||
Line 76: | Line 257: | ||
</pre> | </pre> | ||
− | ===<font color="red">Option 2: Ship signed eclipselink.jar - invalid</font>=== | + | ===''<font color="red">Option 2: Ship signed eclipselink.jar - invalid</font>''=== |
*This option has us sign our eclipselink.jar with jarsigner - however we do not have access to the private keys used to sign the JBoss libraries so this is currently not feasible. | *This option has us sign our eclipselink.jar with jarsigner - however we do not have access to the private keys used to sign the JBoss libraries so this is currently not feasible. | ||
− | + | *If the user's application is signed (IE: they are running a signed applet persistence client) - they will need to resign the jar. | |
− | + | ||
− | + | ||
===<font color="orange">Option 3: Global Shared Library - Server level scope - verifying</font>=== | ===<font color="orange">Option 3: Global Shared Library - Server level scope - verifying</font>=== | ||
*In this option we create a global shared library on the server or in a jar-only EAR that is accessible to all server applications. | *In this option we create a global shared library on the server or in a jar-only EAR that is accessible to all server applications. | ||
*This shared library must override the '''common/lib/ejb3-persistence.jar'''. | *This shared library must override the '''common/lib/ejb3-persistence.jar'''. | ||
====Server Configuration 3:==== | ====Server Configuration 3:==== | ||
+ | * no '''eclipselink.jar''' into '''common/lib'''. | ||
+ | |||
+ | =====Shared Library on EAR/lib===== | ||
+ | *Add EAR/lib/eclipselink.jar and EAR/lib/javax.persistence_2.0.0.v201002051058.jar | ||
+ | *Reference these two jars in the '''war/src/META-INF/manifest.MF | ||
+ | **Class-Path: javax.persistence_2.0.0.v201002051058.jar eclipselink.jar | ||
+ | *Getting CCE because the ejb3.persistence.jar on the server is taking precedence by default over the specification jar shipped with the EAR - IE: you cannot have two javax.persistence jars. | ||
+ | **java.lang.ClassCastException: org.eclipse.persistence.jpa.PersistenceProvider cannot be cast to javax.persistence.spi.PersistenceProvider | ||
+ | *Solution would be a similar override as for ''WebLogic'' via '''<pre><wls:prefer-application-packages></pre>''' | ||
+ | |||
====Client Configuration 3:==== | ====Client Configuration 3:==== | ||
+ | * place '''eclipselink.jar''' and the '''jpa 1.0/2.0 specification jar''' into '''EAR/lib'''. | ||
+ | |||
*One of | *One of | ||
**jboss-app.xml | **jboss-app.xml | ||
Line 101: | Line 293: | ||
====Client Configuration 5:==== | ====Client Configuration 5:==== | ||
====Results 5:==== | ====Results 5:==== | ||
+ | ===<font color="red">''Option 6: ship eclipselink and javax.persistence jar only in EAR - infeasible''</font>=== | ||
+ | ====Server Configuration 6:==== | ||
+ | *Remove '''ejb3-persistence.jar''' from ''common/lib'' on the server. | ||
+ | ====Client Configuration 6:==== | ||
+ | *add '''javax.persistence''' and '''eclipselink.jar''' to the ''EAR/lib'' directory. | ||
+ | ====Results 6:==== | ||
+ | *The JBoss server will not start because the web apps internal to the server require the presence of '''ejb3-persistence''' at the global server classpath level. | ||
+ | ===<font color="green">''Option 7: Override common/lib with default/lib for both eclipselink and javax.persistence jars''</font>=== | ||
+ | ====Server Configuration 7:==== | ||
+ | *keep the signed '''ejb3-persistence.jar''' from ''common/lib'' on the server in place. | ||
+ | *copy eclipselink.jar to ''server/default/lib'' | ||
+ | *copy javax.persistence spec jar to ''server/default/lib'' | ||
+ | ====Client Configuration 7:==== | ||
+ | *no changes | ||
+ | ====Results 7:==== | ||
+ | *EntityManager and EntityManagerFactory injection on the remote stateless session bean is working fine. | ||
+ | *The JPA war applications that start with the JBoss server deploy fine | ||
+ | *Weaving is unaffected as currently only static weaving is avaible on JBoss | ||
== Open Issues == | == Open Issues == | ||
Line 129: | Line 339: | ||
== References == | == References == | ||
+ | *[http://wiki.eclipse.org/EclipseLink/Examples/JPA/JBoss_Web_Tutorial EclipseLink JPA Tutorial EAR for JBoss 5.1.0 and 6.0.0 M1] | ||
+ | *EclipseLink JBoss Tutorial [http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/trunk/examples/org.eclipse.persistence.example.jpa.server.jboss.EnterpriseEAR/ EAR], [http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/trunk/examples/org.eclipse.persistence.example.jpa.server.jboss.EnterpriseEJB/ EJB] and [http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/trunk/examples/org.eclipse.persistence.example.jpa.server.jboss.EnterpriseWeb/ WAR] projects in SVN. | ||
+ | *[https://community.jboss.org/message/533316 JBoss Community Post 531496] |
Latest revision as of 11:05, 24 June 2010
Contents
- 1 Bug Analysis Document: 305331: EclipseLink deployment on JBoss EAP 5.0.0 GA using signed JPA 1.0 ejb3-persistence.jar
- 1.1 Document History
- 1.2 Status
- 1.3 Overview
- 1.4 Concepts
- 1.5 Reproduction
- 1.5.1 Results: unsigned/signed conflict SecurityException - expected
- 1.5.2 Prerequisites
- 1.5.3 Data Model
- 1.5.4 Servlet Client for Local Stateless Session Bean
- 1.5.5 SE Client for Remote Stateless Session Bean
- 1.5.6 Use Case 1: Container managed Persistence Unit injected on a Stateless Session Bean invoked via a Servlet client
- 1.5.7 Use Case 2: Application managed Persistence Unit injected on Servlet client
- 1.6 Analysis
- 1.6.1 Option 1: Replace signed ejb3-persistence.jar with an unsigned version from JBoss 5.1.0 community edition - valid
- 1.6.2 Option 2: Ship signed eclipselink.jar - invalid
- 1.6.3 Option 3: Global Shared Library - Server level scope - verifying
- 1.6.4 Option 4: Application Shared Library - Local EAR level scope - verifying
- 1.6.5 Option 5: Generate an eclipselink jar with the JPA 2.0 dependencies removed
- 1.6.6 Option 6: ship eclipselink and javax.persistence jar only in EAR - infeasible
- 1.6.7 Option 7: Override common/lib with default/lib for both eclipselink and javax.persistence jars
- 1.7 Open Issues
- 1.8 Decisions
- 1.9 Future Considerations
- 1.10 References
Bug Analysis Document: 305331: EclipseLink deployment on JBoss EAP 5.0.0 GA using signed JPA 1.0 ejb3-persistence.jar
- Bugzilla Bug 305331 Unsigned eclipselink.jar doesn't work with signed ejb3-persistence.jar for JPA testing on JBOSS EAP 5.0.0 GA
- Bugzilla Bug 305330 EclipseLink JPA tests failed On JBOSS EAP 5.0.0 GA JNDI lookup failure of Proxy FactoryA
Document History
Date | Author | Version Description & Notes |
---|---|---|
20100312 | Michael O'Brien | 1.0 Initial investigation of solution scenarios |
20100318 | Michael O'Brien | 1.1 Issue #2 - the EJB ProxyFailure issue is resolved by using a 3 part JNDI lookup that includes a prefixed application name |
20100319 | Michael O'Brien | 1.2 With Yiping Zhao and Peter Krogh - Solution for Issue #1 - the signing issue |
Status
- Issue 1: Signing: Override signed %SERVER/common/lib/ejb3-persistence.jar with the lower unsigned %SERVER/jboss-as/server/default/lib/' ejb3-persistence.jar (CE edition), trunk/plugins/javax.persistence_unsigned_for_testing_1.0.0.jar or trunk/jpa/plugins/javax.persistence_2.0.0.v201002051058.jar
- Currently recommending Option 7
- Issue 2: EJB ProxyFactory Exception: Use 3-part (app_name/bean_name/remote) or (app_name/remote-bean_name/qualified_bean_name).
Overview
Issue 1: Signed JAR
- The EAP 5.0.0 GA version of the JBoss Application Server ships with signed library jars. This presents a problem for users of EclipseLink that place our unsigned implementation jar eclipselink.jar beside the JPA 1.0 javax specification jar - ejb3-persistence.jar in the common/lib library folder off the server. On deployment in EAP 5.0.0 GA we receive a Security Exception because of the difference in security levels.
- The Community Edition of JBoss 5.1.0 and 6.0.0 M1 do not have these issues because their library jars are unsigned.
- This document details several possible solutions to this signed jar issue and recommends the best approach.
- JBoss JIRA JBPAPP-2971 is encountering the same issue with cglib.jar - one of the alternatives for this JIRA are the same as Option 1
Issue 2: EJB ProxyFactory Exception
- Outside of Eclipse we are not resolving an EJB Stateless Session bean Proxy properly - specifically in 5.0 EAP version of the JBoss server (The 5.1 and 6.0 version of the Community edition are working fine
- The solution is to use a more strict JBoss specific JNDI format that is required of JBoss EAP but is optional in JBoss CE
- Prepend the application(EAR) name in front of the bean_name/remote-qualified_bean_name JNDI lookup.
- Both the JNDI lookup and narrow work fine and return a session bean proxy.
- https://bugs.eclipse.org/bugs/show_bug.cgi?id=305330#c9
Exception
javax.naming.NamingException: Could not dereference object [Root exception is java.lang.RuntimeException: Exception while trying to locate proxy factory in JNDI, at key ProxyFactory/eclipselink-advanced-field-access-model/TestRunner/TestRunner] at org.jnp.interfaces.NamingContext.getObjectInstanceWrapFailure(NamingContext.java:1504) at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:822) at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:686) at javax.naming.InitialContext.lookup(InitialContext.java:392) at org.eclipse.persistence.testing.framework.junit.JUnitTestCase.runBareClient(JUnitTestCase.java:480) at org.eclipse.persistence.testing.framework.junit.JUnitTestCase.runBare(JUnitTestCase.java:455) Caused by: java.lang.RuntimeException: Exception while trying to locate proxy factory in JNDI, at key ProxyFactory/eclipselink-advanced-field-access-model/TestRunner/TestRunner at org.jboss.ejb3.proxy.impl.objectfactory.ProxyObjectFactory.getProxyFactoryFromJNDI(ProxyObjectFactory.java:235) at org.jboss.ejb3.proxy.impl.objectfactory.ProxyObjectFactory.getObjectInstance(ProxyObjectFactory.java:153) at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:304) at org.jnp.interfaces.NamingContext.getObjectInstance(NamingContext.java:1479) at org.jnp.interfaces.NamingContext.getObjectInstanceWrapFailure(NamingContext.java:1496) Caused by: javax.naming.NameNotFoundException: ProxyFactory not bound at org.jnp.server.NamingServer.getBinding(NamingServer.java:771) at org.jnp.server.NamingServer.getBinding(NamingServer.java:779) at org.jnp.server.NamingServer.getObject(NamingServer.java:785) at org.jnp.server.NamingServer.lookup(NamingServer.java:396) at org.jnp.server.NamingServer.lookup(NamingServer.java:399) at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:305) at sun.rmi.transport.Transport$1.run(Transport.java:159) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.Transport.serviceCall(Transport.java:155) at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:619) at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255) at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233) at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:142) at org.jnp.server.NamingServer_Stub.lookup(Unknown Source) at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:726) at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:686) at org.jboss.ejb3.proxy.impl.objectfactory.ProxyObjectFactory.getProxyFactoryFromJNDI(ProxyObjectFactory.java:226)
Code Details of the fix
properties.put("java.naming.provider.url", "jnp://localhost:1099/"); //properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); Context context = new InitialContext(properties); TestRunner runner; testrunner = "eclipselink-advanced-field-access-model/TestRunner/remote-org.eclipse.persistence.testing.framework.server.TestRunner"; System.out.println("_lookup: " + testrunner); Object reference = context.lookup(testrunner); System.out.println("_reference:" + reference); runner = (TestRunner) PortableRemoteObject.narrow(reference, TestRunner.class); System.out.println("_narrowed:" + runner);
JNDI Output Logs
Previously not working with truncated JNDI lookup that is missing the EAR name
//testrunner = "eclipselink-advanced-field-access-model/TestRunner/remote-org.eclipse.persistence.testing.framework.server.TestRunner"; [junit] _lookup: TestRunner/remote-org.eclipse.persistence.testing.framework.server.TestRunner
Working
testrunner = "eclipselink-advanced-field-access-model/TestRunner/remote-org.eclipse.persistence.testing.framework.server.TestRunner"; [junit] _lookup: eclipselink-advanced-field-access-model/TestRunner/remote-org.eclipse.persistence.testing.framework.server.TestRunner [junit] _reference:Proxy to jboss.j2ee:ear=eclipselink-advanced-field-access-model.ear,jar=eclipselink-advanced-field-access-model_ejb.jar,name=TestRunner,service=EJB3 implementing [interface org.eclipse.persistence.testing.framework.server.TestRunner] [junit] _narrowed:Proxy to jboss.j2ee:ear=eclipselink-advanced-field-access-model.ear,jar=eclipselink-advanced-field-access-model_ejb.jar,name=TestRunner,service=EJB3 implementing [interface org.eclipse.persistence.testing.framework.server.TestRunner]
Summary:
- The fix is to follow the more strict JBoss specific JNDI format of EAR_name/EJB_name/remote-qualified_EJB_name instead of EJB_name/remote-qualified_EJB_name
EJB 3.0 Specification details on JNDI lookup of EJB reference
- The specification only mentions the standard 2 part format
- 3.6.1 p51
CartHome cartHome = (CartHome)ctx.lookup(“com.acme.example.MySessionBean/cartHome”);
Concepts
JPA Specification Notes
JPA 1.0 Specification
JPA 2.0 Specification
Reproduction
- Reproduction in standalone EAR (outside of test framework configuration)
- trunk examples JBoss EAR with commented JPA 2.0 calls and persistence.xml tags
- http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/trunk/examples/org.eclipse.persistence.example.jpa.server.jboss.EnterpriseEJB/ejbModule/META-INF/persistence.xml
- copy unsigned trunk eclipselink.jar to common/lib
- create default JBoss 5 server in Eclipse IDE
- deploy jboss.EnterpriseEAR (with default HSQL datasource) to JBoss 5.0 EAP
- http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/trunk/examples/org.eclipse.persistence.example.jpa.server.jboss.EnterpriseEJB/ejbModule/META-INF/persistence.xml
- trunk examples JBoss EAR with commented JPA 2.0 calls and persistence.xml tags
Results: unsigned/signed conflict SecurityException - expected
Logs:
2010-03-11 11:10:08,988 INFO [org.jboss.bootstrap.microcontainer.ServerImpl] (main) JBoss (Microcontainer) [5.0.0.GA (build: SVNTag=JBPAPP_5_0_0_GA date=200910202128)] Started in 1m:3s:180ms 2010-03-11 11:10:47,698 INFO [org.jboss.ejb3.deployers.Ejb3DependenciesDeployer] (HDScanner) Encountered deployment AbstractVFSDeploymentContext@26267218{vfszip:/C:/opt/jboss-eap-5.0/jboss-as/server/default/deploy/org.eclipse.persistence.example.jpa.server.jboss.EnterpriseEAR.ear/org.eclipse.persistence.example.jpa.server.jboss.EnterpriseEJB.jar/} 2010-03-11 11:10:48,059 INFO [org.jboss.jpa.deployment.PersistenceUnitDeployment] (HDScanner) Starting persistence unit persistence.unit:unitName=org.eclipse.persistence.example.jpa.server.jboss.EnterpriseEAR.ear/org.eclipse.persistence.example.jpa.server.jboss.EnterpriseEJB.jar#example 2010-03-11 11:10:48,069 WARN [org.jboss.detailed.classloader.ClassLoaderManager] (HDScanner) Unexpected error during load of:javax.persistence.spi.ProviderUtil java.lang.SecurityException: lass "javax.persistence.spi.ProviderUtil"'s signer information does not match signer information of other classes in the same package at java.lang.ClassLoader.checkCerts(ClassLoader.java:769) ... at org.jboss.jpa.deployment.PersistenceUnitDeployment.start(PersistenceUnitDeployment.java:285) >and resultant secondary exception CNFE because the signed JPA 1.0 specification class was not loaded 2010-03-11 11:10:48,069 ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController] (HDScanner) Error installing to Start: name=persistence.unit:unitName=org.eclipse.persistence.example.jpa.server.jboss.EnterpriseEAR.ear/org.eclipse.persistence.example.jpa.server.jboss.EnterpriseEJB.jar#example state=Create java.lang.NoClassDefFoundError: javax/persistence/spi/ProviderUtil Caused by: java.lang.ClassNotFoundException: Unexpected error during load of: javax.persistence.spi.ProviderUtil, msg=class "javax.persistence.spi.ProviderUtil"'s signer information does not match signer information of other classes in the same package
Prerequisites
Data Model
- The standalone testing models for reproduction are based off of the JBoss server example in the SVN trunk.
- The formal testing model is the TestRunnerBean in the JPA test suite
EJB JNDI Specification Defaults
- There are 2 primary ways of defining a stateless session bean and it's remote interface, one involves using defaults, the other has annotation overrides.
- The way that you define these classes will determine what the JNDI name is when looking up the Proxy from the ProxyFactory on JBoss.
Specifying @Remote @Stateless Session Bean using Defaults
- The following scenario specifies @Remote on the remote interface and @Stateless on the stateless session bean.
- This results in the following JNDI name emitted by the server on EAR deploy
@Stateless(name="ApplicationService", mappedName="ApplicationService") @Remote(ApplicationServiceRemote.class) public class ApplicationService implements ApplicationServiceRemote { @PersistenceContext(unitName="example", type=PersistenceContextType.TRANSACTION) private EntityManager entityManager; ... } public class FrontController extends HttpServlet implements Servlet { public static final String APPLICATION_SERVICE_JNDI_NAME = "org.eclipse.persistence.example.jpa.server.jboss.EnterpriseEAR/ApplicationService/remote-org.eclipse.persistence.example.jpa.server.business.ApplicationServiceRemote"; /** * Get the SSB ApplicationService bean - using a JNDI context lookup (no EJB injection was used on this servlet) * @param viaJNDILookup * @return */ public ApplicationServiceRemote getApplicationService(boolean viaJNDILookup) { if(null == applicationService && viaJNDILookup) { try { Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); env.put(Context.PROVIDER_URL, "localhost"); env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces" ); InitialContext ctx = new InitialContext(env); System.out.println("FrontController.getApplicationService() JNDI lookup of " + APPLICATION_SERVICE_JNDI_NAME); return (ApplicationServiceRemote) ctx.lookup(APPLICATION_SERVICE_JNDI_NAME); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("Exception looking up session bean: ", e); } } else { return applicationService; } } ... }
Specifying @Remote @Stateless Session Bean using Overrides
public interface TestRunner { ... } @Stateless(name="TestRunner", mappedName="TestRunner") @Remote(TestRunner.class) @TransactionManagement(TransactionManagementType.BEAN) public class TestRunnerBean implements TestRunner { @PersistenceContext private EntityManager entityManager; ... }
Servlet Client for Local Stateless Session Bean
- The following JNDI context lookup is used to get a reference to the local interface of the stateless session bean deployed in the ejb.jar of the EAR.
SE Client for Remote Stateless Session Bean
- The following JNDI context lookup will get a standalone SE client a reference to the stateless session bean running in the example EAR.
Use Case 1: Container managed Persistence Unit injected on a Stateless Session Bean invoked via a Servlet client
- This use case is valid for options 1, 2, 5
Use Case 2: Application managed Persistence Unit injected on Servlet client
- This use case is valid for options 1, 2, 3, 4, 5
StackTrace
Logs
Analysis
Option 1: Replace signed ejb3-persistence.jar with an unsigned version from JBoss 5.1.0 community edition - valid
Server Configuration 1:
- place eclipselink.jar into common/lib.
- replace the signed JBoss EAP 5.0.0 (ejb3-persistence.jar) with the unsigned version from JBoss 5.1.0 (community edition) - both JPA 1.0 versions in common/lib
- restart server, deploy EAR
Client Configuration 1:
- Remove the JPA 2.0 API in the stateless session bean and revert persistence.xml from a JPA 2.0 to JPA 1.0 level before running the example project in trunk
- Client EAR runs out of the box using default HSQL TX datasource - https://bugs.eclipse.org/bugs/attachment.cgi?id=161810
- Client is a Servlet with JNDI injection via
public static final String APPLICATION_SERVICE_JNDI_NAME = "org.eclipse.persistence.example.jpa.server.jboss.EnterpriseEAR/ApplicationService/local"; ... Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); env.put(Context.PROVIDER_URL, "localhost"); env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces" ); InitialContext ctx = new InitialContext(env); return (ApplicationServiceLocal) ctx.lookup(APPLICATION_SERVICE_JNDI_NAME);
- Need to test SE client
Results 1:
- JPA 1.0 application runs fine
12:01:41,308 INFO [STDOUT] [EL Finest]: 2010-03-11 12:01:41.308--UnitOfWork(11747982)--Thread(Thread[http-127.0.0.1-8080-1,5,jboss])--Register the existing object org.eclipse.persistence.example.jpa.server.business.Cell@3324876( id: 2 state: null left: null right: null parent: HashSet@34627602 references: HashSet@34627602)
Option 2: Ship signed eclipselink.jar - invalid
- This option has us sign our eclipselink.jar with jarsigner - however we do not have access to the private keys used to sign the JBoss libraries so this is currently not feasible.
- If the user's application is signed (IE: they are running a signed applet persistence client) - they will need to resign the jar.
- In this option we create a global shared library on the server or in a jar-only EAR that is accessible to all server applications.
- This shared library must override the common/lib/ejb3-persistence.jar.
Server Configuration 3:
- no eclipselink.jar into common/lib.
- Add EAR/lib/eclipselink.jar and EAR/lib/javax.persistence_2.0.0.v201002051058.jar
- Reference these two jars in the war/src/META-INF/manifest.MF
- Class-Path: javax.persistence_2.0.0.v201002051058.jar eclipselink.jar
- Getting CCE because the ejb3.persistence.jar on the server is taking precedence by default over the specification jar shipped with the EAR - IE: you cannot have two javax.persistence jars.
- java.lang.ClassCastException: org.eclipse.persistence.jpa.PersistenceProvider cannot be cast to javax.persistence.spi.PersistenceProvider
- Solution would be a similar override as for WebLogic via
<wls:prefer-application-packages>
Client Configuration 3:
- place eclipselink.jar and the jpa 1.0/2.0 specification jar into EAR/lib.
- One of
- jboss-app.xml
- EAR/lib
- application.xml
Results 3:
Server Configuration 4:
Client Configuration 4:
Results 4:
Option 5: Generate an eclipselink jar with the JPA 2.0 dependencies removed
Server Configuration 5:
Client Configuration 5:
Results 5:
Option 6: ship eclipselink and javax.persistence jar only in EAR - infeasible
Server Configuration 6:
- Remove ejb3-persistence.jar from common/lib on the server.
Client Configuration 6:
- add javax.persistence and eclipselink.jar to the EAR/lib directory.
Results 6:
- The JBoss server will not start because the web apps internal to the server require the presence of ejb3-persistence at the global server classpath level.
Option 7: Override common/lib with default/lib for both eclipselink and javax.persistence jars
Server Configuration 7:
- keep the signed ejb3-persistence.jar from common/lib on the server in place.
- copy eclipselink.jar to server/default/lib
- copy javax.persistence spec jar to server/default/lib
Client Configuration 7:
- no changes
Results 7:
- EntityManager and EntityManagerFactory injection on the remote stateless session bean is working fine.
- The JPA war applications that start with the JBoss server deploy fine
- Weaving is unaffected as currently only static weaving is avaible on JBoss
Open Issues
Issue # | Owner | Description / Notes |
---|---|---|
I1 | mobrien | - |
Decisions
Issue # | Description / Notes | Decision |
---|---|---|
Future Considerations
References
- EclipseLink JPA Tutorial EAR for JBoss 5.1.0 and 6.0.0 M1
- EclipseLink JBoss Tutorial EAR, EJB and WAR projects in SVN.
- JBoss Community Post 531496