2015-04-24 2 views
3

Я погружался в ServiceMix 5.4.0 и OSGi и столкнулся с довольно странным поведением с OpenJPA.ServiceMix не может найти источник данных OSGI

У меня есть источник данных, определенный как так:

<blueprint 
     xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"> 

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 
     <property name="driverClassName" value="org.postgresql.Driver"/> 
     <property name="url" value="jdbc:postgresql://localhost:5432/test"/> 
     <property name="username" value="test"/> 
     <property name="password" value="test"/> 
    </bean> 

    <service interface="javax.sql.DataSource" ref="dataSource"> 
     <service-properties> 
     <entry key="osgi.jndi.service.name" value="jdbc/test"/> 
     </service-properties> 
    </service> 
</blueprint> 

Использование JNDI: имена команд, я могу подтвердить, что источник данных видно:

[email protected]> jndi:names 
JNDI Name   Class Name             
osgi:service/jndi org.apache.karaf.jndi.internal.JndiServiceImpl    
osgi:service/jdbc/test org.apache.commons.dbcp.BasicDataSource      
[email protected]> 

Мой persistence.xml:

<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="test" transaction-type="JTA">    
     <jta-data-source>osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/test)</jta-data-source> 

     <class>com.example.persistence.security.User</class> 

     <exclude-unlisted-classes>true</exclude-unlisted-classes> 

     <properties> 
      <property name="openjpa.jdbc.DBDictionary" value="postgres"/>      
      <property name="openjpa.Log" value="slf4j"/> 
     </properties> 
    </persistence-unit> 
</persistence> 

Затем я вставляю блок непрерывности в класс DAO по схеме:

<?xml version="1.0" encoding="UTF-8"?> 

<blueprint default-activation="eager" 
      xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" 
      xmlns:jpa="http://aries.apache.org/xmlns/jpa/v1.0.0" 
      xmlns:tx="http://aries.apache.org/xmlns/transactions/v1.0.0"> 

    <bean id="securityDAO" class="com.example.security.dao.SecurityDAOImpl" init-method="init"> 
     <tx:transaction method="*" value="Required" /> 
     <jpa:context property="entityManager" unitname="test" /> 
    </bean> 

    <service ref="securityDAO" interface="com.example.security.dao.SecurityDAO"> 
    </service> 


</blueprint> 

Блок инерционность успешно введен, который я проверяю в Init-метода в DAO:

public void init() { 
    if (em==null) { 
     log.error("Entity manager not found. Check JPA configuration."); 
     throw new RuntimeException("No EntityManager found"); 
    } 

    log.info("Started SecurityDAO"); 
} 

После всей моей кропотливой работы, ServiceMix вознаграждает меня со следующим загадочным исключением, когда я называю метод моего DAO от другого боба:

.... 
public void setSecurityDAO (SecurityDAO dao) { 
    this.dao = dao; 
} 

@Override 
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
    String userName = req.getParameter("userName"); 
    String password = req.getParameter("password"); 

    // Invocation of injected DAO results in exception 
    User u = dao.authenticateUser(userName, password);   

Это приводит к следующему:

Caused by: java.lang.RuntimeException: The DataSource osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/test) required by bundle persistence/0.0.1.SNAPSHOT could not be found. 
    at org.apache.aries.jpa.container.unit.impl.JndiDataSource.getDs(JndiDataSource.java:87) 
    at org.apache.aries.jpa.container.unit.impl.DelayedLookupDataSource.getConnection(DelayedLookupDataSource.java:36) 
    at org.apache.openjpa.lib.jdbc.DelegatingDataSource.getConnection(DelegatingDataSource.java:116) 
    at org.apache.openjpa.lib.jdbc.DecoratingDataSource.getConnection(DecoratingDataSource.java:93) 
    at org.apache.openjpa.jdbc.schema.DataSourceFactory.installDBDictionary(DataSourceFactory.java:233) 
    ... 54 more 
