Hi Kirk,
please see my comments inline...
On 02/27/2012 04:45 PM, Kirk Rasmussen wrote:
> Wow thanks Ancoron for the insight into different solutions. As a newbie
> to OSGi I find the JPA stuff the most confusing of all since it involves
> lazy loading/class weaving/transactions/etc. and wasn't sure how it
> would affect runtime behavior by splitting the bundles.
In OSGi it's pretty simple: each bundle (unless it is a so-called
"fragment") get's it's very own ClassLoader and represents a separate
"module", which has dependencies (what-do-I-need?) and capabilities
(what-do-I-provide?). Once you've understood this basic principle it's
quite easy and straight forward.
In JPA it is a completely different lifecycle which doesn't match to
OSGi per-se: as longas an entity is "managed" updates to it will most
likely trigger some SQL once the transaction completes (or you use
auto-commit). So, one could say that OSGi just provides the
"what-is-where" layer here, and JPA does the "when-and-how" stuff.
However, besides that when using JPA in GlassFish it usually tries to
weave your entities on-the-fly using dynamic weaving. This causes some
trouble sometimes as during the deployment of such a hybrid bundle as
additional classes are required which are not required by the bundle in
the first place (OSGi package dependencies vs. JPA implementation
weaving requirements for classes).
Therefore, I usually weave all my entity classes statically at build
time and have all the additional dependencies directly inside my
bundles' "Import-Package" header. This is not portable, but as long as I
know which JPA implementation I am going to use at runtime, I don't care.
For this, see my little article at github:
https://github.com/ancoron/osgi-tests/wiki/Shared-JPA-entity-classes-using-OSGi-in-GlassFish-3.1
>
> I haven't really used EJB since the EJB 2 days as I've been using Spring
> pretty much exclusively but I find the Java EE 6 hybrid approach very
> compelling in the OSGi context. I've been reading Enterprise OSGi in
> Action book but they use Blueprint and Apache Aries for the JPA
> container.
From my perspective, if you've got a GlassFish and its "hybrid"
capabilities you don't need to use the OSGi blueprint stuff. I used it
just one time now and that was for integrating a third-party component
into OSGi properly, without too much of code-patching. If you have
control over your projects I would recommend to stick with the JavaEE 6
stuff (annotations and code).
>
> It seems like the JPA solutions are fragmenting which has me a bit
> worried from a standardization perspective.
What do you mean by "fragmenting"? I used Hibernate previously as it was
the "de-facto" standard, but as GlassFish 3 came out and included
EclipseLink for JPA 2.0 I immediately switched over. I am also trying to
stick to official standard API's but in every bigger project I came
across in the past years, I always ended up having to use proprietary
APIs or implementation specific things. However, with OSGi and fragment
bundles, this is not a big deal to provide support for multiple
implementations, if you want (or need) to.
Cheers,
Ancoron
>
> -----Original Message-----
> From: Ancoron Luciferis [mailto:ancoron.luciferis_at_googlemail.com]
> Sent: Saturday, February 25, 2012 10:57 AM
> To: users_at_glassfish.java.net
> Cc: Kirk Rasmussen
> Subject: Re: OSGi Java EE hybrid example split into modules best
> practices
>
> Hi Kirk,
>
> sorry for hijacking this thread a bit but I wanted to return to your
> initial question of separating entities from business services.
>
> I have done exactly that and use it in production already. I already did
> it in different ways:
>
> 1.) Separate entity classes (by their respective concerns) into several
> bundles
>
> 2.) Have one or more bundles for "common" entity stuff (e.g. interfaces,
> abstract classes = MappedSuperclass, ...)
>
> Now comes the difference in my approaches:
>
>
> 1st approach: only one EntityManager
>
> 3.a) Business Service implemented as a EJB:
>
> 4.a) Use a single EntityManager for all entities used by this business
> service, regardless of their bundle origin (only works if all can use
> the same datasource/persistence-unit), using the standard
> @PersistenceContext annotation
>
> 5.a) a single persistence.xml inside the business service bundle
>
>
> 2nd approach: one EntityManager per unit
>
> 3.b) Business Service implemented as a EJB:
>
> 4.b) Use multiple EntityManagers for each entity bundle used by this
> business service, respecting their bundle origin using the standard
> @PersistenceContext annotation and providing the "unitName" attribute
>
> 5.b) a single persistence.xml inside the business service bundle
>
>
> 3rd approach: separate JPA EJBs
>
> 3.c) Business Service implementation whatever you like
>
> 4.c) Separate persistence EJB inside entity bundles (actually making
> them hybrid bundles too), each having its own persistence.xml and their
> limited scope of entities to deal with.
>
>
> However, for each of the approaches you have to keep some things in
> mind:
>
> The first approach is the most easy/lightweight one, but involves having
> no clear separation of concerns and people tend to cross the borders
> between those entity bundles, if they can (direct Java relationship
> between entities of different origin, clear build order problems, cyclic
> dependencies, QA trouble, ...).
>
> The second approach will involve XA transactions when you implement
> business functionality that uses multiple entity managers in one
> transaction.
>
> The third approach will provide the best separation of concerns as you
> also control with the separate EJB what an outside user can actually do
> with your entities.
>
> As a test I also took this one step further and introduced good-old DTOs
> implementing the same interfaces for the outside users (so they don't
> even see that I'm using JPA or whatever I use internally to manage
> persistence). This way I make sure that modification of an object
> instance I give to the outer user does not implicitly trigger the entity
> manager and also that I don't have unexpected updates/inserts once the
> outer transaction (if there is any) commits.
>
> Also this provides the user of my persistence with a guaranteed
> reliability, as only I can control the lifecycle of entities, caching,
> lazy-loading, ... , including ensuring the load-modify-save principle
> (I've lately seen quite some applications not caring about the "load"
> part, just creating new entities, set some values and expect the JPA
> implementation to do the right thing - in all cases).
>
>
> This may be a bit overly complex but it solves a lot of problems when
> you don't know how others will use your stuff (or how many layers will
> be there on top of yours, or which transactional characteristics they
> may apply - or not).
>
>
> I hope this didn't produce confusion.
>
> Cheers,
>
> Ancoron
>
>
> On 02/21/2012 07:18 PM, Kirk Rasmussen wrote:
>> Hello,
>>
>> I am very interested in the hybrid Java EE approach to OSGi that
>> Glassfish supports to leverage declarative security and transaction
>> propagation available in Java EE. I was able to get the EclipseCon
>> demo app working fine.
>>
>> I was wondering if it is possible to split up the EJB and JPA
> portions.
>> In other words I would like to have a persistence bundle that contains
>
>> the entities with all the goodies (sharable, lazy loaded, 2^nd level
>> cache) and a separate EJB service bundle.
>>
>> A more realistic service API would leverage Entities and not just Java
>
>> primitives like Strings. For example, let's say the 'UserAuthService'
>> added a new method:
>>
>> public interface UserAuthService {
>>
>> ...
>>
>> // EJB impl would have @RolesAllowed("admin") applied
>>
>> public User lookup(String name)
>>
>> }
>>
>> So now the common bundle would have a dependency on the Entity User.
>> Seems logical to move this to another package / bundle, e.g.
>> eclipsecon2011.osgieehol.persistence. From my understanding
>> http://glassfish.java.net/public/GF-OSGi-Features.pdf the JPA bundle
>> must include both the entities and the META-INF/persistence.xml file
>> which I did.
>>
>> Now the EJB bundle only contains 'UserAuthServiceEJB' which I modified
>
>> to lookup the EntityManager as an OSGi service (@PersistenceContext
>> didn't work):
>>
>> @Stateless
>>
>> public class UserAuthServiceEJB implements UserAuthService
>>
>> {
>>
>> //_at_PersistenceContext
>>
>> @Inject @OSGiService(dynamic=true)
>>
>> private EntityManager em;
>>
>> ....
>>
>> }
>>
>> But it's not able to locate the JPA EntityManager
>>
>> [#|2012-02-21T12:06:21.679-0600|WARNING|glassfish3.1.2|javax.enterpris
>> e.system.container.ejb.com.sun.ejb.containers|_ThreadID=26;_ThreadName
>> =Thread-4;|EJB5184:A system exception occurred during an invocation on
>
>> EJB UserAuthServiceEJB, method: public boolean
>> eclipsecon2011.osgieehol.ejb_service.impl.UserAuthServiceEJB.login(jav
>> a.lang.String,java.lang.String)|#]
>>
>> Caused by: java.lang.NullPointerException
>>
>> at
>> eclipsecon2011.osgieehol.ejb_service.impl.UserAuthServiceEJB.login(Use
>> rAuthServiceEJB.java:27)
>>
>> What is the proper way to accomplish this?
>>
>> Thanks!
>>
>> "Do the right thing. It will gratify some people and astonish the
> rest."
>> - Mark Twain
>>
>