Hello Xfire Web Services and OSGi

0

源起

除了直接接到 spring MVC 來展現網頁之外,對於外部的程式也需要連結,這裡測試 XFire 掛 Spring 的模式來做。

XFire

Chapter 17.5. Web Services

XFire Spring support

XFire JSR 181 Annotations

做法

xfire 有支援 spring ,他將一些預設定義放在 classpath:org/codehaus/xfire/spring/xfire.xml, 不過它是 spring 1.x 版本,即使設定 eclipse buddy 機制取得這個檔,也需要修改,索性直接將這個 檔放到需要的包中。

主要實做下面幾包 bundle 來用。

  1. haha.remix.xfire
  2. haha.hello.ws.userdao
  3. haha.hello.ws.client

haha.remix.xfire

這是個大轉包,沒有加程式,只是改 MANIFEST.MF 來協助。

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: haha.remix.xfire
Bundle-SymbolicName: haha.remix.xfire
Bundle-Version: 1.0.0
Bundle-Activator: haha.remix.xfire.Activator
Bundle-Localization: plugin
Import-Package: javax.servlet;version="2.4.0",
 javax.servlet.http;version="2.4.0",
 org.apache.commons.logging,
 org.osgi.framework;version="1.3.0" 
Bundle-ClassPath: lib/wstx-asl-3.1.0.jar,
 lib/stax-api-1.0.1.jar,
 lib/wsdl4j-1.5.2.jar,
 lib/xfire-all-1.2.2.jar,
 lib/xfire-jsr181-api-1.0-M1.jar,
 .,
 lib/activation-1.1.jar,
 lib/jdom-1.0.jar,
 lib/XmlSchema-1.1.jar
Export-Package: com.ctc.wstx.stax,
 javax.jws,
 javax.xml.stream,
 org.apache.ws.commons.schema,
 org.codehaus.stax2,
........[skip]
Require-Bundle: org.apache.commons.httpclient;resolution:=optional,
 org.apache.commons.codec;resolution:=optional,
 haha.remix.spring;resolution:=optional

這裡需注意 require bundle 都是選擇性的,那是因為有些特定需求要到客端包要求的時候,才會需要, 也不一定會有這些客端包,所以一直掛著讓他一定要這個附屬包也說不過去,所以用選擇性掛上。

haha.hello.ws.userdao

META-INF/spring/bean.xml

<osgi:reference id="httpService" 
  interface="org.osgi.service.http.HttpService"/>

<bean name="servletRegister" 
   class="haha.hello.ws.userdao.ServletRegister" init-method="init">
      <property name="httpService" ref="httpService"/>
</bean>

haha.hello.ws.userdao.ServletRegister 負責啟動 WEB-INF/xx.xml 與註冊服務到 osgi:reference 的 org.osgi.service.http.HttpService

System.setProperty("javax.xml.stream.XMLInputFactory",
  "com.ctc.wstx.stax.WstxInputFactory");
System.setProperty("javax.xml.stream.XMLOutputFactory",
  "com.ctc.wstx.stax.WstxOutputFactory");
System.setProperty("javax.xml.stream.XMLEventFactory",
  "com.ctc.wstx.stax.WstxEventFactory");

DispatcherServlet servlet = new DispatcherServlet();
servlet.setNamespace("hello-servlet");

OsgiWebApplicationContext owac = new OsgiWebApplicationContext();
servlet.setContextClass(owac.getClass());
httpService.registerServlet("/services", servlet, null ,null);

WEB-INF/hello-servlet.xml

<import resource="xfire.xml"/>
<osgi:reference id="userDao" 
     interface="haha.hello.jpa.userdao.UserDao"/>

<bean name="helloImpl" class="haha.hello.ws.userdao.HelloImpl">     
   <property name="userDao" ref="userDao"/>
</bean>

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
   <property name="mappings">
            <value>/hello=wsController</value>
   </property>
</bean>