Caused by: javax.naming.NoInitialContextException: Unable to find the InitialContextFactory org.eclipse.jetty.jndi.InitialContextFactory. 
    at org.apache.aries.jndi.ContextHelper.getInitialContext(ContextHelper.java:148) 
    at org.apache.aries.jndi.OSGiInitialContextFactoryBuilder.getInitialContext(OSGiInitialContextFactoryBuilder.java:49) 
    at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684) 
    at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313) 
    at javax.naming.InitialContext.init(InitialContext.java:244) 
    at javax.naming.InitialContext.<init>(InitialContext.java:216) 
    at org.apache.aries.jpa.container.unit.impl.JndiDataSource.getDs(JndiDataSource.java:64) 
    ... 58 more 

Каким-то образом источник данных, экспортируемый OSGi, не находит своего пути в набор персистентности. Странная часть заключается в том, что, когда я добавил следующий код в init-метод, чтобы увидеть, могу ли я выполнить тестовый запрос, не только OpenJPA не генерирует исключение в методе init, а вызов DAO, который запускает исключение сейчас работы, а также:

public void init() { 
    if (em==null) { 
     log.error("Entity manager not found. Check JPA configuration."); 
     throw new RuntimeException("No EntityManager found"); 
    } 

    try { 
     Query q = em.createNativeQuery("SELECT 1=1");   
     q.getFirstResult();   
    } catch (Exception ex) { 
     log.error("Unable to execute test query against database", ex); 
     throw new RuntimeException(ex); 
    } 

    log.info("Started SecurityDAO"); 
} 

Итак, подведем итоги: Если я вызываю метод из другого пучка, чем мой DAO, OpenJPA бросает исключение, указывающее, что он не может найти InitialNamingContext, и не показывает никаких признаков в журнал, который он запустил. Если я выполняю запрос внутри своего DAO до того, как в него поступит внешний компонент, как-то OpenJPA сможет найти InitialNamingContext, OpenJPA появляется в журнале, а последующие вызовы извне пакета DAO начинают работать.

Очевидно, что здесь отсутствует что-то основное. Любая помощь или продуманное объяснение того, что ломается, или то, что я делаю неправильно, будет с благодарностью.

EDIT:

я не заметил прошлой ночью, но когда я добавил в тестовом запросе, следующие строки отображаются в журнале. Они отсутствуют, когда я закомментировать этот запрос:

... | Runtime | 220 - org.apache.openjpa - 2.3.0 | Starting OpenJPA 2.3.0 
... | JDBC | 220 - org.apache.openjpa - 2.3.0 | Using dictionary class "org.apache.openjpa.jdbc.sql.PostgresDictionary". 
... | JDBC | 220 - org.apache.openjpa - 2.3.0 | Connected to PostgreSQL version 9.9 using JDBC driver PostgreSQL Native Driver version PostgreSQL 9.3 JDBC4.1 (build 1102). 

EDIT 2:

Пробовал его на равнине ванильного Karaf 3.0.3, и получил ту же ошибку. В качестве обходного пути я создал отдельный компонент в комплекте, который выполняет вышеупомянутый тестовый запрос. По-видимому, до тех пор, пока один компонент в пакете вызывает вызов OpenJPA, прежде чем компонент, находящийся за пределами пакета, попытается выполнить вызов, OpenJPA будет правильно инициализирован.

Поскольку это нигде не видно в документах OpenJPA/ServiceMix, я могу только предположить, что я что-то делаю неправильно в другом месте в моей конфигурации.

EDIT 3:

Per John Forth, вот MANIFEST.MF

Manifest-Version: 1.0 
Bnd-LastModified: 1430533396366 
Build-Jdk: 1.8.0_45 
Built-By: somedude 
Bundle-Blueprint: OSGI-INF/blueprint/blueprint.xml 
Bundle-Description: Database access layer for Peer Review product 
Bundle-ManifestVersion: 2 
Bundle-Name: Example :: Persistence 
Bundle-SymbolicName: persistence-jpa 
Bundle-Version: 0.0.1.SNAPSHOT 
Created-By: Apache Maven Bundle Plugin 
Export-Package: com.example.persistence.security;version="0.0.1.SNAPSHOT",co 
m.example.security.dao;version="0.0.1.SNAPSHOT";uses:="com.example.persistence. 
security,javax.persistence" 
Export-Service: com.example.security.dao.SecurityDAO 
Import-Package: javax.persistence;version="[1.1,2)",org.osgi.service.blu 
eprint;version="[1.0.0,2.0.0)",org.slf4j;version="[1.7,2)" 
Meta-Persistence: META-INF/persistence.xml 
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.7))" 
Tool: Bnd-2.3.0.201405100607 

