soap sucks doesn’t it? - eclipsecon europe 2019 · soap sucks doesn’t it? tom bujok geecon...

79
SOAP SUCKS Doesn’t it? TOM BUJOK GeeCON CONFERENCE 16th of MAY 2013

Upload: others

Post on 28-May-2020

3 views

Category:

Documents


0 download

TRANSCRIPT

SOAP SUCKS Doesn’t it?

TOM BUJOK

GeeCON CONFERENCE 16th of MAY 2013

SOAP SUCKS DOESN’T IT?

ABOUT METom(EK|ASZ){0,1} BUJOkcenteractive ag, BERN, [email protected]

WHY SOAP?IT’s NOt 2005...Non-CLOUD / non-SOCIAL / non-BIG DATANOT reST / NOSQL

...A WEEKEND TRIP WITH YOUR INLAWS

BUZZWORD DRIVEN ARCHITECTURE

JAVA DEVELOPERS ARE NUTS

5 MINUT

XML PARSING<?xml version="1.0" encoding="UTF-8"?><stocks> <stock> <symbol>Citibank</symbol> <price>100</price> <quantity>1000</quantity> </stock> <stock> <symbol>UBS</symbol> <price>90</price> <quantity>2000</quantity> </stock></stocks>

JAVADocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();Document doc = dBuilder.parse(stocks);doc.getDocumentElement().normalize();NodeList nodes = doc.getElementsByTagName("stock");for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element el = (Element) node; NodeList list = el.getElementsByTagName("symbol") NodeList children = list.item(0).getChildNodes(); String value = children(0).getNodeValue(); } }}

JAVADocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();Document doc = dBuilder.parse(stocks);doc.getDocumentElement().normalize();NodeList nodes = doc.getElementsByTagName("stock");for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element el = (Element) node; NodeList list = el.getElementsByTagName("symbol") NodeList children = list.item(0).getChildNodes(); String value = children(0).getNodeValue(); } }}

JAVADocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();Document doc = dBuilder.parse(stocks);doc.getDocumentElement().normalize();NodeList nodes = doc.getElementsByTagName("stock");for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element el = (Element) node; NodeList list = el.getElementsByTagName("symbol") NodeList children = list.item(0).getChildNodes(); String value = children(0).getNodeValue(); } }}

JAVADocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();Document doc = dBuilder.parse(stocks);doc.getDocumentElement().normalize();NodeList nodes = doc.getElementsByTagName("stock");for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element el = (Element) node; NodeList list = el.getElementsByTagName("symbol") NodeList children = list.item(0).getChildNodes(); String value = children(0).getNodeValue(); } }}

I am curious what is the purpose of normalize(). I have tried to surf but couldn't find any useful stuff.

forums.oracle.com

In cases where the document contains CDATASections, the normalize operation alone may not be sufficient, since XPointers do not differentiate between Text nodes and CDATASection nodes.

JAVADocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();Document doc = dBuilder.parse(stocks);doc.getDocumentElement().normalize();NodeList nodes = doc.getElementsByTagName("stock");for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element el = (Element) node; NodeList list = el.getElementsByTagName("symbol") NodeList children = list.item(0).getChildNodes(); String value = children(0).getNodeValue(); } }}

JAVADocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();Document doc = dBuilder.parse(stocks);doc.getDocumentElement().normalize();NodeList nodes = doc.getElementsByTagName("stock");for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element el = (Element) node; NodeList list = el.getElementsByTagName("symbol") NodeList children = list.item(0).getChildNodes(); String value = children(0).getNodeValue(); } }}

JAVADocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();Document doc = dBuilder.parse(stocks);doc.getDocumentElement().normalize();NodeList nodes = doc.getElementsByTagName("stock");for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element el = (Element) node; NodeList list = el.getElementsByTagName("symbol") NodeList children = list.item(0).getChildNodes(); String value = children(0).getNodeValue(); } }}

JAVADocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();Document doc = dBuilder.parse(stocks);doc.getDocumentElement().normalize();NodeList nodes = doc.getElementsByTagName("stock");for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element el = (Element) node; NodeList list = el.getElementsByTagName("symbol") NodeList children = list.item(0).getChildNodes(); System.out.println(children(0).getNodeValue()); } }}

7 MINUT

def doc = new XmlSlurper().parse(stocks)doc.stock.each { println it.symbol.text() }

GROOVY

+

RETHINK THE BASICS

WEB SERVICE STACKS ???

WEB-SERVICE STACKS

