# Axis2 SimpleHotel



## Ulmerschwabe (30. Apr 2007)

Hallo liebe Java-Freunde

Momentan arbeite ich mich in SOAP und Axis2 ein.
Habe mir dazu das Buch "Java Web Services mit Apache Axis2" gekauft. Dieses habe ich Schritt für Schritt durchgearbeitet (bis SimpleHotel) und das Beispiel SimpleHotel mitgemacht. Dieses habe ich sowohl in den Repository\services Ordner von Axis als auch in den axis2\Web-Inf\services Ordner von Tomcat in Form eines .aar Archivs abgelegt. Der Service und die Funktionen werden auch über axis2 und tomcat als laufend angezeigt, wenn ich mir die Services über die Weboberfläche anzeigen lasse.
Nun habe ich die Beispielanwendung (Client) vom Buch geschrieben und versucht diese sowohl mit dem StandalonServer von Axis als auch mit Tomcat laufen zu lassen.

Das ergab folgenden Fehler:


> Exception in thread "main" org.apache.axis2.AxisFault: Exception occurred while trying to invoke service method findHotel
> at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:271)
> at org.apache.axis2.description.OutInAxisOperationClient.execute(OutInAxisOperation.java:202)
> at org.apache.axis2.client.ServiceClient.sendReceive(ServiceClient.java:579)
> ...



Die Anwendung findet wohl meinen Service nicht...
Meine ClientAnwendung dazu sieht bis zu dieser Zeile wie folgt aus:


```
package de.axishotels.client;

import javax.xml.namespace.QName;

import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.databinding.utils.BeanUtil;
import org.apache.axis2.engine.DefaultObjectSupplier;

import de.axishotels.Hotel;
import de.axishotels.RoomType;


public class AxisHotelsClient {
public static void main(String[] args1) throws AxisFault{
		ServiceClient sender = new ServiceClient();
		Options options = sender.getOptions();
		EndpointReference targetEPR = new EndpointReference(
				"http://localhost:8080/axis2/services/SimpleHotelService");
		options.setTo(targetEPR);
		
		// die Operation "findHotel" soll aufgerufen werden
		QName opFindHotel = new QName("http://axishotels.de/xsd", "findHotel");

		
		//Parameter für die Operation "findHotel" definieren
		String hotelCode ="AX050";
		Object[] opArgs = new Object[] {hotelCode};
		
		// OMElement mit der Request-Nachricht erzeugen
		OMElement request = BeanUtil.getOMElement(opFindHotel, opArgs, null, false, null);
		
		// Request an den Service schicken... der Aufruf erfolgt
		// synchron mit dem Kommunikationsmuster IN-OUT
		OMElement response = sender.sendReceive(request);
...}
}
```

Die services.xml sieht folgendermaßen aus:

```
<service>
	<description>SimpleHotelService</description>
	<parameter name="ServiceClass">
		de.axishotels.HotelService
	</parameter>
	<operation name="getHotels">
		<messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
	</operation>
	<operation name="findHotel">
		<messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
	</operation>
</service>
```

Wie in der services.xml zu sehen ist bietet SimpleHotelService die Operationen:
- findHotel
- getHotels
an.

Kann mir bitte einer sagen, wo ich meinen Fehler habe??

Gruß Marco


----------



## Gast (3. Mai 2007)

Lieber Marco,

hierzu würde ich gerne Deinen Sourcecode und Dein AAR-File sehen, vielleicht kannst Du das ganze an marc@teufel.net schicken? 
Ich helfe Dir gerne.

Viele Grüsse,

Marc


----------



## da.winter (22. Mai 2007)

Guten Tag,

ich habe ebenfalls das Buch und habe direkt abgeleitet meinen eigenen WebService erstellt. Ebenfalls unter Tomcat.
Der WebService läuft soweit. 
Nun mache ich mich gerade an das Programmieren des Clients. Aus diesem Grund fände ich es toll, wenn ihr die Antworten hier posten würdet, da ich im Moment ebenfalls ein paar Probleme habe.

mfg Daniel


----------



## BanditsReno (23. Mai 2007)

Hallo,
ich entwickel jetzt den zweiten Webservice mittels Axis2 und mir sind da ein paar komische Dinge aufgefallen.

