blog.smart-java.nl
Ordina J-Technologies – Java Blog

Archief ‘Web Services’ categorie




Webservices over MQ (2)

Door: Jethro Bakker, 5 June 2008

Een tweede deel over het gebruik van Spring Webservices en JMS transport.

Ons uitgangspunt is dat er meerdere type berichten (SOAP, POX) binnen komen op dezelfde queue. In een grote organisatie is het voordeel hiervan dat je maar 1x een queue hoeft aan te vragen en daar alle berichten op zet. Eventuele nieuwe berichtsoorten kunnen dan vrij gemakkelijk toegevoegd worden. Nadeel is dat we meerdere type berichten moeten kunnen afhandelen. Een uitdaging om dit efficient en met zoveel mogelijk bestaande code te kunnen doen. We willen namelijk zo min mogelijk infrastructuur code schrijven.

Standaard biedt Spring Webservices een WebServiceMessageListener aan die je kunt gebruiken om berichten te consumeren van de queue. Deze listener ondersteunt een type bericht. Je kunt namelijk maar een message factory definieeren op een WebserviceMessageListener.

In eerste instantie had ik daar een oplossing voor bedacht die er als volgt uit ziet:

class MyWebserviceMessageListener extends WebServiceMessageListener {
  private PoxMessageFactory poxMessageFactory;
  private SaajSoapMessageFactory soapMessageFactory;

  public void onMessage(Message message, Session session) {
    if ("applicatie1".equals(message.getStringAttribute("afzender"))) {
      setMessageFactory(poxMessageFactory);
    } else {
      setMessageFactory(soapMessageFactory);
    }
  }
}

Afhankelijk van een attribuut van het JMS bericht wordt besloten welke message factory gebruikt wordt. Bovenstaande code blijkt niet te werken omdat de WebServiceMessageListener initieel een message factory nodig heeft. Maar het gaat me nu even om het idee. Waarom is het niet verstandig dit zo op te lossen?

Een message driven pojo (MDP), zoals de MyWebserviceMessageListener, draait in een container. (DefaultMessageListenerContainer) Op deze container kun je het aantal consumers instellen. Bijvoorbeeld 3 of 10. Je kunt dit doen door de properties: maxConcurrentConsumers en concurrentConsumers te gebruiken. Zoals de namen van de properties al aangeven hebben we hier te maken met concurrency en onze MDP moet daarom thread safe zijn! In de referentie documentatie staat dat ook heel duidelijk:

Please also be aware that in the case where your POJO will be receiving messages on multiple threads, it is important to ensure that your implementation is thread-safe.

De oplossing zoals hier boven beschreven is niet thread safe en kan de prullenbak in omdat we meerdere concurrent consumers gaan gebruiken. De oplossing is niet thread safe omdat meerdere threads gebruik maken van dezelfde MDP. Er kunnen dus twee threads actief zijn en tegelijk een bericht verwerken. De ene thread een SOAP bericht en de andere een POX bericht. Dan gaat een van beide threads de mist in omdat het een verkeerde message factory gebruikt.

We zullen op basis van de bericht inhoud moeten beslissen of het bericht een SOAP bericht is of een standaard XML bericht. Dit doen we door de message factories in de MDP te verwijderen en te vervangen door twee JMSMessageReceivers die we zelf moeten schrijven. Zo’n receiver heeft een dependency op een message factory. In de MDP beslissen we nu naar welke receiver we gaan op basis van de bericht inhoud.

Een JMSMessageReceiver is een:

Convenience base class for JMS server-side transport objects. Contains a WebServiceMessageReceiver, and has methods for handling incoming JMS BytesMessage and TextMessage requests. Also contains a textMessageEncoding property, which determines the encoding used to read from and write to TextMessages. This property defaults to UTF-8.

Voorbeeld:

public class PoxJmsReceiver extends JmsMessageReceiver {
    public void invoke(Message message, Session session) throws JMSException {
        try {
            handleMessage(message, session);
        } catch (Exception ex) {
            JMSException jmsException = new JMSException(ex.getMessage());
            jmsException.setLinkedException(ex);
            throw jmsException;
        } 

    }
}

