reenabling soap using erjaxws
DESCRIPTION
Presentation made at WOWODC 2014, about a new SOAP framework from Project Wonder.TRANSCRIPT
Reenabling SOAP using ERJaxWSMarkus Stoll
WebServices using SOAP
• Why SOAP? I do love REST!
• "Simple Object Access Protocol"
SOAP
• Standardized
• self defining
JavaWebServices
• known bugs (e. g. problems with https)
• bugs with mapping of complex data types (uses Axis 1.x)
• clumsy (Axis 1.x)
• complicated (Axis 1.x)
• slow (Axis 1.x)
• consider it broken
Alternatives?
• AXIS 2
‣ POJO for services and mapped data
‣ service definitions in separate files
‣ rewritten from scratch
!
• Jax WS
‣ POJO for services and mapped data
‣ all definitions using Java Annotations
‣ part of Standard Java!
ERJaxWS
• Jax WS RI Libraries
• ERJaxWebServiceRequestHandleradapting WORequest to Jax WS internal engine for handling servlet requests
• NOT API compatible to JavaWebServices
• provide new SOAP service
• provide SOAP service based on imported WSDL
• call external SOAP service based on imported WSDL
Provide own SOAP service - 1
package your.app.ws;!import javax.jws.WebService;!@WebService!public class Calculator {! public int add(int a, int b) { return a + b; }}
Provide own SOAP service - 2
package your.app;!import javax.xml.ws.Endpoint;!import er.extensions.appserver.ERXApplication;import er.extensions.appserver.ws.ERJaxWebService;import er.extensions.appserver.ws.ERJaxWebServiceRequestHandler;!public class Application extends ERXApplication {! public static void main(String[] argv) { ERXApplication.main(argv, Application.class); }! public Application() { setAllowsConcurrentRequestHandling(true); // do it the WONDER way ERJaxWebServiceRequestHandler wsHandler = new ERJaxWebServiceRequestHandler(); wsHandler.registerWebService("Calculator", new ERJaxWebService<Calculator>(Calculator.class)); this.registerRequestHandler(wsHandler, this.webServiceRequestHandlerKey());! // create a standalone endpoint using Jax WS mechanisms Endpoint.publish("http://localhost:9999/ws/Calculator", new Calculator());! }}
Provide own SOAP service - 3 !
LIVE-DEMO
Provide SOAP service based on WSDL
// Import WSDL and create interface and classes for mapped data$ wsimport -keep -s Sources http://localhost:port/cgi-bin/WebObjects/WebService1.woa/ws/Calculator?wsdl!// Import WSDL and create jar$ wsimport -clientjar Libraries/myservice.jar http://localhost:port/cgi-bin/WebObjects/WebService1.woa/ws/Calculator?wsdl!!!// create CalculatorImplementationpackage your.app;!import javax.jws.WebService;!@WebService(endpointInterface = "your.app.Calculator")!public class CalculatorImpl implements Calculator{! @Override public int add(int arg0, int arg1) { return arg0 + arg1; }!}
Provide SOAP service based on WSDL !
LIVE-DEMO
Java Annotations / WebService
• @WebService name, namespace, service interface
• @BindingType SOAP version
• @SOAPBinding WSDL document styles
• @WebMethod name, exclusion
• @WebParam name
• @WebResult name
Call a remote SOAP service URL url = new URL("http://127.0.0.1:3333/cgi-bin/WebObjects/JaxServerTest.woa/ws/Hello?wsdl");! // 1st argument service URI, refer to wsdl document above // 2nd argument is service name, refer to wsdl document above QName qname = new QName("http://app.your/", "HelloImplService");! Service service = Service.create(url, qname);! Hello remoteHello = service.getPort(Hello.class);! remoteHello.hello("Jon Doe“);!!! // BETTER: use imported interface! HelloImplService service = new HelloImplService(url);! Hello remoteHello = service.getPort(Hello.class);! remoteHello.hello("Jon Doe“);!
Data mapping
• JAXB
• all native Java data types
• all "Bean" classes
• custom type adaptors
custom data mapping - 1!!!public class WSStruct {! public String name;! public int zip;! public MyCustomDate myDate; ! public NSTimestamp datetime;}
custom data mapping - 2@XmlType(name = "WSStructType", propOrder = {"name", "zip", "datetime"})@XmlAccessorType(value = XmlAccessType.PUBLIC_MEMBER)!public class WSStruct { @XmlElement public String name; @XmlAttribute public int zip; @XmlTransient public MyCustomDate myDate; ! public NSTimestamp datetime;}
custom data mapping - 3@XmlType(name = "WSStructType", propOrder = {"name", "zip", "datetime"})@XmlAccessorType(value = XmlAccessType.PUBLIC_MEMBER)!public class WSStruct { @XmlElement public String name; @XmlAttribute public int zip; @XmlTransient public MyCustomDate myDate; @XmlJavaTypeAdapter(value = NSTimestampAdapter.class) public NSTimestamp datetime;}class NSTimestampAdapter extends XmlAdapter<String, NSTimestamp>{ private final NSTimestampFormatter formatter = new NSTimestampFormatter(); public NSTimestamp unmarshal(String v) throws Exception { return (NSTimestamp) formatter.parseObject(v); } public String marshal(NSTimestamp v) throws Exception { return formatter.format(v); }}
Data mapping
• Directly map EOs? NO!
• might change
• would need to adapt your EO templates
• avoid marshalling your complete data tree
WebFaults
• WebServices exceptions can be defined as WebFaults
• Beware: serialized info is not in Exception but in a referred WebFault bean
• stack traces possible switch off with property com.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace=false
WebFault sample@WebFault(faultBean = "TestServiceFaultInfo")public class TestServiceException extends Exception { private TestServiceFaultInfo code; public TestServiceException(String message, TestServiceFaultInfo info) { super(message); this.code = info; } public TestServiceFaultInfo getFaultInfo() { return code; }}!public class TestServiceFaultInfo { public String msg;! public TestServiceFaultInfo() { }! public TestServiceFaultInfo(String msg) { this.msg = msg; }}
Stateful Services
• @Stateful - makes no sense in WebObjects env
• Jax WS injects a RequestContext into your Service object
• gives access to WOContext and by that to your Session
• creates WebObjects Cookies as usual
• enable session persistence in your client proxy
Stateful Services !
LIVE-DEMO
Secure WebServices
• basic auth by common means
• create your own custom ERJaxWebService
• @SOAPMessageHandlerdeclare your own Jax WS message handlersfor example for handling signed SOAP messages
Troubleshooting
• Test-Tools
• SoapUI
• http://wsdlbrowser.com
• test against original javax.xml.ws.Endpoint
• compare imported WSDL vs. recreated WSDL
Resources
• https://github.com/markusstoll/wonder/tree/ERJaxWS
• https://jax-ws.java.net
• http://www.techferry.com/articles/jaxb-annotations.html
Q&AMarkus Stoll junidas GmbH [email protected]