I'm trying to get an OSGi persistence bundle working on WebLogic's built-in Felix framework. As per the WebLogic OSGi documentation, my WebLogic data source test-ds appears to be available as a service within OSGi:
Service 59 - [weblogic.jdbc.common.internal.RemoteDataSource, javax.sql.DataSource, javax.sql.CommonDataSource, java.sql.Wrapper, weblogic.jdbc.extensions.WLDataSource, java.rmi.Remote, weblogic.jdbc.common.internal.DataSourceMetaData, weblogic.common.resourcepool.ObjectLifeCycle, weblogic.jndi.CrossPartitionAware] (pid: n/a)
from Bundle 0 - System Bundle (org.apache.felix.framework), version 5.6.0
Name: test-ds
service.bundleid: 0
service.scope: singleton
I've created a persistence bundle com.test.persistence-bundle with the following entity class:
@Entity
public class TestEntity {
@Id
private Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
... and persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="test-pu" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>osgi:service/test-ds</jta-data-source>
<non-jta-data-source>osgi:service/test-ds</non-jta-data-source>
<class>test.model.TestEntity</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle12cDialect"/>
</properties>
</persistence-unit>
</persistence>
... and manifest:
Manifest-Version: 1.0
Bnd-LastModified: 1556912147017
Build-Jdk: 1.8.0_171
Built-By: roadkill
Bundle-ManifestVersion: 2
Bundle-Name: test-persistence-bundle
Bundle-SymbolicName: com.test.persistence-bundle
Bundle-Version: 1.0.0.SNAPSHOT
Created-By: Apache Maven Bundle Plugin
DynamicImport-Package: org.hibernate.proxy,javassist.util.proxy
Export-Package: test.model;uses:="javax.persistence";version="1.0.0"
Import-Package: javax.persistence;version="[2.2,3)",org.hibernate.proxy;
resolution:=optional,javassist.util.proxy;resolution:=optional
Meta-Persistence: META-INF/persistence.xml
Provide-Capability: osgi.service;effective:=active;objectClass="javax.pe
rsistence.EntityManager";osgi.unit.name=test-pu,osgi.service;effective:
=active;objectClass="javax.persistence.EntityManagerFactory";osgi.unit.
name=test-pu,osgi.service;effective:=active;objectClass="org.apache.ari
es.jpa.template.JpaTemplate";osgi.unit.name=test-pu,osgi.service;effect
ive:=active;objectClass="org.apache.aries.jpa.supplier.EmSupplier";osgi
.unit.name=test-pu
Require-Capability: osgi.extender;osgi.extender="aries.jpa",osgi.service
;effective:=active;objectClass="javax.persistence.spi.PersistenceProvid
er";javax.persistence.provider="org.hibernate.jpa.HibernatePersistenceP
rovider",osgi.service;effective:=active;objectClass="javax.transaction.
TransactionManager",osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
Tool: Bnd-4.2.0.201903051501
I've also created a client bundle com.test.service-impl which implements TestService from another bundle:
@Component(service = TestService.class)
public class TestServiceImpl implements TestService {
@PersistenceContext(unitName = "test-pu")
EntityManager em;
@Override
public void foo() {
System.out.println(em);
}
}
The EntityManager instance should be injected via the blueprint for the service implementation:
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:jpa="http://aries.apache.org/xmlns/jpa/v2.0.0" xmlns:tx="http://aries.apache.org/xmlns/transactions/v2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 https://osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
<jpa:enable />
<tx:enable />
<bean id="testService" class="test.service.impl.TestServiceImpl"/>
<service ref="testService" interface="test.service.TestService"/>
</blueprint>
However, em is always null. It seems the EntityManager services are never started even though all bundles are Active. I get the following message when updating com.test.service-impl:
13:20:36.380 [Blueprint Extender: 1] INFO org.apache.aries.blueprint.container.BlueprintContainerImpl - Blueprint bundle com.test.service-impl/1.0.0.SNAPSHOT is waiting for dependencies [(&(osgi.unit.name=test-pu)(objectClass=javax.persistence.EntityManager))]
13:20:36.380 [Blueprint Extender: 1] DEBUG org.apache.aries.blueprint.container.BlueprintEventDispatcher - Sending blueprint container event BlueprintEvent[type=GRACE_PERIOD, dependencies=[(&(osgi.unit.name=test-pu)(objectClass=javax.persistence.EntityManager))]] for bundle com.test.service-impl/1.0.0.SNAPSHOT
I'm using Aries JPA to wire everything together with Hibernate as the persistence provider. I also have Aries Blueprint and Aries Transaction installed along with all required dependencies.
Here are the relevant bundles from my bundlelist:
com.test.persistence-api (1.0.0.SNAPSHOT) "test-persistence-api" [active, 23]
com.test.persistence-bundle (1.0.0.SNAPSHOT) "test-persistence-bundle" [active, 25]
com.test.service-impl (1.0.0.SNAPSHOT) "test-service-impl" [active, 21]
javax.persistence-api (2.2) "Java(TM) Persistence API jar" [active, 45]
javax.transaction-api (1.2) "javax.transaction API" [active, 10]
javax.transaction-api (1.3) "javax.transaction API" [active, 18]
org.apache.aries.blueprint.annotation.impl (1.0.1) "Apache Aries Blueprint Annotation Impl" [active, 32]
org.apache.aries.blueprint.core (1.10.2) "Apache Aries Blueprint Core" [active, 19]
org.apache.aries.jpa.api (2.7.2) "Apache Aries JPA Container API" [active, 44]
org.apache.aries.jpa.blueprint (2.7.2) "Apache Aries JPA blueprint" [active, 22]
org.apache.aries.jpa.container (2.7.2) "Apache Aries JPA container" [active, 64]
org.apache.aries.jpa.javax.persistence_2.1 (2.7.2) "Apache Aries JPA Specification 2.1 API" [active, 67]
org.apache.aries.jpa.support (2.7.2) "Apache Aries JPA support" [active, 66]
org.apache.aries.proxy (1.1.4) "Apache Aries Proxy Service" [active, 70]
org.apache.aries.transaction.blueprint (2.2.0) "Apache Aries Transaction Blueprint" [active, 52]
org.apache.aries.transaction.manager (1.3.3) "Apache Aries Transaction Manager" [active, 34]
org.apache.aries.util (1.1.3) "Apache Aries Util" [active, 30]
org.hibernate.common.hibernate-commons-annotations (5.1.0.Final) "hibernate-commons-annotations" [active, 56]
org.hibernate.orm.core (5.3.10.Final) "hibernate-core" [active, 31]
org.hibernate.orm.core (5.4.2.Final) "hibernate-core" [active, 29]
org.hibernate.orm.osgi (5.4.2.Final) "hibernate-osgi" [active, 59]
org.osgi.service.blueprint (1.0.2.201505202024) "org.osgi:org.osgi.service.blueprint" [active, 27]
org.osgi.service.cm (1.5.0.201505202024) "org.osgi:org.osgi.service.cm" [active, 6]
org.osgi.service.coordinator (1.0.2.201505202024) "org.osgi:org.osgi.service.coordinator" [active, 73]
org.osgi.service.jdbc (1.0.0.201505202023) "org.osgi:org.osgi.service.jdbc" [active, 37]
org.osgi.util.function (1.1.0.201802012106) "org.osgi:org.osgi.util.function" [active, 65]
org.osgi.util.promise (1.1.1.201810101357) "org.osgi:org.osgi.util.promise" [active, 17]
Any ideas?
Thanks in advance!
TL;DR: It turns out this was due to a bug in the version of Felix that WebLogic ships with. I was able to upgrade the framework by simply replacing
\wlserver\server\lib\org.apache.felix.org.apache.felix.main.jarand\wlserver\server\lib\osgi.jarwith the latest versions of felix-main and osgi-core, respectively.While trying to figure out the source of the issue, I ended up downloading and manually reading through Karaf's
jpa,transaction, andhibernatefeatures to ensure all of the proper bundles were installed and started in the correct order. WebLogic allows you to specify start levels by placing bundles inside of subdirectories within theosgi-libfolder. I'm not sure how helpful this was in the long run, but it gave me some confidence that things were set up in a verified way.Here's the list of bundles, with versions and start levels, that I gathered from the Karaf features (not shown: logging/console/shell stuff):
I also made some changes to the OSGi framework configuration itself via the WebLogic console:
sun.*andcom.sun.*are definitely needed to avoidClassNotFoundExceptions from bytebuddy:Lastly, it appears WebLogic sets the
nameproperty of the published DataSource service to the JNDI name of the data source itself. Thus, the full value forjta-data-sourceshould be something like:Hope this helps.