Deze oplossing heeft als nadeel dat het bericht twee keer gelezen wordt. Een keer in de MDP om te checken of het SOAP bericht is en een keer in het Spring Webservices framework. Bij kleine berichten maakt dit niet zoveel uit maar bij grote berichten kan dit geheugen problemen gaan geven. Een mogelijke oplossing voor dit probleem is om de eerste zoveel bytes van het bericht in te lezen in de MDP en op basis daarvan te besluiten of het een SOAP bericht is. Andere ideeen zijn uiteraard welkom.




Webservices over MQ

Door: Jethro Bakker, 8 May 2008

In een vorig project heb ik kennis gemaakt met het Spring Webservices framework. Met dit framework is het eenvoudig om een POJO als webservice beschikbaar te stellen over HTTP. In versie 1.5 is er ondersteuning toegevoegd voor MQ en SMTP. Hoe werkt dat?

Je definieert allereerst een DefaultMessageListenerContainer. De container heeft o.a. een connection factory en een destination als parameter. Daarnaast geeft je een messageListener op:

<property name="messageListener">
  <bean class="org.springframework.ws.transport.jms.WebServiceMessageListener">
    <property name="messageFactory" ref="messageFactory"></property>
    <property name="messageReceiver" ref="messageDispatcher"></property>
  </bean>
</property>

De WebServiceMessageListener komt zoals je ziet uit het Spring Webservices framework en heeft twee parameters, een message factory en een dispatcher.

Message Factory
De message factory kan bijvoorbeeld een SoapMessageFactory zijn. In ons geval niet want we gebruiken geen SOAP maar Plain Old XML (POX). Spring Webservices biedt hiervoor een DomPoxMessageFactory. Zoals de naam al aangeeft is deze implementatie gebaseerd op een DOM XML parser. Bij grote documenten kan dit veel geheugen opslokken. Mijn voorkeur gaat daarom uit naar Stax of Sax implementatie. Helaas zijn deze niet out of the box beschikbaar. Daarom heb ik er zelf eentje geschreven. De StaxMessageFactory implementeert de interface WebServiceMessageFactory. Deze interface bevat twee methoden om een WebServiceMessage te creeeren. Een methode creeert een leeg bericht en de andere een bericht op basis van een InputStream.

Message Dispatcher & Endpoint Mappings
De message dispatcher wordt wel out of the box geleverd. De dispatcher bevat een lijst van endpoint mappings. Voorbeelden van endpoint mappins zijn:
SoapActionEndpointMapping – dispatchen op basis van Soap Action
PayloadRootQNameEndpointMapping – dispatchen op basis van root XML element

De klant waar ik voor werkzaam ben heeft een specifieke wens. Er moet gedispatcht worden op basis van een attribuut van het root element. Hiervoor moet er zelf een EndpointMapping geschreven worden. Dat is gelukkig heel eenvoudig. Op basis van de AbstractMapBasedEndpointMapping kun je snel je eigen implementatie schrijven. Deze klasse dwingt af dat je twee methoden implementeert: validateLookupKey en getLookupKeyForMessage. Uiteindelijk configureer je het als volgt in Spring.

<bean id="endpointMapping" class="*MyOwnEndpointMapping">
  <property name="rootElementName" value="MyMessage"></property>
  <property name="rootAttributeName" value="MyAttribute"></property>
  <property name="mappings">
  <props>
    <prop key="A">EndpointA</prop>
    <prop key="B">EndpointB</prop>
    <prop key="C">EndpointC</prop>
  </props>
</property>
</bean>

De MyOwnEndpointMapping is nog te configureren met twee extra parameters: rootElementName en rootAttributeName. Deze parameters worden gebruikt om het attribuut te selecteren en te controleren of de root element naam klopt.De endpoints die we gebruiken overerven van AbstractMarshallingPayloadEndpoint omdat we Castor gebruiken om objecten te marshallen. Een voorbeeld van een endpoint:

public class EndpointC extends AbstractMarshallingPayloadEndpoint {
  public EndpointC(Marshaller marshaller) {
    super(marshaller);
  }
 
  public Object invokeInternal(Object request) {
    MyObject myObject = (MyObject) request;
    return myObject;
  }
}

Het aardige van deze aanpak is dat het niet uitmaakt voor de onderliggende implementatie welk transport mechanisme je gebruikt. Daarnaast is het ook niet van belang wat voor Marshaller er gebruikt wordt. Castor, JAXB het maakt voor de onderliggende implementatie niet uit. Hierdoor zijn de Endpoints makkelijk te unittesten en ook eenvoudig.

Door deze aanpak krijgen we nu ook functionaliteit cadeau. Bijvoorbeeld validatie en log functionaliteit. Door middel van interceptors kan dit eenvoudig ingeregeld worden. Aan de MyOwnEndpointMapping voeg je een property interceptors toe:

  <property name="interceptors">
    <list>
      <ref bean="loggingInterceptor" />
    </list>
  </property>
  ...
  <bean id="loggingInterceptor" class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor" />

Mocht in de toekomst toch SOAP gebruikt gaan worden dan is dit eenvoudig aan te passen door een andere message factory te gebruiken. De endpoint mapping zal dan ook aangepast moeten worden.




Sun Certified Developer for Java Web Services (SCDJWS) voorbereiding

Door: Jan-Kees van Andel, 30 January 2008

Voorbereiding voor het Sun Certified Developer for Java Web Services (pfff…) kan lasting zijn. Het is niet zoals bij SCJP, SCJD of SCEA, waar je door een studieboek heen kunt werken, want zo’n boek is er niet. Vandaar dit stappenplan.

1 Praktijkervaring

Web services is een complex onderwerp. Er zijn (te?) veel specificaties waardoor het moeilijk is om een goed overzicht te krijgen van wat er allemaal speelt in web service land. Daarom raad ik aan om niet voor het examen op te gaan zonder eerst zelf wat web services te bouwen. Zelf heb ik dat ook gedaan, op een project. Begonnen met het maken van een WSDL file met tools zoals XMLSpy en MyEclipse. Af en toe ook een beetje spieken in de gegenereerde code zorgt voor houvast.

Zeker in het begin moet je niet alles met de hand willen doen. Een WSDL file kan intimiderend overkomen, dus klik gewoon een WSDL in elkaar met XMLSpy of gebruik de annotaties van JAX-WS. JAX-WS zit niet in het examen. Het examen gaat over oudere stof, maar het concept van web services blijft hetzelfde, dus ik zou in het begin gewoon de gemakkelijkste tools gebruiken.
Ook een JAX-RPC mapping file is een gedrocht waar je meteen van weg wilt rennen. Zonder gein, die wil je niet zien. Ik zou zeggen, genereer die lekker mee met een tool zoals wsdl2java of java2wsdl. Of je gebruikt JAX-WS waarmee je de mapping file ook niet ziet.

Als dit hele stuk al abracadabra is, hoef je nog niet te denken aan certificeren. Het begint met (op zijn minst wat) praktijkervaring.

2 Monson-Haefel

Als je een keer een web service gemaakt hebt, kun je jezelf meer verdiepen in de onderliggende technieken. J2EE Web Services is de meest complete study guide. Het is een dik boek, maar de belangrijkste onderwerpen uit SCDJWS worden er dan ook uitgebreid in behandeld.

  1. Het begint met 80 pagina’s over XML, namespaces en XML Schema.
  2. Daarna nog eens 80 pagina’s over SOAP en WSDL.
  3. Het stuk daarna, over UDDI, zou ik voorlopig overslaan tot je de andere stof goed beheerst.
  4. Dan volgen er 200 pagina’s over de verschillende JAX-RPC API’s: JAX-RPC, Service Endpoints, EJB Endpoints, Client API’s, SAAJ, Handlers en Mapping files.
  5. Het stuk over JAXR is sterk gerelateerd aan UDDI, dus die slaan we ook even over.
  6. De volgende 50 pagina’s gaan over twee JAXP technologieën, namelijk SAX2 en DOM 2. TrAX wordt hier niet behandeld.
  7. De laatste 80 pagina’s gaan over Deployment van Web Services. Onderdelen hiervan zijn onder andere de deployment descriptors.