Erstens sagt die Fehlermeldung wie oben erwähnt (Exception occurred while trying to invoke service method findHotel) nichts über die wahre Ursache aus. Der Grund kann zum einen darin begründet liegen, dass man nicht weiß, wie groß ein verwendetes Array wird( gerade bei Datenbankaufrufen). Abhilfe schafft die ArrayList, und diese dann in ein Array überführen.
Zweitens kommt diese Meldung auch dann zustande, wenn eine Methode serverseitig geschrieben wurde, aber nie benutzt wird.

Da ja Marc Teufel auch in diesem Forum aktiv ist, möchte ich ihn an dieser Stelle gleich fragen, warum er die Methode "getHotels" in der service.xml aufführt und im Client, obwohl diese eigentlich nie dafür bestimmt ist, im Client aufgerufen zu werden, zumal es auch gar nicht funktioniert.

MfG


----------



## da.winter (23. Mai 2007)

Also ich quäle mich Momentan mit meinem eigenen WebService herum. Ich bin leider weit Entfernt als Programmierer bezeichnet zu werden, jedoch gebe ich mir sehr viel mühe.

Mein WebService soll später folgende Aufgaben erfüllen:

Der Benutzer gibt in einem Browser eine AngebotsNummer ein, diese wird dann meinen Service gesendet. Dieser prüft ob das Angebot(ist ein PDF File) vorhanden ist. 
Ist es nicht vorhanden erhält er eine PDF Datei und kopiert diese in ein Verzeichnis auf dem Server. Im Anschluss zeigt er sie dem Benutzer im Browser an.
Ist die pdf Datei vorhanden, soll er sie dem Benutzer im Browser anzeigen.
Nun verstehe ich nicht wie ich dem Benutzer meine Datei im Browser anzeigen lassen kann.

Hier der QuellCode, ich hoffe es kann mir jmd helfen...:

#Klasse Angebotsaufrufe

```
package AngebotService;

import java.io.*;
import java.net.URI;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.awt.Desktop;




public class AngebotsAufrufe extends CopyAngebot
{
    String usr, pwd, host;
    String speicherort 	= 	null;
    String	verzeichnis = 	null;
  	String	bemerkung   = 	"test";
  	String	datum	    = 	"test";
  	String 	uhrzeit     = 	"test";
  	String response		=	null;
  	String angebotsnr 	= 	null;
	Connection con 		= 	null;
	Statement smt  		= 	null;
	Reader datei		= 	null;
	
	
	

	public String CreateAngebot(String pdffile)
	{
		angebotsnr = pdffile;
		usr  = "dewea083";
		pwd  = "";
		host = "jdbc:mysql://localhost:3306/Angebotsspeicher"; 						//Datenbank auf Server
		if(pdffile == null)
		{
			System.out.println("ERROR ANGEBOT CANNOT BE NULL!");
			return null;
		}
		else
		{ 
			try
			{					 	

				src 					= "/home/dewea083/Documents/1178526328411.pdf";		 	 																	//mkordner = new File("/usr/share/tomcat/webapps/pdf/"+angebotsnr).mkdir();		//erstelle einen Ordner der die AngebotsNummer hat
				CopyAngebot daten 	= new CopyAngebot();		 	 
		 	 	dest 					= "/srv/www/htdocs/pdf/"+pdffile+".pdf";							//gibt den Speicherort und den Dateinamen für das Angebot an
		 	 	daten.copyFile(src, dest); 										//Datei wird in das Verzeichnis kopiert		 	 

		 	 	verzeichnis = dest;
		 	 	Class.forName("com.mysql.jdbc.Driver");
		 	 	con 		 = DriverManager.getConnection(host, usr, pwd);																		//formatiert den Verzeichnisnamen so, dass er in der Datenbank gespeichert werden kann
		 	 	smt		 = con.createStatement();						
		 	 	String sql2 = "INSERT INTO Angebotverzeichnis(AngebotsNr,Verzeichnis,Bemerkung,Datum,Uhrzeit)" +
			 		       "VALUE(" +angebotsnr+ ",\"" +verzeichnis+ "\",\"" +bemerkung+"\",\"" +datum+ "\",\"" +uhrzeit+"\");";	
			 
		 	 	smt.executeUpdate(sql2);											//Daten vom Angebot werden in der DB gespeichert	 

		 	 	System.out.println("Angebot "+pdffile+".pdf"+" wurde erstellt");
		 	 	response = "Neues PDF erstellt, jetzt bitte anzeigen";
		 	 	con.close();
		 	 	smt.close();
		 	 	return response; //Hier soll irgendwie die PDF dem Benutzer angezeigt werden
			}		
			catch(Exception ex)
			{						
			System.out.println(ex);
			return null;
			}
		}
	}	
	
	public String GetAngebot(String pangebot)
	{
		usr  = "dewea083";
		pwd  = "";
		host = "jdbc:mysql://localhost:3306/Angebotsspeicher"; //Datenbank auf Server
		if(pangebot == null)
		{
			System.out.println("ERROR ANGEBOT CANNOT BE NULL!");
			return null;
		}
		else
			{	
				try
				{	
				 System.out.println("Gesucht wird: "+pangebot);
				 Class.forName("com.mysql.jdbc.Driver");				//JDBC Treiber laden
				 con = DriverManager.getConnection(host, usr, pwd);		//Verbindung aufbauen
				 smt =con.createStatement();
				 String sql = "SELECT AngebotsNr From Angebotsspeicher.Angebotverzeichnis " +
				 			  "WHERE AngebotsNr ="+pangebot;
				 ResultSet rst = smt.executeQuery(sql);					//SQL Anweisung ausführen
				 System.out.println("Angebot wird gesucht");			//Es wird nach der Angebotsnummer gesucht
				 
				 
				 	while (rst.next())
				 	{
					 speicherort = rst.getString(1);				   //Gib mir das Verzeichnis wo die Datei liegt 
				 	}
					 con.close();
					 smt.close();
				}
				catch(Exception ex)
				{						
				System.out.println(ex);
				return null;
				}
				if (speicherort == null)
				{
					AngebotsAufrufe ca1 = new AngebotsAufrufe();
					ca1.CreateAngebot(pangebot);
					response = "Angebot nicht vorhanden. Erstelle es jetzt";	
				}
				else
				{
					System.out.println("Angebot "+pangebot +" bereits vorhanden");
					response = "Angebots vorhanden, ich zeige es dir jetzt an";
				}
				return response;
			}
	}
}
```