И, так как это может быть связано, то pom.xml расслоения JPA:

<?xml version="1.0" encoding="UTF-8"?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <parent> 
     <artifactId>example</artifactId> 
     <groupId>com.example</groupId> 
     <version>0.0.1-SNAPSHOT</version> 
    </parent> 

    <artifactId>persistence-jpa</artifactId> 
    <packaging>bundle</packaging> 

    <name>Example :: Persistence</name> 

    <dependencies> 
     <dependency> 
      <groupId>org.apache.geronimo.specs</groupId> 
      <artifactId>geronimo-jpa_2.0_spec</artifactId> 
      <version>1.1</version> 
     </dependency> 

     <dependency> 
      <groupId>org.slf4j</groupId> 
      <artifactId>slf4j-api</artifactId> 
      <version>1.7.7</version> 
     </dependency> 
    </dependencies> 

    <build> 
     <plugins> 
      <plugin> 
       <artifactId>maven-compiler-plugin</artifactId> 
       <version>3.3</version> 
       <configuration> 
        <source>1.7</source> 
        <target>1.7</target> 
       </configuration> 
      </plugin> 

      <plugin> 
       <groupId>org.apache.felix</groupId> 
       <artifactId>maven-bundle-plugin</artifactId> 
       <version>2.5.3</version> 
       <extensions>true</extensions> 
       <configuration> 
        <instructions> 
         <Meta-Persistence>META-INF/persistence.xml</Meta-Persistence> 
         <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> 
         <Bundle-Version>${project.version}</Bundle-Version>      
         <Import-Package>*</Import-Package> 
         <Export-Package>com.example.persistence*,com.example.security.*;version=${project.version}</Export-Package> 
        </instructions> 
       </configuration> 
      </plugin> 
     </plugins> 
    </build> 
</project> 
+0

Не могли бы вы разместить МАНИФЕСТ.МФ вашего набора настойчивости? –

ответ

0

Если вы используете OSGI, видимость класса определяется в файлах MANIFEST.MF.

Таким образом, набор персистентности может видеть и загружать классы, которые импортируются в его MANIFEST.MF.

Правильный способ расширения существующего пакета - определить фрагмент, который прикреплен к существующему пакету. Таким образом, вы можете предоставить классы (например, DAO) и файлы (например, persistence.xml) и сделать видимыми для узла-фрагмента.

MANIFEST.MF тогда выглядит

Bundle-ManifestVersion: 2 
Bundle-Name: foo.bar.openjpa-fragment 
Bundle-SymbolicName: foo.bar.openjpa-fragment;singleton:=true 
Bundle-Version: 0.0.1.SNAPSHOT 
Bundle-Vendor: foo bar 
Fragment-Host: org.apache.openjpa-bundle 
Bundle-ClassPath: . 

Обратите внимание, что это всего лишь пример.

OSGI предназначен для обеспечения надлежащей видимости.

Вы можете добавить более одного фрагмента в существующий пакет, например. чтобы сохранить конфигурацию в отдельном комплекте, что упрощает настройку конфигурации.

+0

Непонятно, как это переводится для меня ... Я определяю пакет с некоторыми сущностями, DAO или тремя и persistence.xml, который затем ссылается на службу CXF в другом комплекте. Должен ли я структурировать свой проект JPA, чтобы объекты и DAO были фрагментами, связанными с пакетом OpenJPA? – McCroskey

+0

Точно. DAO должны быть фрагментом, присоединенным к пакету OpenJPA, иначе пакет OpenJPA не может видеть и загружать эти классы. – bebbo

Смежные вопросы