<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Extreme Pattern: Hello Xfire Web Services and OSGi</title>
    <link>http://blog.extremepattern.com/articles/2006/11/09/hello-xfire-web-services-and-osgi</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>enjoy</description>
    <item>
      <title>Hello Xfire Web Services and OSGi</title>
      <description>&lt;h3&gt;源起&lt;/h3&gt;


	&lt;p&gt;除了直接接到 spring &lt;span class="caps"&gt;MVC&lt;/span&gt; 來展現網頁之外，對於外部的程式也需要連結，這裡測試
XFire 掛 Spring 的模式來做。&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://docs.codehaus.org/display/XFIRE/Home"&gt;XFire&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://static.springframework.org/spring/docs/2.0.x/reference/remoting.html"&gt;Chapter 17.5. Web Services&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://docs.codehaus.org/display/XFIRE/Spring"&gt;XFire Spring support&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://docs.codehaus.org/display/XFIRE/JSR+181+Annotations"&gt;XFire &lt;span class="caps"&gt;JSR 181&lt;/span&gt; Annotations&lt;/a&gt;&lt;/p&gt;


	&lt;h3&gt;做法&lt;/h3&gt;


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


	&lt;p&gt;主要實做下面幾包 bundle 來用。&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;haha.remix.xfire&lt;/li&gt;
		&lt;li&gt;haha.hello.ws.userdao&lt;/li&gt;
		&lt;li&gt;haha.hello.ws.client&lt;/li&gt;
	&lt;/ol&gt;


	&lt;h3&gt;haha.remix.xfire&lt;/h3&gt;


	&lt;p&gt;這是個大轉包，沒有加程式，只是改 &lt;span class="caps"&gt;MANIFEST&lt;/span&gt;.MF 來協助。&lt;/p&gt;


&lt;pre&gt;
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
&lt;/pre&gt;

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


	&lt;h3&gt; haha.hello.ws.userdao&lt;/h3&gt;


	&lt;p&gt;&lt;span class="caps"&gt;META&lt;/span&gt;-INF/spring/bean.xml&lt;/p&gt;


&lt;pre&gt;
&amp;lt;osgi:reference id="httpService" 
  interface="org.osgi.service.http.HttpService"/&amp;gt;

&amp;lt;bean name="servletRegister" 
   class="haha.hello.ws.userdao.ServletRegister" init-method="init"&amp;gt;
      &amp;lt;property name="httpService" ref="httpService"/&amp;gt;
&amp;lt;/bean&amp;gt;
&lt;/pre&gt;

	&lt;p&gt;haha.hello.ws.userdao.ServletRegister 負責啟動 &lt;span class="caps"&gt;WEB&lt;/span&gt;-INF/xx.xml 與註冊服務到 
osgi:reference 的 org.osgi.service.http.HttpService&lt;/p&gt;


&lt;pre&gt;
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);
&lt;/pre&gt;

	&lt;p&gt;&lt;span class="caps"&gt;WEB&lt;/span&gt;-INF/hello-servlet.xml&lt;/p&gt;


&lt;pre&gt;
&amp;lt;import resource="xfire.xml"/&amp;gt;
&amp;lt;osgi:reference id="userDao" 
     interface="haha.hello.jpa.userdao.UserDao"/&amp;gt;

&amp;lt;bean name="helloImpl" class="haha.hello.ws.userdao.HelloImpl"&amp;gt;     
   &amp;lt;property name="userDao" ref="userDao"/&amp;gt;
&amp;lt;/bean&amp;gt;

&amp;lt;bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"&amp;gt;
   &amp;lt;property name="mappings"&amp;gt;
            &amp;lt;value&amp;gt;/hello=wsController&amp;lt;/value&amp;gt;
   &amp;lt;/property&amp;gt;
&amp;lt;/bean&amp;gt;

&amp;lt;bean id="wsController" 
      class="org.codehaus.xfire.spring.remoting.XFireExporter"&amp;gt;
        &amp;lt;property name="serviceFactory"&amp;gt;
            &amp;lt;ref bean="xfire.annotationServiceFactory"/&amp;gt;
        &amp;lt;/property&amp;gt;
        &amp;lt;property name="xfire"&amp;gt;
            &amp;lt;ref bean="xfire"/&amp;gt;
        &amp;lt;/property&amp;gt;
        &amp;lt;property name="serviceBean"&amp;gt;
            &amp;lt;ref bean="helloImpl"/&amp;gt;
        &amp;lt;/property&amp;gt;
&amp;lt;/bean&amp;gt;
&lt;/pre&gt;

	&lt;p&gt;&lt;span class="caps"&gt;WEB&lt;/span&gt;-INF/xfire.xml 取自 xfire classpath:org/codehaus/xfire/spring/xfire.xml
修改一下 singleton 設定而已。&lt;/p&gt;


	&lt;p&gt;這一包主要將 haha.hello.ws.userdao.Hello 放到 WebServic 去。&lt;/p&gt;


	&lt;p&gt;haha.hello.ws.userdao.Hello&lt;/p&gt;


&lt;pre&gt;
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();
}
&lt;/pre&gt;

	&lt;p&gt;haha.hello.ws.userdao.HelloImpl 會注入 osgi:reference 的 haha.hello.jpa.userdao.UserDao 來用。&lt;/p&gt;


&lt;pre&gt;
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].....
&lt;/pre&gt;

	&lt;p&gt;&lt;span class="caps"&gt;MANIFEST&lt;/span&gt;.MF&lt;/p&gt;


&lt;pre&gt;
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
&lt;/pre&gt;

	&lt;p&gt;啟動後可以直接開瀏覽器到 http://127.0.0.1/services/hello?wsdl 觀察 &lt;span class="caps"&gt;WSDL&lt;/span&gt;。&lt;/p&gt;


	&lt;h3&gt; haha.hello.ws.client&lt;/h3&gt;


	&lt;p&gt;陽春型客戶端，只是取用 getName 輸出看看而已，沒有用到 &lt;span class="caps"&gt;WSDL2JAVA&lt;/span&gt; 來轉成 java。&lt;/p&gt;


&lt;pre&gt;
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]....
&lt;/pre&gt;

	&lt;p&gt;&lt;span class="caps"&gt;MANIFEST&lt;/span&gt;.MF&lt;/p&gt;


&lt;pre&gt;
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
&lt;/pre&gt;

	&lt;h3&gt;觀察&lt;/h3&gt;


	&lt;ol&gt;
	&lt;li&gt;越深入企業層面的應用，越發覺既有程式套件之間的相依性很高，之前用一個 classpath 可以找到，
現在轉 OSGi 變成要考慮匯出匯入問題，變的更為複雜，有時現有套件無法滿足，只好直接轉 remix 大包
來實現或是用 eclipse buddy 機制。&lt;/li&gt;
		&lt;li&gt;如果使用 import-package 方式，似乎無法保證某些服務會先啟動，於是將 ws.client 
中設定 Require-Bundle 來讓某些服務先滿足。&lt;/li&gt;
	&lt;/ol&gt;</description>
      <pubDate>Thu, 09 Nov 2006 20:43:00 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:a1cb7161-113a-4b40-8e5a-cebf27f169fd</guid>
      <author>LIN</author>
      <link>http://blog.extremepattern.com/articles/2006/11/09/hello-xfire-web-services-and-osgi</link>
      <category>eclipse</category>
      <category>java</category>
    </item>
  </channel>
</rss>