#Klasse AngebotsService

```
package AngebotService;


public class AngebotsService 
{

	public String findeAngebot(String fangebot)
	{
		AngebotsAufrufe aa1 = new AngebotsAufrufe();
		return aa1.GetAngebot(fangebot);
	}

	public String erstelleAngebot(String eangebot)
	{
		AngebotsAufrufe aa2 = new AngebotsAufrufe();
		return aa2.CreateAngebot(eangebot);
	}
}
```
Die Klasse CopyAngebot, ist lediglich für das kopieren der pdf datei von einem zum anderen Ort zuständig.


----------



## Flipperdream (15. Jul 2007)

Hallo zusammen!

Schön zu wissen das ich nicht alleine bin mit diesem Problem!

Ich würde gerne mal eine Erklärung haben wie die Übergabe der Antworten des SimpleHotelService erfolgt. Bei "findHotel" wird ein Hotel als Object über geben und per returnTypes das Object als Type "Hotel" definiert. Das ist so weit auch klar. Per "Hotel hotel =(Hotel) response[0]; wird die Antwort des WebSerives übergeben. Wie wird nun die Methode "getHotels()" im Client realisiert?
Es werden doch nun ein Array vom Type Hotel übergeben, wie muss ich das im Client umsetzten?

Danke!!!


----------



## NetEti (18. Jul 2007)

Hallo zusammen,
falls dieser späte Post noch interessiert :? , getHotels() geht.
- von Hand: 

```
Class[] returnTypes = new Class[]{Hotel.class, Hotel.class, Hotel.class};
		Object[] result = BeanUtil.deserialize(response, returnTypes, new DefaultObjectSupplier());
		for (Object hotelObject : result) {
			Hotel hotel = (Hotel) hotelObject;
		...
- generiert:
		SimpleHotelServiceSimpleHotelServiceHttpportStub stub = new SimpleHotelServiceSimpleHotelServiceHttpportStub();
		Hotel[] hotels = stub.getHotels().get_return();
		for (Hotel hotel: hotels) {
		...
```


----------



## NetEti (21. Jul 2007)

hi, wegen Nachfrage kurz die allgemeinere Form:

```
Class[] returnTypes = new Class[]{Hotel[].class};
  Object[] result = BeanUtil.deserialize(response, returnTypes, new DefaultObjectSupplier());
  Hotel[] liste = (Hotel[]) result[0];
  for (Hotel hotel : liste) {
    ...
```
P.S.:	'for (Hotel hotel : liste) {...' geht ab 1.5, googeln mit java foreach


