Donnerstag, 18. Juni 2009

Webservices mit EJB3

In einem schon etwas älteren Artikel bin ich bereits auf das Arbeiten mit JPA / EJB3 eingegangen. Ziel war es, mit Entity Beans Datenbanktabellen generieren zu lassen. In EJB3 Projekten kommen aber neben den Entity Beans natürlich auch Stateless und Statefull Session Beans zum Einsatz. Darin wird die Geschäftslogik gehalten. In diesem Artikel will ich nun etwas kompakt zeigen, wie diese Stateless Session Beans als Webservices genutzt werden können und wie man per SOAP auf diese Webservices zugreifen kann.

Entscheidend sind dabei folgende Annotations, die mal anhand eines Beispieles aufgezeigt werden:


package de.mortensenit.webservicedemo.person.actions;

import java.util.Date;

import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

/**
* Session Bean implementation class PersonActionDemo
*
* © 2009
*
* @author Frederik Mortensen
*/
@WebService
@SOAPBinding(style = Style.RPC)
@Stateless
public class PersonActionDemo
implements PersonActionDemoLocal,
PersonActionDemoRemote {

/**
* Person maintainance webservice, takes care of inserting and upating the
* person
*
* @param surname
* @param forename
* @param birthdate
* @return
*/
@Override
@WebMethod
public Boolean maintainPersonWS(
@WebParam(name = "surname") String surname,
@WebParam(name = "forename") String forename,
@WebParam(name = "birthdate") Date birthdate) {

// do soemething...
return true;

}

}


Die ersten zwei verwendeten Annotations betreffen dabei die Klasse an sich und lauten:
  • @WebService
  • @SOAPBinding(style=Style.RPC)
Diese Annotations ermöglichen es der Klasse, als Webservice Endpoint zu fungieren, weitere Parameter der Annotation sind optional.

Die eigentliche, aufgerufene Methode des Webservices erhält ebenfalls Annotationen:

  • @WebMethod
  • @WebParam(name="surname")
Mit der WebParam Annotation hat man hier die Möglichkeit, den nach aussen hin sichtbaren Parameter des Webservices umzubenennen und sprechende Namen zu verwenden.

Deployt man nun sein Projekt auf dem Application Server, sieht man in der JBoss Management Console unter "jboss.ws" den eigenen, neu kreierten Endpoint. Desweiteren wird nun von JBoss aus eine WSDL-Datei generiert, welche unter folgendem Pfad erreichbar sein sollte:

http://localhost:8080/{context}/{endpoint}?wsdl (Context und Endpoint sieht man in der Management Console)

Alles, was man nun zu seinem Glück noch braucht, ist ein Webservice Client. Den kann man in den aktuellen IDEs wie Eclipse und NetBeans bereits selbständig generieren lassen. Auch in .NET ist dies vollautomatisch möglich. Wer es in Eclipse ausprobieren möchte, muß zuerst Axis2 installiert haben. In Eclipse sollte man nun unter...

  • Windows
  • Preferences
  • Web Services
  • Axis2 Preferences
die Axis2 Runtime Location angeben. Ist dies einmal gespeichert, steht ein neuer Wizzard zur Verfügung:
  • File
  • New
  • Other
  • Web Service Client
Dort muß unter "Service definition" der Pfad zur WSDL-Datei angegeben werden. Nun wird ein Stub und ein CallbackHandler generiert. Wer statt mit Eclipse lieber den klassischen Weg über die Konsole gehen möchte, kann auch direkt die nötige Batch-Datei aufrufen. Zu finden ist diese unter:

{axis2installordner}\bin\wsdl2java.bat


Ruft man diese Batch-Datei mit dem Parameter -uri auf und gibt den Pfad zur WSDL-Datei an, wird ein src-Ordner erstellt, der ebenfalls Stub und CallbackHandler als generierte Klassen enthält.

Sind also Stub und co. durch den Wizzard erst einmal generiert, kann man folgende Testklasse mit Main-Methode erstellen, um den SOAP-Aufruf durchzuführen:


package de.mortensenit.webserviceclientdemo.person;

import java.rmi.RemoteException;
import java.util.Calendar;
import org.apache.axis2.AxisFault;
import de.mortensenit.webserviceclientdemo.PersonActionDemoServiceStub.MaintainPersonWS;

public class SoapTest {

public static void main(String[] args) {

try {
//filling webservice parameters
MaintainPersonWS webService = new MaintainPersonWS();
webService.setForename("Frederik");
webService.setSurname("Mortensen");
webService.setBirthdate(Calendar.getInstance());

//calling webservice
new PersonActionsServiceStub().maintainPersonWS(webService);
}
catch (AxisFault axisFault) {
axisFault.printStackTrace();
}
catch (RemoteException remoteException) {
remoteException.printStackTrace();
}

}

}


Ruft man nun die Main-Methode auf, wird der Webservice via SOAP aufgerufen und mit den Parametern befüllt, die man ausgewählt hat. Soeben haben Sie Ihren ersten Webservice erstellt. Sollten Probleme oder Fragen auftreten, bin ich gerne bereit, auf Kommentare auch per E-mail zu antworten und zu helfen.

Mögliche Fehlerquellen:
Leider hat mir die bei mir im Einsatz befindliche JBoss-Version jboss-4.2.3.GA echte Bauchschmerzen bereitet mit folgender Exception:


ERROR [SOAPFaultHelperJAXWS] SOAP request exception
java.lang.UnsupportedOperationException: setProperty must be overridden by all subclasses of SOAPMessage

Herausgekommen ist, daß sich diese JBoss-Variante mit der aktuellen Java6-Version nicht verträgt. Es gibt jedoch ein leichtes Workaround. Man muß die von JBoss verwendete Datei {jboss-installordner}\lib\jboss-saaj.jar in das Unterverzeichnis endorsed kopieren. Dies führt dazu, daß die von JBoss mitgelieferte Implementierung der Klasse SOAPMessage vorgezogen wird vor dem installierten JRE.

Quellen:
https://jax-ws.dev.java.net/jax-ws-ea3/docs/annotations.html

1 Kommentar:

  1. Hi,

    kleiner Tipp: es gibt beim JBoss auch die JBossWs/Services Ansicht auf der alle bei diesem JBoss registrierten Service Endpoints aufgelistet werden: http://localhost:8080/jbossws/services

    Sehr bequeme Variante zu sehen ob der Webservice oderntlich deployt ist und an die WSDL zu gelangen. =)

    Grüße
    Markus

    AntwortenLöschen

Hier kann jeder (auch unregistrierte) Leser seine Meinung kundtun...