Nice article Ancoron! I have to say that in principle I prefer dynamic
weaving to build time weaving. This reminds me of the old EJB 2 days
where you had to generate container specific stubs as part of the build
process. I'd rather have container specific stuff generated for me at
deploy time if possible -- less stuff for me to have to keep track.
What I meant by "fragmenting" is, unlike the EJB3 world, there is some
dependency on which OSGi container you select and how you go about
building applications (unless I'm mistaken). For example with Glassfish
you can use CDI but with Aries you use Blueprint. Also with CDI you can
only inject the EntityManagerFactory (Sahoo pointed me to work around
using Interceptors) whereas with Aries you can directly inject a managed
EntityManager so this affects the way you write code.
In the Enterprise OSGi in Action book they use managed JPA with
declarative transactions exclusively in their examples using Blueprint
(Apache Aries 0.4):
package fancyfoods.persistence;
public class InventoryImpl implements Inventory {
private EntityManager em;
public void setEntityManager(EntityManager em) {
this.em = em;
}
}
<bean id="inventory" class="fancyfoods.persistence.InventoryImpl">
<tx:transaction
method="*"
value="Required" />
<jpa:context
property="entityManager"
unitname="fancyfoods" />
</bean>
Whereas Glassfish via CDI:
@Inject @OSGiService(dynamic = true, serviceCriteria =
"(persistence-unit=sample.uas.entities)")
private EntityManagerFactory emf;
so the code becomes more brittle (i.e. have to manually create/close
EntityManager):
EntityManager em = emf.createEntityManager();
try {
em.joinTransaction();
} finally {
em.close();
}
Sahoo suggested using an interceptor as follows:
@AroundInvoke
Object setEM(InvocationContext ctx) throws Exception {
log("entering setEM()");
utx.begin();
em = emf.createEntityManager();
em.joinTransaction();
try {
Object result = ctx.proceed();
utx.commit();
return result;
} catch (Exception e) {
utx.rollback();
throw e;
}
finally {
em.close();
log("exiting setEM()");
}
This a nice work around but its container specific code that I wouldn't
need in Aries for example making my code non-portable which makes me
sad. IMHO for Enterprise OSGi to take off mainstream issues like this
need to be resolved. OSGi applications need to support managed JPA,
declarative transactions and security as transparently and as portably
as EJB3.
In regards to Hibernate vs EclipseLink. Is it possible to use Hibernate
enhanced classes from external bundles? I did a proof of concept using
Hibernate 4 where I embedded all the 3rd party libraries it needed
within the bundle (WHAT A PITA!) along with the JPA entity classes,
persistence.xml and a simple EJB service I got it to work but I never
shared the entity classes outside the bundle. For example if I had a
service bundle and a web bundle could the service bundle return JPA
entities from an OSGi service to the web bundle safely (e.g. lazy
associations, 2nd level caching).
Thanks for your help!
References:
http://aries.apache.org/modules/jpaproject.html
http://www.manning.com/cummins/SourceCodeEnterpriseOSGiinAction.zip
p.s. In case it helps anyone here is my Maven Felix bundle plugin
settings for creating a Hibernate bundle. I had a hell of time getting
it to embed all the libraries AND generate the proper Import-Package. I
could either get one or the other working but not both. In order to get
the libraries embedded I had to manually set the Import-Package myself.
I'm sure I am doing something wrong but I gave up for now.
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.6</version>
<extensions>true</extensions>
<configuration>
<excludeDependencies>false</excludeDependencies>
<instructions>
<!-- Read all
OSGi configuration info from this optional file -->
<_include>-osgi.properties</_include>
<Embed-Directory>lib</Embed-Directory>
<Embed-Dependency>*;scope=runtime</Embed-Dependency>
<Embed-Transitive>false</Embed-Transitive>
<Export-Package>!*</Export-Package>
<Import-Package>!*,javax.ejb,javax.persistence,javax.persistence.criteri
a,javax.persistence.metamodel,javax.persistence.spi,javax.naming,javax.n
aming.event,javax.servlet,javax.servlet.annotation,javax.servlet.http,ja
vax.sql,javax.transaction,javax.validation,javax.validation.constraints,
javax.validation.groups,javax.validation.metadata,javax.validation.spi,j
avax.xml.bind,javax.xml.transform,org.osgi.framework,org.slf4j,org.xml.s
ax</Import-Package>
</instructions>
</configuration>
</plugin>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.hibernate.common</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>antlr</groupId>
<artifactId>antlr</artifactId>
<version>2.7.7</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.15.0-GA</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.1.0.CR2</version>
<scope>runtime</scope>
</dependency>
</dependencies>