----------



## Flipperdream (5. Aug 2007)

Hallo zusammen,

nachdem nun die RPC's im Vordergrund standen, wollte ich mich gerne mit den anderen Aufrufmustern beschäftigen (nicht blockierende Clients mit zwei Verbindungen usw.).

Hat da jemand schon Erfahrungen? 
In den Bsp im Buch werden immer nur String Variablen übertragen. Kann man auch eigene Komplexe Datentypen in einer SOAP Message übertragen, die in einer eigenen XML Schema-Beschreibung enthalten ist?
z.B stellt der Client eine Anfrage an den Webservice nach einem Hotel mit den Parametern Preis(Double), Verfügbarkeit von freien Zimmern (Zeitspanne) und möchte eine Liste der Zimmer erhalten, wo alle Informationen enthalten sind.

Bei den RPC's funktioniert das ja recht gut, nur kann manchmal eine Abfrage mehrere Minuten dauern und der Client soll in dieser Zeit ja nicht unbedingt immer blockiert sein, daher mein Interesse an den anderen Aufrufmustern.

DanKe!


----------



## Flipperdream (6. Aug 2007)

Flipperdream hat gesagt.:
			
		

> Hallo zusammen,
> 
> nachdem nun die RPC's im Vordergrund standen, wollte ich mich gerne mit den anderen Aufrufmustern beschäftigen (nicht blockierende Clients mit zwei Verbindungen usw.).
> 
> ...



So ich habe mal schon weiter experimentiert und folgenden Sachstand:

ich habe folgenden Code:

```
public static OMElement createAnfrage()
	{	
		OMFactory fac = OMAbstractFactory.getOMFactory();
		OMNamespace ns = fac.createOMNamespace("http://www.firma_abc.de/","abc");
		OMElement SuchePersonAnfrage= fac.createOMElement(
				"SuchePersonAnfrage", ns);
		OMElement such1 = fac.createOMElement("nachname", ns, SuchePersonAnfrage);
		such1.setText("Meier");
		OMElement such2 = fac.createOMElement("vorname", ns, SuchePersonAnfrage);
		such2.setText("otto");
		OMElement such3 = fac.createOMElement("alter",ns,SuchePersonAnfrage);
		such3.setText("50");
		
		
		return SuchePersonAnfrage;


	}
	
public static void main(String[] args) throws Exception
	{		
		OMElement anfrage = createAnfrage();
		// ... 
	}
```

dieser soll folgende SOAP Nachricht erzeugen:

```
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
	<soapenv:Body>
		<abc:SuchePersonAnfrage xmlns:abc="http://www.firma_abc.de/">
			<abc:nachname>Meier</abc:nachname>
			<abc:vorname>otto</abc:vorname>
			<abc:alter>50</abc:alter>
		</abc:SuchePersonAnfrage>
	</soapenv:Body>
</soapenv:Envelope>
```

dabei soll die Nachricht die folgendene Struktur /Abhängigkeit haben (soll):

```
anfrage:
firstchild:
	lokalname=nachname
	value=Meier
	
lastchild:
	localname=alter
	value=50
```

jedoch ist es leider so (ist):


```
anfrage:
firstchild:
	lokalname=nachname
	firstchild: 
		localname=include
		value=Meier
	lastchlid:
		localname=include
		value=Meier
lastchild:
	localname=alter
	firstchild: 
		localname=include
		value=50
	lastchlid:
		localname=include
		value=50
```

Was habe ich im oben aufgelisteten Code falsch gemacht, damit meine gewünschte "Soll" Struktur/Abhängigkeit erzeugt wird.
Wenn ich diese Struktur nicht einhalte habe ich Probleme mit dem Verarbeiten der Nachricht, da ich die entsprechenden Werte nicht abgreifen kann. 

Kann ich statt dem setText(String) auch andere Werte z.B. double, Boolean usw in die Nachricht integrieren?

Vielen Dank schon mal im voraus.


----------



## vase2k (16. Feb 2008)

moin moin ..

nachdem das Beispiel aus dem Buch bei mir wunderbar funktioniert hat, habe ich mir einen webservice (TestService.java) geschrieben, über den ich aus einer datenbank informationen an einen client (TestClient.java) senden will. für den transport werden die daten in einem vektor in einer transportklasse (TransportContainer.java) gespeichert.