<bean id="wsController" 
      class="org.codehaus.xfire.spring.remoting.XFireExporter">
        <property name="serviceFactory">
            <ref bean="xfire.annotationServiceFactory"/>
        </property>
        <property name="xfire">
            <ref bean="xfire"/>
        </property>
        <property name="serviceBean">
            <ref bean="helloImpl"/>
        </property>
</bean>

WEB-INF/xfire.xml 取自 xfire classpath:org/codehaus/xfire/spring/xfire.xml 修改一下 singleton 設定而已。

這一包主要將 haha.hello.ws.userdao.Hello 放到 WebServic 去。

haha.hello.ws.userdao.Hello

package haha.hello.ws.userdao;

import javax.jws.WebMethod;
import javax.jws.WebResult;
import javax.jws.WebService;

@WebService(name = "HelloService",  targetNamespace = "http://www.openuri.org/2004/04/HelloWorld")
public interface Hello {
  @WebMethod
  @WebResult
  String getName();
}

haha.hello.ws.userdao.HelloImpl 會注入 osgi:reference 的 haha.hello.jpa.userdao.UserDao 來用。

package haha.hello.ws.userdao;

import haha.hello.jpa.userdao.UserDao;
import javax.jws.WebService;

@WebService(endpointInterface = "haha.hello.ws.userdao.Hello")
public class HelloImpl implements Hello {

 private UserDao userDao;

 private String name = "foo";