‣ APACHE AXIS 1.4 (✝2006)‣ XFIRE 1.2.6 (✝2007)‣ APACHE AXIS 2 1.6.2‣ Apache cxf 2.7.0

‣ SPRING-WS 2.1.1 ‣ JAX-WS RI 2.2.7 ‣ GLASSFISh METRO 2.2.1-1 ‣ WSo2

HOWTO?

R U NC O M P I L E

D E P L O YG E N E R A T EA N N O T A T E

CODE-FIRST vs.

CONTRACT-FIRST

@WebService(name = "PersonService")public class PersonService { public Person getPerson(String uuid) { return new Person(); }}

@XmlAccessorType(XmlAccessType.FIELD)@XmlRootElement(namespace = "http://jdays/person")public class Person { String uuid; String firstName; String lastName;}

tIGHT-COUPLING vs. DTO (ANTI) PATTERN

@WebMethod(action = "urn:getBook") @WebResult(name = "getBookReturn", targetNamespace = "http://jdays/library/wsdl") @RequestWrapper(localName = "getBook", targetNamespace = "http://jdays/library/wsdl", className = "se.jdays.GetBook") @ResponseWrapper(localName = "getBookResponse", targetNamespace = "http://jdays/library/wsdl", className = "se.jdays.GetBookResponse") public Book getName( @WebParam(name = "isbn", targetNamespace = "http://jdays/library/wsdl") String isbn);

CODE-FIRST (ANTI) pattern

├── resources│ ├── CustomerService.wsdl│ ├── binding.xml│ ├── client-applicationContext.xml│ ├── cxf.xml│ └── server-applicationContext.xml└── webapp └── WEB-INF ├── cxf-servlet.xml └── web.xml

IS IT REALLY THAT EASY (CLIENT <-> SERVER)?‣ ant / maven‣ CXF-CODEGEN PLUGIN‣ BUILDEr-HELPER-PLUGIN ‣ WAR-PLUGIN‣ JETTY-PLUGIN

OBJECT-ORIENTED PARADIGMObjects have

failedRichard p. Gabriel

def url="api.twitter.com/1/statuses/user_timeline.json"def response = ("https://$url?id=tombujok").toURL().textprintln new JsonSlurper().parseText(response)?.text.first()

GROOVY REST CLIENT 15 minut

BUT SOAP IS NOT QUITE THAT EASY...

WSDL STRUCTURE

T Y P E

M E S S A G E

P O R T T Y P E

B I N D I N G

S E R V I C E

P O R T S

O P E R A T I O N

SOAP BINDING STYLES

‣ RPC-ENCODED‣ RPC-LITERAL‣ DOCUMENT-ENCODED‣ DOCUMENT-LITERAL‣ DOCUMENT-LITERAL-WRAPPED

http://www.ibm.com/developerworks/webservices/library/ws-whichwsdl/

SOAP MESSAGE RPC-ENCODED<soap:envelope> <soap:body> <myMethod> <x xsi:type="xsd:int">5</x> <y xsi:type="xsd:float">5.0</y> </myMethod> </soap:body></soap:envelope>

SOAP MESSAGE RPC-LITERAL<soap:envelope> <soap:body> <myMethod> <x>5</x> <y>5.0</y> </myMethod> </soap:body></soap:envelope>

SOAP MESSAGE DOCUMENT-LITERAL<soap:envelope> <soap:body> <xElement>5</xElement> <yElement>5.0</yElement> </soap:body></soap:envelope>

IT LOOKS A BIT SCARY...

MEET rEFICIO SOAp-WSLIGHTWEIGHT and FANCYXMl-ORIENTED SOAP STACKBASED on SPRING-WS

18 minut

MESSAGE GENERATION

SOAP BUILDER - ONE LINER

String message = Wsdl .parse(WSDL_URL) .binding().localPart(BINDING_NAME).find() .operation().soapAction(SOAP_ACTION).find() .buildInputMessage()

SOAP BUILDERString url = "http://CurrencyConvertor.com?WSDL";WsdlParser parser = WsdlParser.parse(url);

SoapBuilder builder = parser.binding() .localPart("CurrencyConvertorSoap") .builder();

SoapOperation operation = builder.operation() .soapAction("http://ConversionRate") .find();

String input = builder.buildInputMessage(operation);

SOAP BUILDER - INTERFACEString buildInputMessage()

String buildOutputMessage()

String buildFault(String code, String message)

String buildEmptyFault()

String buildEmptyMessage()