TestService.java

```
package de.testService;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Vector;

public class TestService {

    public Connection con = null;
    TransportContainer tc = new TransportContainer();
    Vector v = new Vector();

    public final void connection() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        con = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/travelagent", "root", "");
    }

    public TransportContainer getHotels(String table) {
        try {
            connection();
            String sql = "SELECT * FROM " + table;
            PreparedStatement pStmt = con.prepareStatement(sql);
            ResultSet rs = pStmt.executeQuery();
            while (rs.next()) {
                v.addElement(new Hotel(rs.getString(2), rs.getString(3), rs
                        .getString(4), rs.getString(6), rs.getInt(5)));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        tc.setData(v);
        return tc;

    }

}
```

TransportContainer.java

```
package de.testService;

import java.util.Vector;

public class TransportContainer {

    public TransportContainer() {

    }

    public Vector v;

    public void setData(Vector data) {
        this.v = data;
    }

    public Vector getData() {
        return this.v;
    }
}
```



TestClient.java

```
package de.wsTester;

import javax.xml.namespace.QName;

import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.rpc.client.RPCServiceClient;

import de.testService.*;

public class TestClient {

    public static void main(String[] args) throws AxisFault {
       
        RPCServiceClient sender = new RPCServiceClient();
        Options options = sender.getOptions();

        EndpointReference targetERP = new EndpointReference(
                "http://localhost:8080/axis2/services/testService");
        options.setTo(targetERP);

        QName opGetHotels = new QName("http://testService.de", "getHotels");

        String table = "hotels";
        Object[] opArgs = new Object[] { table };

        Class[] returnTypes = new Class[] { TransportContainer.class };
        Object[] response = sender.invokeBlocking(opGetHotels, opArgs,returnTypes);
    }

}
```


verwendeter applikationsserver ist der jboss 4.2.0.GA, axis2 der version 1.3 wurde als war-file ins deploy-verzeichnis kopiert.

das deployen des webservices funktioniert wunderbar, der webservice liefert auch die gewünschten ergebnisse, doch wenn ich den webservice über den client anspreche, bekomme ich folgende exception:


```
Exception in thread "main" java.lang.IllegalArgumentException: argument type mismatch
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.apache.axis2.databinding.utils.BeanUtil.deserialize(BeanUtil.java:391)
    at org.apache.axis2.databinding.utils.BeanUtil.processObject(BeanUtil.java:655)
    at org.apache.axis2.databinding.utils.BeanUtil.ProcessElement(BeanUtil.java:603)
    at org.apache.axis2.databinding.utils.BeanUtil.deserialize(BeanUtil.java:535)
    at org.apache.axis2.rpc.client.RPCServiceClient.invokeBlocking(RPCServiceClient.java:103)
    at de.wsTester.TestClient.main(TestClient.java:29)
```

laut soap-monitor schickt der webservice auch eine richtige antwort raus, allerdings scheint der client diese nicht verarbeiten zu können:


```
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
    <ns:getHotelsResponse xmlns:ns="http://testService.de">
      <ns:return xmlns:ax22="http://testService.de/xsd" type="de.testService.TransportContainer">
        <ax22:data type="de.testService.Hotel">
          <ax22:hotelCity>München</ax22:hotelCity>
          <ax22:hotelCode>AX001</ax22:hotelCode>
          <ax22:hotelName>Axis2 Grand Hotel</ax22:hotelName>
          <ax22:numOfStars>5</ax22:numOfStars>
        </ax22:data>
      </ns:return>
    </ns:getHotelsResponse>
  </soapenv:Body>
</soapenv:Envelope>
```

wo liegt mein fehler? auch über hinweise, was ich evtl noch besser machen könnte, würde ich mich freuen.

danke im voraus

matthias


----------



## Gast (24. Okt 2008)

Hallo, ich habe nun auch die getHotels() Methode am laufen. Jedoch finde ich es unschön,im Client den Result-Typ als fixes Object-Array zu implementieren. Wie übergebe ich denn z.B. ein Array mit variabler Größe dann?

Sind Arraylists / Lists / Vektoren etc überhaupt möglich? Mal abgesehen von der Problematik bei Java-Spezifischen Typen wie Vektoren und einem Webservice.

Wie würde denn eine Verkettung zwischen Java und .Net-Webservices zu realisieren sein, wenn ich nun variable Arraygrößen habe?

Grüße


----------

