Coding a CXF web service translating a DNA to a protein. My notebook
Apache CXF is a Web Services framework. In this post, I'll will describe how I implemented a Web Service translating a DNA to a protein using the web server Apache Tomcat and the CXF libraries.
Defining the interface
First a simple java interface bio.Translate is needed to describe the service. This simple service receives a string (the dna) and returns a string (the peptide). The annotations will be used by CXF to name the parameters in the WSDL file (see later):
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package bio; | |
import javax.jws.WebParam; | |
import javax.jws.WebResult; | |
import javax.jws.WebService; | |
@WebService | |
public interface Translate | |
{ | |
@WebResult(name="protein") | |
public String translate(@WebParam(name = "dna")String dna); | |
} |
Implementing the service
bio.TranslateImpl implements bio.Translate. The setter/getter for ncbiString will be used by a configuration file to specify a genetic code (standard, mitochondrial) for this service. The methods initIt and cleanUp could be used to acquire and to release some resources for the service when it is created and/or disposed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package bio; | |
import javax.jws.WebService; | |
@WebService(endpointInterface = "bio.Translate",serviceName = "TranslateService",name="Translate") | |
public class TranslateImpl | |
implements Translate | |
{ | |
/** see http://www.ncbi.nlm.nih.gov/Taxonomy/Utils/wprintgc.cgi */ | |
private String ncbiString=null; | |
public void setNcbiString(String ncbiString) | |
{ | |
this.ncbiString=ncbiString; | |
} | |
public String getNcbiString() | |
{ | |
return this.ncbiString; | |
} | |
@Override | |
public String translate(String text) | |
{ | |
StringBuilder pep=new StringBuilder(text.length()/3); | |
for(int i=0;i+2< text.length();i+=3) | |
{ | |
pep.append(translate(text.charAt(i),text.charAt(i+1),text.charAt(i+2))); | |
} | |
return pep.toString(); | |
} | |
private static int base2index(char c) | |
{ | |
switch(Character.toLowerCase(c)) | |
{ | |
case 't':case 'u': return 0; | |
case 'c': return 1; | |
case 'a': return 2; | |
case 'g': return 3; | |
default: return -1; | |
} | |
} | |
private char translate(char a,char b,char c) | |
{ | |
int base1= base2index(a); | |
int base2= base2index(b); | |
int base3= base2index(c); | |
if(base1==-1 || base2==-1 || base3==-1) | |
{ | |
return '?'; | |
} | |
else | |
{ | |
return getNcbiString().charAt(base1*16+base2*4+base3); | |
} | |
} | |
public void initIt() | |
{ | |
System.err.println("Init called"); | |
} | |
public void cleanUp() | |
{ | |
System.err.println("Cleanup called"); | |
} | |
} |
Configuring the service
CXF uses the libraries of the Spring framework (I blogged about spring here ). A XML config file beans.xml makes it easy to configure two java beans for the 'standard genetic code' and the 'mitochondrial code'. In this config file, we also tell Spring about the two methods initIt and cleanUp. Those two beans will be used by two Web Services
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<beans xmlns="http://www.springframework.org/schema/beans" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xmlns:jaxws="http://cxf.apache.org/jaxws" | |
xsi:schemaLocation=" | |
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd | |
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> | |
<import resource="classpath:META-INF/cxf/cxf.xml" /> | |
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> | |
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> | |
<bean id="translateStd" class="bio.TranslateImpl" | |
init-method="initIt" destroy-method="cleanUp"> | |
<property name="ncbiString"> | |
<value>FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG</value> | |
</property> | |
</bean> | |
<bean id="translateMit" class="bio.TranslateImpl" | |
init-method="initIt" destroy-method="cleanUp"> | |
<property name="ncbiString"> | |
<value>FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNKKSS**VVVVAAAADDEEGGGG</value> | |
</property> | |
</bean> | |
<jaxws:endpoint | |
id="translateStdEndPoint" | |
implementor="#translateStd" | |
address="/translateStd" /> | |
<jaxws:endpoint | |
id="translateMitEndPoint" | |
implementor="#translateMit" | |
address="/translateMit" /> | |
</beans> |
Defining the CXF application for Tomcat
The following web.xml file only tells tomcat, the web server, to use the CXFServlet to listen to the SOAP queries.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<web-app> | |
<context-param> | |
<param-name>contextConfigLocation</param-name> | |
<param-value>WEB-INF/beans.xml</param-value> | |
</context-param> | |
<listener> | |
<listener-class> | |
org.springframework.web.context.ContextLoaderListener | |
</listener-class> | |
</listener> | |
<servlet> | |
<servlet-name>CXFServlet</servlet-name> | |
<display-name>CXF Servlet</display-name> | |
<servlet-class> org.apache.cxf.transport.servlet.CXFServlet</servlet-class> | |
<load-on-startup>1</load-on-startup> | |
</servlet> | |
<servlet-mapping> | |
<servlet-name>CXFServlet</servlet-name> | |
<url-pattern>/*</url-pattern> | |
</servlet-mapping> | |
</web-app> |
Compile & Deploy
Installing a CXF web service requires many libraries and at the end, the size of the deployed 'war' file was 8.5Mo(!). Currently, my structure for the current project is:./translate/WEB-INF/classes/bio/TranslateImpl.javaThe service was compiled and deployed using the following Makefile:
./translate/WEB-INF/classes/bio/Translate.java
./translate/WEB-INF/beans.xml
./translate/WEB-INF/web.xml
cxf.lib=apache-cxf-2.3.1/lib
all:
mkdir -p translate/WEB-INF/lib
javac -d translate/WEB-INF/classes -sourcepath translate/WEB-INF/classes translate/WEB-INF/classes/bio/TranslateImpl.java
cp ${cxf.lib}/cxf-2.3.1.jar \
${cxf.lib}/geronimo-activation_1.1_spec-1.1.jar \
${cxf.lib}/geronimo-annotation_1.0_spec-1.1.1.jar \
${cxf.lib}/geronimo-javamail_1.4_spec-1.7.1.jar \
${cxf.lib}/geronimo-servlet_3.0_spec-1.0.jar \
${cxf.lib}/geronimo-ws-metadata_2.0_spec-1.1.3.jar \
${cxf.lib}/geronimo-jaxws_2.2_spec-1.0.jar \
${cxf.lib}/geronimo-stax-api_1.0_spec-1.0.1.jar \
${cxf.lib}/jaxb-api-2.2.1.jar \
${cxf.lib}/jaxb-impl-2.2.1.1.jar \
${cxf.lib}/neethi-2.0.4.jar \
${cxf.lib}/saaj-api-1.3.jar \
${cxf.lib}/saaj-impl-1.3.2.jar \
${cxf.lib}/wsdl4j-1.6.2.jar \
${cxf.lib}/XmlSchema-1.4.7.jar \
${cxf.lib}/xml-resolver-1.2.jar \
${cxf.lib}/aopalliance-1.0.jar \
${cxf.lib}/spring-core-3.0.5.RELEASE.jar \
${cxf.lib}/spring-beans-3.0.5.RELEASE.jar \
${cxf.lib}/spring-context-3.0.5.RELEASE.jar \
${cxf.lib}/spring-web-3.0.5.RELEASE.jar \
${cxf.lib}/commons-logging-1.1.1.jar \
${cxf.lib}/spring-asm-3.0.5.RELEASE.jar \
${cxf.lib}/spring-expression-3.0.5.RELEASE.jar \
${cxf.lib}/spring-aop-3.0.5.RELEASE.jar \
translate/WEB-INF/lib
jar cvf translate.war -C translate .
mv translate.war path-to-tomcat/webapps
all:
mkdir -p translate/WEB-INF/lib
javac -d translate/WEB-INF/classes -sourcepath translate/WEB-INF/classes translate/WEB-INF/classes/bio/TranslateImpl.java
cp ${cxf.lib}/cxf-2.3.1.jar \
${cxf.lib}/geronimo-activation_1.1_spec-1.1.jar \
${cxf.lib}/geronimo-annotation_1.0_spec-1.1.1.jar \
${cxf.lib}/geronimo-javamail_1.4_spec-1.7.1.jar \
${cxf.lib}/geronimo-servlet_3.0_spec-1.0.jar \
${cxf.lib}/geronimo-ws-metadata_2.0_spec-1.1.3.jar \
${cxf.lib}/geronimo-jaxws_2.2_spec-1.0.jar \
${cxf.lib}/geronimo-stax-api_1.0_spec-1.0.1.jar \
${cxf.lib}/jaxb-api-2.2.1.jar \
${cxf.lib}/jaxb-impl-2.2.1.1.jar \
${cxf.lib}/neethi-2.0.4.jar \
${cxf.lib}/saaj-api-1.3.jar \
${cxf.lib}/saaj-impl-1.3.2.jar \
${cxf.lib}/wsdl4j-1.6.2.jar \
${cxf.lib}/XmlSchema-1.4.7.jar \
${cxf.lib}/xml-resolver-1.2.jar \
${cxf.lib}/aopalliance-1.0.jar \
${cxf.lib}/spring-core-3.0.5.RELEASE.jar \
${cxf.lib}/spring-beans-3.0.5.RELEASE.jar \
${cxf.lib}/spring-context-3.0.5.RELEASE.jar \
${cxf.lib}/spring-web-3.0.5.RELEASE.jar \
${cxf.lib}/commons-logging-1.1.1.jar \
${cxf.lib}/spring-asm-3.0.5.RELEASE.jar \
${cxf.lib}/spring-expression-3.0.5.RELEASE.jar \
${cxf.lib}/spring-aop-3.0.5.RELEASE.jar \
translate/WEB-INF/lib
jar cvf translate.war -C translate .
mv translate.war path-to-tomcat/webapps
Checking the URL
We can see that the service was correctly deployed by pointing a web browser at http://localhost:8080/translate/, where we can see the two services:Available SOAP services:
Translate
| Endpoint address: http://localhost:8080/translate/translateMit WSDL : {http://bio/}TranslateService Target namespace: http://bio/ |
Translate
| Endpoint address: http://localhost:8080/translate/translateStd WSDL : {http://bio/}TranslateService Target namespace: http://bio/ |
Here, the URLs link to the WSDL definition for the web service:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" ?><wsdl:definitions name="TranslateService" targetNamespace="http://bio/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://bio/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | |
<wsdl:types> | |
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://bio/" xmlns:tns="http://bio/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | |
<xsd:element name="translate" type="tns:translate"></xsd:element> | |
<xsd:complexType name="translate"> | |
<xsd:sequence> | |
<xsd:element minOccurs="0" name="dna" type="xsd:string"></xsd:element> | |
</xsd:sequence> | |
</xsd:complexType> | |
<xsd:element name="translateResponse" type="tns:translateResponse"></xsd:element> | |
<xsd:complexType name="translateResponse"> | |
<xsd:sequence> | |
<xsd:element minOccurs="0" name="protein" type="xsd:string"></xsd:element> | |
</xsd:sequence> | |
</xsd:complexType> | |
</xsd:schema> | |
</wsdl:types> | |
<wsdl:message name="translate"> | |
<wsdl:part element="tns:translate" name="parameters"> | |
</wsdl:part> | |
</wsdl:message> | |
<wsdl:message name="translateResponse"> | |
<wsdl:part element="tns:translateResponse" name="parameters"> | |
</wsdl:part> | |
</wsdl:message> | |
<wsdl:portType name="Translate"> | |
<wsdl:operation name="translate"> | |
<wsdl:input message="tns:translate" name="translate"> | |
</wsdl:input> | |
<wsdl:output message="tns:translateResponse" name="translateResponse"> | |
</wsdl:output> | |
</wsdl:operation> | |
</wsdl:portType> | |
<wsdl:binding name="TranslateServiceSoapBinding" type="tns:Translate"> | |
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"></soap:binding> | |
<wsdl:operation name="translate"> | |
<soap:operation soapAction="" style="document"></soap:operation> | |
<wsdl:input name="translate"> | |
<soap:body use="literal"></soap:body> | |
</wsdl:input> | |
<wsdl:output name="translateResponse"> | |
<soap:body use="literal"></soap:body> | |
</wsdl:output> | |
</wsdl:operation> | |
</wsdl:binding> | |
<wsdl:service name="TranslateService"> | |
<wsdl:port binding="tns:TranslateServiceSoapBinding" name="TranslatePort"> | |
<soap:address location="http://localhost:8080/translate/translateStd"></soap:address> | |
</wsdl:port> | |
</wsdl:service> | |
</wsdl:definitions> |
Creating a client
For creating a client consuming this service, I first used the code generated by CXF's wsdl2java but there was a bug with one of the generated classe (it is a known> wsimport -p generated -d client -keep "http://localhost:8080/translate/translateStd?wsdl"
parsing WSDL...
generating code...
compiling code...
I wrote a java client MyClient.java using this generated API:parsing WSDL...
generating code...
compiling code...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import generated.*; | |
public class MyClient | |
{ | |
public static void main(String args[]) throws Exception | |
{ | |
TranslateService service=new TranslateService(); | |
Translate tr=service.getTranslatePort(); | |
System.out.println(tr.translate("GAATTCATCGATCATAGCATTgcatgctagc")); | |
} | |
} |
Compiling
> cd client
> javac MyClient.java
> javac MyClient.java
Running
> java MyClient
EFIDHSIAC*
EFIDHSIAC*
That's it,
Pierre
No comments:
Post a Comment