SOAP CONTEXTSoapContext context = SoapContext.builder() .alwaysBuildHeaders(true) .buildOptional(true) .exampleContent(true) .typeComments(false) .valueComments(false) .excludedTypes(types) .multiValuesProvider(provider) .build()

MESSAGE GENERATION DONE

SOAP CLIENTSoapClient client = SoapClient.builder() .endpointUrl("http://service.com/endpoint") .basicAuth("user", "pass") .connectTimeoutInMillis(30000) .readTimeoutInMillis(10000) .build();

client.post(soapAction, message)

P R O X Y S S L T R U S T S T O R E

MESSAGE TRANSMISSION DONE

SOAP SERVERSoapServer server = SoapServer.builder() .httpPort(8080) .acceptorThreads(4) .maxThreads(8) .reuseAddress(true) .build()

server.start()server.stop()

T I M E O U T S H T T P S K E Y S T O R E

SOAP ENDPOINTSAutoResponder responder = new AutoResponder(builder);

server.registerRequestResponder("/service", responder);

server.unregisterRequestResponder("/service");

Request RESPONDER

public interface RequestResponder {

/** * Returns a response to a SOAP message. * <p/> * @param request SOAP message to handle * @return XML response with the whole SOAP envelope */ javax.xml.Source respond(SoapMessage request);

}

