xfire is a web service framework that can expose pojo objects as web service.
Yan provides an integration package allowing configuring xfire services with yan.
Standalone application
A sample xfire configuration file is:
<?xml version="1.0" encoding="UTF-8"?> <module name="echo service" export="echo"> <nut name="service" class="jfun.yan.xfire.ServiceNut"/> <body> <!-- START SNIPPET: xfire --> <service id="echo" serviceClass="org.codehaus.xfire.test.Echo" inHandlers="$addressingHandler" scope="session"> <bean class="org.codehaus.xfire.test.EchoImpl"/> </service> <bean id="addressingHandler" class="org.codehaus.xfire.addressing.AddressingInHandler"/> <!-- END SNIPPET: xfire --> </body> </module>
The <service> tag is supported by the jfun.yan.xfire.ServiceNut class. This tag supports every attribute currently supported by the native xfire configuration.
The "scope" attribute can be set to "application", "service", "session" and "request".
- "application" and "service" are equivalent. They both enforce one EchoImpl instance per service. Therefore "service" is picked as scope name.
- "session" scope enforces one EchoImpl instance per session.
- "request" scope uses one EchoImpl instance per service method invocation.
- if "scope" is not specified, the default scope is "service'.
- If you simply want a globally singleton EchoImpl, just set the nested EchoImpl component to singleton as:
<service id="echo" serviceClass="org.codehaus.xfire.test.Echo" inHandlers="$addressingHandler" scope="request"> <bean class="org.codehaus.xfire.test.EchoImpl" singleton="true"/> </service>
The scope is changed to "request" to avoid any caching done at the service level.
- "singleton" attribute (and many other common attributes) can still be set on the <service> tag to control the instantiation of the Service object. A Service is a regular component.
In order to set up xfire environment, either "jfun/yan/xfire/xfireXmlBeans.xml" or "jfun/yan/xfire/xfire.xml" needs to be loaded.
A typical Java code that bootstrap xfire may look like:
Container createContainer() throws IOException{ NutsProcessor processor = new NutsProcessor( ClassLoaderUtils.guessClassLoader(getClass().getClassLoader()) ); processor.processResource("jfun/yan/xfire/xfireXmlBeans.xml"); processor.processResource("tests/jfun/yan/xfire/echo.xml"); processor.preInstantiate(); return processor.getContainer(); }
The container created can then be used to lookup regular beans as well as xfire Service:
Container yan = getContainer(); assertNotNull(yan.getInstance("xfire.serviceFactory")); Service service = (Service)yan.getInstance("echo"); assertNotNull(service);
Servlet
When deployed as a servlet, jfun.yan.xfire.XFireYanServlet can be used to read service information from a yan configuration file.
For example, the xfire book example can be configured using Yan configuration file.
The web.xml file will look like:
<?xml version="1.0" encoding="ISO-8859-1"?> <!-- START SNIPPET: webxml --> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <servlet> <servlet-name>XFireServlet</servlet-name> <display-name>XFire Servlet</display-name> <servlet-class>jfun.yan.xfire.XFireYanServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>XFireServlet</servlet-name> <url-pattern>/servlet/XFireServlet/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>XFireServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <context-param> <param-name>yanConfigFile</param-name> <param-value>META-INF/xfire/yan.xml</param-value> </context-param> </web-app> <!-- END SNIPPET: webxml -->
The "yanConfigFile" parameter is used to specify the location of the configuration file.
And the yan.xml file looks like:
<?xml version="1.0" encoding="UTF-8"?> <module name="book service example"> <import resource="jfun/yan/xfire/xfire.xml" includes="*"/> <body> <service name="BookShelf" namespace="http://yan.codehaus.org/BookShelf" component="$bookshelf" /> <ctor id="bookshelf" class="jfun.yan.xfire.demo.BookShelf"> <local> <function id="book" params="isbn,title,author"> <bean class="org.codehaus.xfire.demo.Book" args="" props="{title=$title,isbn=$isbn,author=$author}" /> </function> </local> <args> <array of="org.codehaus.xfire.demo.Book"> <call function="book" args="123, learning xfire, Dan Diephouse"/> <call function="book" args="456, learning Yan, Ben Yu"/> </array> </args> </ctor> </body> </module>
In this example, component "bookshelf" is configured in exactly the same way as any other regular component. We then use the "service" tag to expose it as a web service.
Backbone Configuration
Though not required, reading the xfire.xml helps in knowing what ids the xfire infrastructure beans are registered under. Now let's take a look:
<?xml version="1.0" encoding="UTF-8"?> <module name="xfire main"> <body> <deserializer target-type="org.codehaus.xfire.soap.SoapVersion" class="org.codehaus.xfire.spring.editors.SoapVersionPropertyEditor"/> <deserializer target-type="org.codehaus.xfire.service.ServiceFactory" class="org.codehaus.xfire.spring.editors.ServiceFactoryEditor" /> <deserializer target-type="jfun.yan.xfire.ScopePolicy" class="jfun.yan.xfire.ScopeDeserializer" /> <bean id="xfire.serviceRegistry" class="org.codehaus.xfire.service.DefaultServiceRegistry" singleton="true" /> <bean id="xfire.transportManager" class="org.codehaus.xfire.transport.DefaultTransportManager" singleton="true" args="$xfire.serviceRegistry"/> <bean id="xfire" class="org.codehaus.xfire.DefaultXFire" singleton="true" args="$xfire.serviceRegistry,$xfire.transportManager"/> <bean id="xfire.typeMappingRegistry" class="org.codehaus.xfire.aegis.type.DefaultTypeMappingRegistry" initializer="createDefaultMappings" singleton="true"/> <bean id="xfire.aegisBindingProvider" class="org.codehaus.xfire.aegis.AegisBindingProvider" singleton="true" args="$xfire.typeMappingRegistry"/> <bean id="xfire.serviceFactory" class="org.codehaus.xfire.service.binding.ObjectServiceFactory" singleton="true" args="$xfire.transportManager, $xfire.aegisBindingProvider"/> <bean id="xfire.servletController" class="org.codehaus.xfire.transport.http.XFireServletController" singleton="true" args="$xfire"/> <bean id="xfire.messageServiceFactory" class="org.codehaus.xfire.service.binding.ObjectServiceFactory" args="$xfire.transportManager, $xfire.messageBindingProvider"/> <bean id="xfire.messageBindingProvider" class="org.codehaus.xfire.service.binding.MessageBindingProvider" /> </body> </module>