De appendixes A, B, C en H zijn interessant om te lezen, maar zover ik gemerkt heb, niet direct nuttig voor het examen. De andere zijn direct nuttig voor het examen, dus die zou ik wel doorlezen.

Als je de rest van het boek uit hebt, kun je de hoofdstukken over UDDI en JAXR doornemen. Als het goed is, zal dit goed te doen zijn.

3 XYZWS.com

Op XYZWS.com staat ook een study guide voor het examen, maar deze heeft een grote overlap met J2EE Web Services. De volgende stukken zou ik in ieder geval bestuderen.

  • JAXB (core onderdeel van het examen, niet behandeld in J2EE Web Services)
  • XML Security (idem)

De overige onderdelen (SOAP, WSDL, JAX-RPC…) zou ik nog niet lezen. Dat kost teveel tijd en je moet nog redelijk veel stof.

Maarrr, je bent al goed op weg. :)

4 Specificaties…

De Web Service wereld hangt aan elkaar van specificaties. De volgende zijn essentieel voor het examen.

  1. XML 1.0 (vooral (default/target/ ) namespaces)
  2. XML Schema 1.0 (structuren en datatypen)
  3. SOAP 1.1 (alles)
  4. WSDL 1.1 (idem)
  5. UDDI 2.0 (datastructuren en API’s)

Deze moet je ook tot in redelijk detail kennen. Ik ben zelf niet grondig door de spec gegaan, maar heb ze globaal gescand. De meeste specs worden in J2EE Web Services en XYXWS ook grondig behandeld.

  • JAX-RPC (alles)
  • JAXB (basics. JAXB binding files heb ik niet hoeven leren)

Dit is een lastige, maar deze moet je ook goed kennen.

  • WS-I Basic Profile 1.0 (dit is een lastige, dingen die in WSDL, SOAP ofzo mogen, mogen soms niet volgens deze specificatie. Je moet alles kennen)

5 Sun Blueprints

Designing Web Services with the J2EE(TM) 1.4 Platform : JAX-RPC, SOAP, and XML Technologies is een boek waarin verschillende web service onderdelen (vanuit een Sun perspectief) worden beschreven. De meeste onderdelen zijn niet interessant voor het examen, aangezien die al in de andere bronnen behandeld worden.

Vooral hoofdstuk 3 (Service Endpoint Design) moet je tot in detail kennen. Ze beschrijven een tweelagenmodel met een interaction en processing layer en die moet je tot in detail kennen. Verwacht zeker een stuk of 4-5 vragen over dit onderwerp.

6 Mikalai Zaikin

Als laatste slag kun je de samenvatting van Mikalai Zaikin gebruiken. Hij heeft per objective een samenvatting gemaakt. Laat je niet afschrikken door de 160 pagina’s. Als je de stof al beheerst hoef je deze samenvatting alleen nog maar te lezen. Het is alleen maar om je kennis nog wat op te frissen.

7 Mock examens

Ten slotte kun je nog wat mock examens doen om een beetje goed gevoel te krijgen. Ten eerste test je of je genoeg kennis hebt en zie je of je bepaalde onderdelen nog moet opfrissen. Bovendien geeft het wat extra vertrouwen in de toets (als je het goed doet tenminste :) ).

Op de volgende sites kun je mock examens vinden:

8 Het examen

Zorg dat je uitgerust op het examen aankomt. Zorg voor een goede nachtrust. Ik weet het, het is een dooddoener, maar het werkt wel. Tot ’s avonds laat leren heeft toch geen zin meer, dus zorg dan tenminste dat je wakker bent tijdens de toets.

Als je dit stappenplan volgt, moet je een goed resultaat kunnen halen. Om je een beetje vertrouwen te geven, mij is het gelukt, met 97%.