ABSTRACT RESPONDERpublic abstract class AbstractResponder implements RequestResponder { // ... /** * @param invokedOperation op matched to the SOAP msg * @param message SOAP message passed by the client * @return XML response with the whole SOAP envelope */ public abstract javax.xml.Source respond( SoapOperation invokedOperation, SoapMessage message );}

Custom RESPONDERnew AbstractResponder(builder) { @Override public Source respond(SoapOperation operation, SoapMessage message) { // build the response using builder String response = builder.buildOutputMessage(operation) // here you can tweak the response //... return XmlUtils.xmlStringToSource(response) }};

MESSAGE SERVING DONE

26 minut

DEMO - THIS IS HOW WE ROLL

36 minuty

TWEET #SOAPWS IS ...???

WHY WOULD WE DO THAT???

We currently run our web services with Tomcat and SpringFramework, using Axis2 to generate Java modules from our WSDLs. Our goal was to look for an alternative to avoid constant code changes whenever the WSDL was modified.

Tracy:

WHY WOULD WE DO THAT???

We create a proxy layer so that company A does not talk to company B directly. The entire layer does not care about the WSDL structure, it sits between two companies for doing logging, queing, load-balancing, authentication, authorization, translation, etc.

Hemant:

WHY WOULD WE DO THAT???

...another issue was that the webservice was going to be changing a fair bit over the first year as other functionality was added and the service offerings changed. Having to go through the 'wsdl2java' approach every change would have been a lot of work.

Ken:

WHAT’s THE BUZZ ABOUT VERSIONING?

SOAP with CODE - 1 version

W S D L

S T U B SB U S I N E S S

L O G I C S T U B SB U S I N E S S

L O G I C

SERVER CLIENt

SOAP

SOAP with CODE - 2 versions

W S D L

S T U B S

B U S I N E S SL O G I C

SERVER

SOAP

W S D L ’

S T U B S ’

S T U B S

B U S I N E S SL O G I C

CLIENt

S T U B S ’SOAP

COMPONENT COMPATIBLE INCOMPATIBLE

SOAP HEADER ADD OPTIONAL CHANGE, REMOVE OPT.ADD, CHANGE, REMOVE REQ.

PARAMETER ADD OPTIONAL IN REQUEST ADD, CHANGE, REMOVE

OPERATION ADD A NEW OPERATION CHANGE, REMOVE

RESPONSE CHANGE

WS BACKWARD COMPATIBILITY

http://help.yahoo.com/l/us/yahoo/ewsapt/webservices/support/wss_faq_versioning.html

WISDOM BY BIG-BROTHERS‣ LAYER OF INDIRECTION PATTERN‣ ORACLE SERVICE BUS‣ ORACLE PORTAL SERVER

http://www.newhorizons.com/LOCALWEBADMIN/images/306/outlines/partner%20images/logo-oracle-large.jpghttp://www.oracle.com/technetwork/articles/web-services-versioning-094384.html

WISDOM BY BIG-BROTHERS‣ IBM WEB-SPHERE UDDI‣ IBM WEB-SPHERE SERVER

http://upload.wikimedia.org/wikipedia/commons/5/51/IBM_logo.svghttp://www.ibm.com/developerworks/webservices/library/ws-uddisecure/

SOAP with CODE - WISDOM FROM THE WEB

W S D L

S T U B S

B U S I N E S SL O G I C

SERVER

W S D L ’

S T U B S ’

http://www.gridshore.nl/blog/index.php?/archives/68-Web-service-versioning-in-the-java-world.htmlfindicons.com/icon/130548/llama_glyph?id=130575

LoL

SOAP with CODE - WISDOM FROM THE WEB

W S D L

S T U B S

B U S I N E S SL O G I C

SERVER

W S D L ’

S T U B S ’

http://www.gridshore.nl/blog/index.php?/archives/68-Web-service-versioning-in-the-java-world.html

NO VERSIONINGForce clients to migrate

LoLfindicons.com/icon/130548/llama_glyph?id=130575

SOAP with CODE - WISDOM FROM THE WEB

W S D L

S T U B S

B U S I N E S SL O G I C

SERVER

W S D L ’

S T U B S ’

http://www.gridshore.nl/blog/index.php?/archives/68-Web-service-versioning-in-the-java-world.html

DIFFERENT PACKAGEs

LoLfindicons.com/icon/130548/llama_glyph?id=130575

SOAP with CODE - WISDOM FROM THE WEB

W S D L

S T U B SB U S I N E S S

L O G I C

http://www.gridshore.nl/blog/index.php?/archives/68-Web-service-versioning-in-the-java-world.html

DIFFERENT ARTIFACTS

LoLfindicons.com/icon/130548/llama_glyph?id=130575

B U S I N E S SL O G I C

SERVER

W S D L ’

S T U B S ’

SOAP with CODE - WISDOM FROM THE WEB

W S D L

S T U B SB U S I N E S S

L O G I C

http://www.gridshore.nl/blog/index.php?/archives/68-Web-service-versioning-in-the-java-world.html

MEDIATION BY HANDLoL

findicons.com/icon/130548/llama_glyph?id=130575

SERVER

W S D L ’

S T U B S ’

W S D L

S T U B S

MEDIATOR

HOW TO DO VERSIONING IN SOAP-WS?

SOAP-WS - VERSIONING MADE EASY

W S D L

S T U B SB U S I N E S S

L O G I C

SERVER

SOAP-WS - VERSIONING MADE EASY

B U S I N E S SL O G I C

SERVER

B U I L D E R S U P P L E M E N T S E R V E R

SOAP-WS - VERSIONING MADE EASY

SERVER

D B F I L E

B U S I N E S SL O G I C

B U I L D E R S U P P L E M E N T S E R V E R

S E R V E R ’B U I L D E R ’ S U P P L E M E N T ’

OTHER STUFF

50 minute

SOAP TESTING DONE RIGHT@Server(wsdl = "http://srv.com?wsdl", binding = "Binding")public class TestExample {

@Test @Server(wsdl = URL, binding = "Binding", port = 41414) public void testSoapMock_serverPerMethod() { }

@Test public void testSoapMock_serverPerClass() { }

}

FULL SPRING INTEGRATION<bean id="soapServerFactory" class="com.centeractive.ws.server.core.SoapServerFactory"> <property name="httpPort" value="8778"/> <property name="responders"> <map> <entry key="/currencyConverter/soap" value-ref="autoResponder" /> </map> </property></bean>

FULL SPRING INTEGRATION@Autowiredprivate SoapBuilder builder;

@Autowiredprivate SoapClient client;

@Autowiredprivate SoapServer server;

ROADMAP

SOAP-ws ROADMAP

GROOVY MODULE

GRAILS PLUGIN

GRIFFON PLUGINARQUILLAN

deista.files.wordpress.com/2011/04/internet-explorer-y-mozilla-firefox.jpg?w=640

WEB-CONTAINERs

HTTP BINDING

WS-SECURITY

cdn1.iconfinder.com/data/icons/secureicons/png/512/PadLock.png

WS-ATTACHMENT

cdn1.iconfinder.com/data/icons/softwaredemo/PNG/256x256/PaperClip4_Black.png

WS-ADDRESSING

cdn1.iconfinder.com/data/icons/Primo_Icons/PNG/128x128/address_black.png

SPRING-WS

WRAP-UP

ANY QUESTIONS?

THANK YOU

TOM BUJOK

GeeCON CONFERENCE 16th of MAY 2013

@TOMBUJOKWWW.REFICIO.ORG

http://gamedevwithoutacause.com/wp-content/uploads/2011/11/singleton-12yr.jpeg