 public String getName() {
   return name + userDao.loadUsers().size();
 }
....[SKIP].....

MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: haha.hello.ws.userdao
Bundle-SymbolicName: haha.hello.ws.userdao
Bundle-Version: 1.0.0
Bundle-Activator: haha.hello.ws.userdao.Activator
Bundle-Localization: plugin
Import-Package: com.ctc.wstx.stax,
 javax.jws,
 javax.servlet;version="2.4.0",
 javax.servlet.http;version="2.4.0",
 org.osgi.framework;version="1.3.0",
 org.osgi.service.http;version="1.2.0",
 org.springframework.osgi.context.support
Require-Bundle: haha.remix.spring,
 org.eclipse.equinox.http.jetty,
 haha.hello.jpa.userdao,
 haha.remix.xfire
Export-Package: haha.hello.ws.userdao

啟動後可以直接開瀏覽器到 http://127.0.0.1/services/hello?wsdl 觀察 WSDL

haha.hello.ws.client

陽春型客戶端,只是取用 getName 輸出看看而已,沒有用到 WSDL2JAVA 來轉成 java。

package haha.hello.ws.client;

import java.net.URL;
import org.codehaus.xfire.client.Client;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class Activator implements BundleActivator {

 public void start(BundleContext context) throws Exception {
    Client client = new Client(
            new URL("http://127.0.0.1/services/hello?wsdl"));
        Object[] results = client.invoke("getName",null);
        System.out.println(results[0]);
 }
...[SKIP]....

MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: haha.hello.ws.client
Bundle-SymbolicName: haha.hello.ws.client
Bundle-Version: 1.0.0
Bundle-Activator: haha.hello.ws.client.Activator
Bundle-Localization: plugin
Import-Package: org.apache.commons.logging,
 org.codehaus.xfire.client,
 org.osgi.framework;version="1.3.0" 
Bundle-ClassPath: .
Require-Bundle: org.apache.commons.httpclient,
 org.apache.commons.codec,
 haha.hello.ws.userdao,
 haha.remix.xfire

觀察

  1. 越深入企業層面的應用,越發覺既有程式套件之間的相依性很高,之前用一個 classpath 可以找到, 現在轉 OSGi 變成要考慮匯出匯入問題,變的更為複雜,有時現有套件無法滿足,只好直接轉 remix 大包 來實現或是用 eclipse buddy 機制。
  2. 如果使用 import-package 方式,似乎無法保證某些服務會先啟動,於是將 ws.client 中設定 Require-Bundle 來讓某些服務先滿足。

Hello Spring MVC and OSGi

0

源起

之前已經可以將物件利用 spring+hibernet 存放道資料庫,現要整合到一個網頁服務上, 所以需要練習一下 Spring MVC 的架構,並把 MVC 納入 haha.remix.spring 中。

預計將之前的 jpa 練習的 userdao 拿來注到 controller 之中,然後在網頁中簡單列出來。

Spring OSGi Specification (v0.7) 2.5 Web application support

結果

瀏覽器開到 http://127.0.0.1/foo/index.html 可以看到資料庫輸出。

osgi> ss

Framework is launched.

id    State       Bundle
0    ACTIVE      system.bundle_3.3.0.v20061101
5    ACTIVE      javax.servlet_2.4.0.200609281713
6    ACTIVE      javax.servlet.jsp_2.0.0.200610251427
7    ACTIVE      log4j_1.2.13
9    ACTIVE      org.apache.commons.logging_1.0.4
10    ACTIVE      org.eclipse.equinox.ds_1.0.0.v20060828
12    ACTIVE      org.eclipse.equinox.log_1.0.100.v20060717
13    ACTIVE      org.eclipse.osgi.services_3.1.100.v20060918
75    ACTIVE      org.apache.commons.el_1.0.0
76    ACTIVE      org.apache.jasper_5.5.17.200610251427
77    ACTIVE      org.eclipse.equinox.http.jetty_1.0.0.v20061012
78    ACTIVE      org.eclipse.equinox.http.servlet_1.0.0.v20061023
79    ACTIVE      org.eclipse.equinox.jsp.jasper_1.0.0.200610251427
80    ACTIVE      org.eclipse.equinox.jsp.jstl_1.0.0
81    ACTIVE      org.mortbay.jetty_5.1.11.200609281713
85    ACTIVE      haha.hello.jpa.userdao_1.0.0
87    ACTIVE      haha.remix.derby_1.0.0
88    ACTIVE      haha.remix.hibernate_1.0.0
94    ACTIVE      haha.hello.mvc.userdao_1.0.0
95    ACTIVE      haha.remix.spring_1.0.0

haha.hello.mvc.userdao

首先要先找到 HttpService 來用。

META-INF/spring/bean.xml

<osgi:reference id="httpService" interface="org.osgi.service.http.HttpService"/>
<bean name="servletRegister" class="haha.hello.mvc.userdao.ServletRegister" init-method="init">
   <property name="httpService" ref="httpService"/>
</bean>

haha.hello.mvc.userdao.ServletRegister.java

DispatcherServlet servlet = new DispatcherServlet();
servlet.setNamespace("foo-servlet");
OsgiWebApplicationContext owac = new OsgiWebApplicationContext();
servlet.setContextClass(owac.getClass());
httpService.registerServlet("/foo", servlet, null ,null);

WEB-INF/foo-servlet.xml

<osgi:reference id="userDao" interface="haha.hello.jpa.userdao.UserDao"/>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <value>
                /*.html=fooController
            </value>
        </property>
</bean>
<bean id="fooController" 
      class="haha.hello.mvc.userdao.FooController">
     <property name="userDao" ref="userDao"/>
</bean>

haha.hello.mvc.userdao.FooController.java

PrintWriter out = res.getWriter();
Collection users = userDao.loadUsers();
int count = 0;
for (Iterator iter = users.iterator(); iter.hasNext();) {
 User user = (User) iter.next();            
 out.println("Hello, " + user.getName() + "<BR/>");
}

META-INF/MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: haha.hello.mvc.userdao
Bundle-SymbolicName: haha.hello.mvc.userdao
Bundle-Version: 1.0.0
Bundle-Activator: haha.hello.mvc.userdao.Activator
Bundle-Localization: plugin
Import-Package: haha.hello.jpa.userdao,
 javax.servlet;version="2.4.0",
 javax.servlet.http;version="2.4.0",
 org.osgi.framework;version="1.3.0",
 org.osgi.service.http;version="1.2.0",
 org.springframework.osgi.context.support,
 org.springframework.web.servlet,
 org.springframework.web.servlet.mvc

觀察

  1. 註冊的動作之前都是用 OSGi DS 做法注入,這次用 Spring 的 osgi:reference 注入,同時也將 userdao 服務注入 controller 之中練習。
  2. OsgiWebApplicationContext 提供支援將 context 注入,不然 osgi:reference 無法使用。

Hello Spring Jpa and OSGi

0

源起

之前用 jboss ejb3 包 bundle 不是很順利,於是想用 spring jpa 支援當這個用途, 試看看 EntityManager 利用 spring 注入的方式。

Chapter 12. Object Relational Mapping (ORM) data access

Getting Started With JPA in Spring 2.0

Using JPA in Spring without referencing Spring

議題

先直接用 spring-osgi 包好的 bundle 來測,不過測試過程中不是很順利,目前 spring-osgi 所用到的 bundle 很多,但是 package 相依性還沒有調好,有些需要用 eclipse buddy 方式來轉包,既然要一個個轉包 (dao/jdbc/beans..),就直接包一起變成比較大包的 haha.remix.spring。

OSGi console 結果
osgi> ss

Framework is launched.

id    State       Bundle
0    ACTIVE      system.bundle_3.3.0.v20061101
5    ACTIVE      javax.servlet_2.4.0.200609281713
9    ACTIVE      org.apache.commons.logging_1.0.4
10    ACTIVE      org.eclipse.equinox.ds_1.0.0.v20060828
12    ACTIVE      org.eclipse.equinox.log_1.0.100.v20060717
13    ACTIVE      org.eclipse.osgi.services_3.1.100.v20060918
18    ACTIVE      org.springframework.osgi_2.0.0
68    ACTIVE      haha.hello.jpa.userdao_1.0.0
69    ACTIVE      haha.hello.jpa.userdao.client_1.0.0
70    ACTIVE      haha.remix.derby_1.0.0
71    ACTIVE      haha.remix.hibernate_1.0.0
73    ACTIVE      haha.remix.spring_1.0.0

haha.remix.spring

META-INF/MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: haha.remix.spring
Bundle-SymbolicName: haha.remix.spring
Bundle-Version: 1.0.0
Bundle-Activator: haha.remix.spring.Activator
Bundle-Localization: plugin
Import-Package: javax.persistence,
 javax.persistence.spi,
 org.apache.commons.logging,
 org.hibernate,
 org.hibernate.ejb,
 org.osgi.framework;version="1.3.0" 
Bundle-ClassPath: lib/spring-beans-2.1-20061103.020011-52.jar,
 .,
 lib/spring-dao-2.1-20061007.091527-15.jar,
 lib/spring-jpa-2.1-20061103.020011-52.jar,
 lib/spring-jdbc-2.1-20061103.020011-52.jar,
 lib/aopalliance.osgi-1.0-20061103.020011-48.jar,
 lib/spring-aop-2.1-20061103.020011-52.jar,
 lib/spring-context-2.1-20061103.020011-52.jar,
 lib/spring-core-2.1-20061103.020011-52.jar,
 lib/spring-web-2.1-20061103.020011-52.jar
Export-Package: org.aopalliance.aop,
 org.springframework.aop;version="2.1.0",
 org.springframework.aop.framework;version="2.1.0",
 org.springframework.aop.target;version="2.1.0",
 org.springframework.beans;version="2.1.0",
 org.springframework.beans.factory;version="2.1.0",
 org.springframework.beans.factory.config;version="2.1.0",
 org.springframework.beans.factory.parsing;version="2.1.0",
 org.springframework.beans.factory.support;version="2.1.0",
 org.springframework.beans.factory.xml;version="2.1.0",
 org.springframework.context;version="2.1.0",
 org.springframework.context.support;version="2.1.0",
 org.springframework.core;version="2.1.0",
 org.springframework.core.io;version="2.1.0",
 org.springframework.core.io.support;version="2.1.0",
 org.springframework.stereotype;version="2.1.0",
 org.springframework.transaction.annotation;version="2.1.0",
 org.springframework.util;version="2.1.0",
 org.springframework.util.xml;version="2.1.0",
 org.springframework.web.context;version="2.1.0",
 org.springframework.web.context.support;version="2.1.0" 

haha.remix.hibernate

META-INF/MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: haha.remix.hibernate
Bundle-SymbolicName: haha.remix.hibernate
Bundle-Version: 1.0.0
Bundle-Localization: plugin
Bundle-ClassPath: .,
 lib/hibernate3.jar,
 lib/hibernate-annotations.jar,
 lib/ejb3-persistence.jar,
 lib/dom4j-1.6.1.jar,
 lib/commons-collections-2.1.1.jar,
 lib/cglib-2.1.3.jar,
 lib/asm.jar,
 lib/jta.jar,
 lib/ehcache-1.2.jar,
 lib/hibernate-entitymanager.jar,
 lib/javassist.jar,
 lib/jboss-archive-browsing.jar,
 lib/antlr-2.7.6.jar
Import-Package: org.apache.commons.logging,
 org.osgi.framework;version="1.4.0",
 org.osgi.service.component;version="1.0.0",
 org.osgi.service.log;version="1.3.0" 
Export-Package: javax.persistence,
 javax.persistence.spi,
 org.hibernate,
 org.hibernate.ejb,
 org.hibernate.proxy
Eclipse-BuddyPolicy: registered

haha.hello.jpa.userdao

META-INF/MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: haha.hello.jpa.userdao
Bundle-SymbolicName: haha.hello.jpa.userdao
Bundle-Version: 1.0.0
Bundle-Activator: haha.hello.jpa.userdao.Activator
Import-Package: javax.persistence,
 org.apache.derby.jdbc,
 org.hibernate.proxy,
 org.osgi.framework;version="1.4.0",
 org.springframework.stereotype;version="2.1.0",
 org.springframework.transaction.annotation;version="2.1.0" 
Eclipse-RegisterBuddy: haha.remix.hibernate
Export-Package: haha.hello.jpa.userdao

MEAT-INF/spring/bean.xml(部份)

<tx:annotation-driven />
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

<bean id="entityManagerFactory" 
  class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
...
</bean>

<bean id="transactionManager" 
   class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<bean id="userDao" class="haha.hello.jpa.userdao.UserDaoImpl"/>

<osgi:service id="osgiUserDao" ref="userDao" 
    interface="haha.hello.jpa.userdao.UserDao"/>

haha.hello.jpa.userdao.client

MEAT-INF/spring/bean.xml(部份)

<osgi:reference id="userDao" interface="haha.hello.jpa.userdao.UserDao"/>
<bean name="userDaoClient" 
    class="haha.hello.jpa.userdao.client.UserDaoClient" init-method="init">
      <property name="userDao" ref="userDao"/>
</bean>

觀察

  1. 如果沒有加上 @Transactional 的話,DAO 會遭遇 hibernate session 關閉問題。 http://forum.springframework.org/archive/index.php/t-29054.html

Hello Spring OSGi

13

源起

Spring 有廣大的用戶與部署經驗,當然也要試看看,包起來如何運作。

環境部署

因為目前文件尚未完備,bundle 之間相依性很複雜,這裡直接用 simple-service-bundle 來測試,順便看看要載入多少東西。所有的 bundle 除了 OSGi 之外,全部取自下面連結。

http://static.springframework.org/maven2-snapshots/

如何取得服務

這個 bundle 會做兩種存取 simple-service-bundle 的方式的測試,差別在生命週期掌握在誰的手上。

  1. Declarative Services (OSGi SCR)
  2. osgi:reference (Spring Ioc)

關於這兩種做法,摘錄 Spring OSGi Specification (v0.7) 的說法如下。

http://www.springframework.org/osgi/specification

Spring-OSGi enabled bundles can co-exist happily with bundles using DS, 
but for new bundle development we recommend the use of the Spring OSGi 
support in place of DS.

下面是設定檔的部份。

META-INF/MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: haha.foo
Bundle-SymbolicName: haha.foo
Bundle-Version: 1.0.0
Bundle-Localization: plugin
Import-Package: org.osgi.service.component;version="1.0.0",
 org.osgi.service.log;version="1.3.0",
 org.springframework.osgi.samples.simpleservice
Service-Component: OSGI-INF/reference.xml
Require-Bundle: org.springframework.osgi

OSGI-INF/reference.xml

<?xml version="1.0" encoding="UTF-8"?>
<component name="haha.foo.Component">
  <implementation class="haha.foo.Component"/>
  <reference name="LOG" interface="org.osgi.service.log.LogService" 
    cardinality="1..1" bind="setLog" unbind="unsetLog" policy="static"/>
  <reference name="MYSERVICE" 
    interface="org.springframework.osgi.samples.simpleservice.MyService" 
    cardinality="1..1" bind="setMyService" unbind="unsetMyService" 
    policy="static"/>
</component>

META-INF/spring/bean.xml

<osgi:reference id="myService" 
  interface="org.springframework.osgi.samples.simpleservice.MyService"/>
<bean name="foobean" class="haha.foo.Bean">
    <property name="myService" ref="myService"/>
</bean>

結果

osgi> ss

Framework is launched.

id    State       Bundle
0    ACTIVE      system.bundle_3.3.0.v20061023
4    ACTIVE      org.eclipse.equinox.ds_1.0.0.v20060828
5    ACTIVE      org.eclipse.equinox.log_1.0.100.v20060717
6    ACTIVE      org.eclipse.osgi.services_3.1.100.v20060918
8    ACTIVE      org.apache.commons.logging_1.0.4
10    ACTIVE      log4j_1.2.13
11    ACTIVE      org.aopalliance_1.0.0
12    ACTIVE      org.springframework.aop_2.0.0
13    ACTIVE      org.springframework.beans_2.0.0
14    ACTIVE      org.springframework.context_2.0.0
15    ACTIVE      org.springframework.core_2.1.0
16    ACTIVE      org.springframework.osgi_2.0.0
20    ACTIVE      haha.foo_1.0.0
21    ACTIVE      org.springframework.osgi.samples.simpleservice_1.0.0

觀察

  1. 覺得由 spring 來存取比目前 ds 方便,spring-osgi 讓你兩種方法都可以用,很有彈性,這也代表很容易嵌入現有的 OSGi (例如 RCP) 架構中使用。

Rebundle hibernate3.2

0

源起

想要加上 ORM 這一層,同時練習一下 javax.persistence 與 EntityManager 的用法。 所以下面會包成兩包,一包是 haha.hibernate,一包是 haha.helloem。

關於資料庫的部份請參考之前作法 Rebudle Derby

部分參考連結 :

An Introduction to Java Persistence for Client-Side Developers

Hibernate EntityManager

haha.hibernate

包這個主要將相依的東西納入即可,同時匯入需要的 jdbc 等類別。

META-INF/MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: haha.hibernate
Bundle-SymbolicName: haha.hibernate
Bundle-Version: 1.0.0
Bundle-Localization: plugin
Bundle-ClassPath: .,
 lib/hibernate3.jar,
 lib/hibernate-annotations.jar,
 lib/ejb3-persistence.jar,
 lib/dom4j-1.6.1.jar,
 lib/commons-collections-2.1.1.jar,
 lib/cglib-2.1.3.jar,
 lib/asm.jar,
 lib/jta.jar,
 lib/ehcache-1.2.jar,
 lib/hibernate-entitymanager.jar,
 lib/javassist.jar,
 lib/jboss-archive-browsing.jar
Import-Package: org.apache.commons.logging,
 org.apache.derby.jdbc,
 org.osgi.framework;version="1.4.0",
 org.osgi.service.component;version="1.0.0",
 org.osgi.service.log;version="1.3.0" 
Export-Package: haha.hibernate,
 javax.persistence,
 org.hibernate.proxy
Service-Component: OSGI-INF/service.xml
Eclipse-BuddyPolicy: registered

src/haha/hibernate/HibernateDservice.java

到底要包出啥服務實在不清楚,直接做看看。

package haha.hibernate;

import javax.persistence.EntityManagerFactory;

public interface HibernateDservice {
    EntityManagerFactory getEntityManagerFactory(String name);

}

src/haha/hibernate/HibernateDserviceImpl.java

public EntityManagerFactory getEntityManagerFactory(String name) {
        return Persistence.createEntityManagerFactory(name);
    }

haha.helloem

這個包啟動時會找到 haha.hibernate 的服務,然後取出 EntityManager 來用,將一個物件放入冰箱保存。

META-INF/MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: haha.helloem
Bundle-SymbolicName: haha.helloem
Bundle-Version: 1.0.0
Bundle-Localization: plugin
Import-Package: haha.hibernate,
 javax.persistence,
 org.hibernate.proxy,
 org.osgi.framework;version="1.4.0",
 org.osgi.service.component;version="1.0.0",
 org.osgi.service.log;version="1.3.0" 
Service-Component: OSGI-INF/reference.xml
Eclipse-RegisterBuddy: haha.hibernate

META-INF/persistence.xml

<persistence-unit name="sample" transaction-type="RESOURCE_LOCAL">
      <class>haha.hibernate.demo.User</class>
      <properties>
         <property name="hibernate.connection.driver_class" 
            value="org.apache.derby.jdbc.ClientDriver"/>
         <property name="hibernate.connection.url" 
            value="jdbc:derby://localhost:1527/derbyDemoDB;create=true"/>
         <property name="hibernate.connection.username" 
            value="user1"/>
         <property name="hibernate.connection.password" 
            value="xxxxx"/>
         <property name="hibernate.dialect" 
            value="org.hibernate.dialect.DerbyDialect"/>
         <property name="hibernate.hbm2ddl.auto" 
            value="update"/>        
      </properties>
   </persistence-unit>

User object

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "usertb")
public class User {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Integer id;
  private String name;
  private Integer age;

  public User() {
  }
  // setXX and getXX ...
}

ejb3 container ?

既然包 hibernate 來當 ORM 來用,似乎用容器來支援一些操作比較方便,這些服務當然與可以自己來做,不過既有現成又測過,就來用看看。

Embeddable EJB 3.0

http://docs.jboss.org/ejb3/embedded/embedded.html

測的版本是jboss-EJB-3.0_Embeddable_ALPHA_9 ,並無法完成轉包到 OSGi 上跑,它的簡易啟動做法如下。

EJB3StandaloneBootstrap.boot(null);
EJB3StandaloneBootstrap.scanClasspath();

問題是這個 scanClasspath 是直接找 classpath 的 jar 或是目錄,而這些東西在 OSGi 環境中卻不存在,要改應該也可以,只是這樣似乎違背用既有東西減少開發的原意。

觀察

  1. EntityManager 跟 Hibernate 的 session 一樣,並非 Thread-safe,還要用些做法來幫忙,否則出錯都不知道在哪裡。
  2. 用 ejb3 container 似乎是個好方法,不過測試 jboss embedded ejb3 的方式不是很順利,該容器載入的模式是針對 jar 等固定模式,對於 osgi 的動態方式,並無法提供夠用的 java.class.path 來掃描那些 ejb3 檔案。
  3. DAO 部份也需要考慮如何實做。

Older posts: 1 2