RSS

Schlagwort-Archive: tomcat

Tomcat auf Ubuntu für Eclipse verwenden

Tomcat auf Ubuntu für Eclipse verwenden

Wenn man versucht einen installierten Tomcat-Server z.B. für Debugging in Eclipse zu verwenden und bekommt die Fehlermeldung, dass die Runtime nicht verwendet werden kann, dann kann das an den unterschiedlichen Installationsverzeichnissen der Tomcat Installation liegen.

Nachdem man Tomcat installiert hat, wird die Installation auf /usr/share, /var/lib, /var/log etc. verteilt. Damit scheint zumindest die „Indigo“ Version von Eclipse, Probleme zu haben. Fasst man die verteilten Verzeichnisse über Softlinks wieder in ein Verzeichnis zusammen, dann funktioniert die Einbindung von Tomcat in Eclipse.

sudo apt-get install tomcat6
cd /usr/share/tomcat6
sudo ln -s /var/lib/tomcat6/conf conf
sudo ln -s /etc/tomcat6/policy.d/03catalina.policy conf/catalina.policy
sudo ln -s /var/log/tomcat6 log
sudo chmod -R 777 /usr/share/tomcat6/conf

Anschließend muss man noch die Runtime über Window/Preferences/Sever/Runtime Environments hinzufügen, das entsprechende Verzeichnis (zum obigen Beispiel) wäre dann  /usr/share/tomcat6.

Falls der Tomcat Server nicht gestartet werden kann, liegt das oft daran, dass er bereits beim Booten des OS über ein Skript gestartet wurde. Das Stoppen geht einfach über:

sudo service tomcat6 stop

Anschließend sollte sich der Tomcat Server in Eclipse starten lassen.

Hinweis: Die Informationen wurden aus stackoverflow entnommen und aufbereitet!

 
Hinterlasse einen Kommentar

Verfasst von - Februar 22, 2012 in IT

 

Schlagwörter: ,

JSON Provider erstellen. Part 5: Ressourcen, Parameter, CRUD, JSON- und XML-Response


Nachdem ich im vorigen Teil die grundsätzliche Vorgehensweise zum Erstellen eines REST-Services auf Tomcat mit der Jersey-Bibliothek erläutert habe, will ich diesem Teil noch zeigen, wie man Klassen für Ressourcen definiert, CRUD anwendet und einen REST-Service JSON sprechen läßt. Dazu verwende ich die generierte „Kontakte“-Klasse aus dem Artikel „JAXB mit Eclipse nutzen“ im REST-Jargon als Ressource. Die Server-Klasse kann sowohl XML, als auch JSON zurückgeben.

Wer mehr zu Rest und dessen Vokabular erfahren will, dem seien u. a. folgendeArtikel empfohlen: „OData: die Daten API des Webs„, „JSON Provider erstellen. Part 4: Mit Tomcat und Jersey REST Services erstellen“ und „Representational state transfer (REST)„.

 

Die Server Klasse um JSON und JAXB erweitern

Im letzten Teil habe ich mehr oder weniger sinnlosen Text über REST ausgegeben. Das soll sich nun ändern, die Texte sind nicht unbedingt sinnvoller ;-), aber immerhin erfolgt die Ausgabe nicht mehr direkt, sondern über das Einlesen und Schreiben einer XML Datei („Kontakte.xml“), die als Datenbank dient. Alle Kontakte werden auf dem Server von ihr gelesen bzw. in sie geschrieben – mit JAXB sollte das kein Problem darstellen. Bei der Anwendung von CRUD bietet es sich an diese Datei entsprechend zu synchronisieren, also neue Kontakte hinzuzufügen (C = Create), alle oder einzelne Kontakte zu lesen (R = Read), Kontakte zu verändern (U = Update) und schließlich auch Kontakte zu löschen (D = Delete).

Die Schnittstelle zwischen der Server-Klasse und der XML-Datei, stellt die Klasse „KontakteHandler“ dar. Mit ihr kann man die CRUD Operationen durchführen.

Man kann das vorhandene Projekt weiterverwenden, oder ein Neues erstellen.

1. Erstellen Sie ein “Dynamic Web Project” mit Eclipse

2. Kopieren der Jersey-Jars und die JAXB-Jars in das Verzeichnis WebContent/WEB-INF/lib des Projektes. Kopieren der generierten JAXB-Klassen (aus dem Artikel „JAXB mit Eclipse nutzen„) in das „src/generated“ Unterverzeichnis des Projektes. Kopieren der Datei „Kontakte.xml“ in das „WebContent“ Verzeichnis.

 

4. Source-Code für die Klasse „KontakteHandler“ erstellen:

package org.jkhofmann.dyndns;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.Writer;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import generated.*;

// Klasse (Singleton) zur Verwaltung der "Kontakte" Ressource
public class KontakteHandler {
	private String xmlFileName = "Kontakte.xml";
	private static KontakteHandler instance = null;
	private Kontakte kontakte = null;
	private boolean isSyncedWithFile = false;

	private KontakteHandler() {

	}

	public static KontakteHandler getInstance() {
		if (instance == null) {
			instance = new KontakteHandler();
		}
		return instance;
	}

	private void readKontakte() {
		Kontakte kontakteRet = null;
		try {
			// create JAXB context and instantiate unmarshaller
			JAXBContext context = JAXBContext.newInstance(Kontakte.class);
			Unmarshaller um = context.createUnmarshaller();
			this.kontakte = (Kontakte) um.unmarshal(new FileReader(xmlFileName));
			isSyncedWithFile = true;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void writeKontakte() {
		try {
			// create JAXB context and instantiate marshaller
			JAXBContext context = JAXBContext.newInstance(Kontakte.class);
			Marshaller m = context.createMarshaller();

			m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

			Writer w = null;
			try {
				w = new FileWriter(xmlFileName);
				m.marshal(this.kontakte, w);
			} finally {
				try {
					w.close();
				} catch (Exception e) {
				}
			}
			isSyncedWithFile = true;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public Kontakte getKontakte() {
		if (!isSyncedWithFile) {
			this.readKontakte();
		}

		return this.kontakte;
	}

	public Kontakte searchKontakte(String nameArg) {
		Kontakte kontakteRet = null;
		boolean isContactFound = false;

		if (!isSyncedWithFile) {
			this.readKontakte();
		}

		for (int i = 0; i < this.kontakte.getKontakt().toArray().length; i++) {
			Kontakte.Kontakt k = kontakte.getKontakt().get(i);
			if (k.getName().equals(nameArg)) {
				if (!isContactFound) {
					kontakteRet = new Kontakte();
					isContactFound = true;
				}

				kontakteRet.getKontakt().add(k);
			}
		}

		return kontakteRet;
	}

	public void setKontakte(Kontakte kontakte) {
		this.kontakte = kontakte;
		this.writeKontakte();
	}

	public void setXmlFileName(String xmlFileName) {
		this.xmlFileName = xmlFileName;
	}
}

5. Erweitern der Server Klasse um die Repräsentation JSON und die Verwendung der Klasse „KontakteHandler“:

package org.jkhofmann.dyndns;

import java.io.File;

import javax.servlet.ServletContext;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

import generated.*;

@Path("/kontakte")
public class HelloRestService {
	@Context UriInfo uriInfo;
	@Context Request request;
	@Context ServletContext context;

	// This method is called if JSON is requested. If QueryParam is empty, all contacs will be
	// returned. Otherwise the contact will be searched in the contact list and if it exists it
	// will be returned.
	@GET
	@Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
	public Kontakte getJSON(@QueryParam("name") String name) {
		Kontakte kontakteRet = null;

		// Set path to the contacts xml source file (it is the real path on the tomcat server):
	    String strBas = context.getRealPath("/") + "Kontakte.xml";
	    KontakteHandler.getInstance().setXmlFileName(strBas);

	    // Depending on if QueryParam is set, select the right handler method
		if ((name != null) && name.trim().length() > 0) {
			// if QueryParam is set, it will be searched for it:
			kontakteRet = KontakteHandler.getInstance().searchKontakte(name);
		} else {
			// if QueryParam is NOT set, return all contacts:
			kontakteRet = KontakteHandler.getInstance().getKontakte();
		}

		return kontakteRet;
	}

	// This can be used to test the integration with the browser
	@GET
	@Produces( { MediaType.TEXT_XML })
	public Kontakte getXML(@QueryParam("name") String name) {
		Kontakte kontakteRet = null;

		// Set path to the contacts xml source file (it is the real path on the tomcat server):
	    String strBas = context.getRealPath("/") + "Kontakte.xml";
	    KontakteHandler.getInstance().setXmlFileName(strBas);

	    // Depending on if QueryParam is set, select the right handler method
		if ((name != null) && name.trim().length() > 0) {
			// if QueryParam is set, it will be searched for it:
			kontakteRet = KontakteHandler.getInstance().searchKontakte(name);
		} else {
			// if QueryParam is NOT set, return all contacts:
			kontakteRet = KontakteHandler.getInstance().getKontakte();
		}

		return kontakteRet;
	}
}

 

6. Erstellen und Anpassen der „web.xml“ Datei

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="WebApp_ID" version="2.5">
	<display-name>HelloRestService</display-name>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>default.htm</welcome-file>
		<welcome-file>default.jsp</welcome-file>
	</welcome-file-list>
	<servlet>
		<servlet-name>HelloRestService</servlet-name>
		<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
		<init-param>
			<param-name>com.sun.jersey.config.property.packages</param-name>
			<param-value>org.jkhofmann.dyndns</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>HelloRestService</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
</web-app>

 

7. Erstellen und Deployen des WAR-Archives, z.B. „JerseyJAXBRestTest1.war“

 

Parameter: PathParam, QueryParam, FormParam etc.

Will man auf eine bestimmte Ressource zugreifen, kann dies u.a. über eine Parametrisierung des URI-Pfades geschehen (PathParam), z.B. „GET /artikel/123„, oder durch einen oder mehrere Aufrufparameter (QueryParam), z.B. „GET /artikel?id=123“ geschehen. QueryParam lässt sich relativ einfach anwenden, wie das Beispiel der Server Klasse zeigt, hier wird er Parameter „name“ ausgewertet, ist er angegeben, wird nach einem Kontakt mit diesem Namen gesucht. Ist das nicht der Fall, werden alle Kontakte ausgegeben. Mit FormParam lassen sich Formular-Parameter abfragen, wie sie in HTML-Formularen übergeben werden.

Weitere Informationen und Parameter sind u.a. in http://jsr311.java.net/nonav/releases/1.0/index.html zu finden.

Die Anwendung von QueryParam wurde bereits im vorigen Beispiel veranschaulicht. FormParam kommt in einem späteren Beispiel zur Anwendung. Im folgenden Beispiel wird die Verwendung von PathParam gezeigt:

@Path("/users/{username}")
public class UserResource {

    @GET
    @Produces("text/xml")
    public String getUser(@PathParam("username") String userName) {
        ...
    }
}

 

Testen

Direkt im Browser

Man kann sich die Ergebnisse direkt in einem Browser anschauen, der Link (ohne QueryParam) lautet: http://localhost:8080/JerseyJAXBRestTest1/kontakte

Sollen nur die Kontakte mit einem bestimmten Namen angezeigt werden, lautet die URL beispielsweise: http://localhost:8080/JerseyJAXBRestTest1/kontakte?name=Name1

Advanced Rest Client

Google Chrome Nutzer können auch die Erweiterung „Advanced Rest Client“ verwenden, sie bietet u.a. den Vorteil, dass man sich den JSON-Response direkt anschauen kann. Dazu erweitert man den Header um „Accept“ mit dem Inhalt „application/json“ und drückt anschliessend den „Send request“ Knopf.

Ohne QueryParam: http://localhost:8080/JerseyJAXBRestTest1/kontakte

Ergebnis:

Mit QueryParam: http://localhost:8080/JerseyJAXBRestTest1/kontakte?name=Name1

Ergebnis:

Java Client

Zum Testen des Services kann man beispielsweise folgenden Java-Client implementieren:

package org.jkhofmann.dyndns;

import java.net.URI;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.representation.Form;

public class JerseyJAXBRestTest1Client {
	public static void main(String[] args) {
		ClientConfig config = new DefaultClientConfig();
		Client client = com.sun.jersey.api.client.Client.create(config);
		WebResource service = client.resource(getBaseURI());
		// Get XML
		System.out.println(service.path("kontakte").accept(
				MediaType.TEXT_XML).get(String.class));
		// Get XML for application
		System.out.println(service.path("kontakte").accept(
				MediaType.APPLICATION_JSON).get(String.class));
		// Get JSON for application
		System.out.println(service.path("kontakte").accept(
				MediaType.APPLICATION_XML).get(String.class));
		// Testen von @QueryParam, Methode queryParam baut URL entsprechend zusammen,
		// z.B. GET http://localhost:8080/JerseyJAXBRestTest1/kontakte?name=Name1:
		System.out.println(service.queryParam("name", "Name1").path("kontakte").accept(
				MediaType.APPLICATION_XML).get(String.class));

	}

	   private static URI getBaseURI() {
		return UriBuilder.fromUri(
				"http://localhost:8080/JerseyJAXBRestTest1").build();
	}

}

Das Ergebnis:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Kontakte><Kontakt><Name>Name1</Name><Vorname>Vorname1</Vorname><eMail>eMail1</eMail></Kontakt><Kontakt><Name>Name2Neu</Name><Vorname>Vorname2Neu</Vorname><eMail>eMail2Neu</eMail></Kontakt><Kontakt><Name>Name3Neu</Name><Vorname>Vorname3Neu</Vorname><eMail>eMail3Neu</eMail></Kontakt></Kontakte>
{"Kontakt":[{"Name":"Name1","Vorname":"Vorname1","eMail":"eMail1"},{"Name":"Name2Neu","Vorname":"Vorname2Neu","eMail":"eMail2Neu"},{"Name":"Name3Neu","Vorname":"Vorname3Neu","eMail":"eMail3Neu"}]}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Kontakte><Kontakt><Name>Name1</Name><Vorname>Vorname1</Vorname><eMail>eMail1</eMail></Kontakt><Kontakt><Name>Name2Neu</Name><Vorname>Vorname2Neu</Vorname><eMail>eMail2Neu</eMail></Kontakt><Kontakt><Name>Name3Neu</Name><Vorname>Vorname3Neu</Vorname><eMail>eMail3Neu</eMail></Kontakt></Kontakte>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Kontakte><Kontakt><Name>Name1</Name><Vorname>Vorname1</Vorname><eMail>eMail1</eMail></Kontakt></Kontakte>

In der zweiten Zeile ist der JSON Response und in der vierten Zeile die Rückgabe mit @QueryParam.

 

Jetzt aber: CRUD

Das R(Read) in CRUD haben wir jetzt ausreichend getestet, bleiben noch C (Create), U(Update) und D(Delete). Im folgenden Beispiel wird die Server Klasse entsprechend erweitert und mit unserer Datenbank „Kontakte.xml“ synchronisiert.

Folgende HTTP Operationen werden in diesem Zusammenhang verwendet:

HTTP Operation CRUD
POST Create
GET Read
PUT Update
DELETE Delete

 

PUT – Update

Die folgende Methode dient der Server Klasse dazu, einen Kontakt zu verändern. Hier wird der @FormParam benutzt, wie er beispielsweise in einem HTML Formular verwendet wird.

Die KontakteHandler Klasse wird wie folgt erweitert:

	public void updateKontakte() {
		this.writeKontakte();
	}

Die Server Klasse muss dazu wie folgt erweitert werden:

...
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
...
	// PUT operation to update data. Accepts parameters as form parameters like they usually used
	// in HTML pages. Shows the usage of @FormParam.
	@PUT
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public Response putContact(@FormParam("name") String nameArg,
							   @FormParam("nameNeu") String neunameArg,
							   @FormParam("vnameNeu") String neuvnameArg,
							   @FormParam("emailNeu") String neuemailArg,
							   @Context HttpServletResponse servletResponse) {
		Response resRet = Response.noContent().build();;

		// Set path to the contacts xml source file (it is the real path on the tomcat server):
	    String strBas = context.getRealPath("/") + "Kontakte.xml";
	    KontakteHandler.getInstance().setXmlFileName(strBas);

	    // Depending on if QueryParam is set, select the right handler method
		if ((nameArg != null) && nameArg.trim().length() > 0) {
			// if QueryParam is set, it will be searched for it:
			Kontakte kontakte = KontakteHandler.getInstance().searchKontakte(nameArg);
			// Check if kontakt was found:
			if (kontakte != null) {
				Kontakte.Kontakt kontakt = kontakte.getKontakt().get(0);
				if ((neunameArg != null) && nameArg.trim().length() > 0)
					kontakt.setName(neunameArg);
				if ((neuvnameArg != null) && nameArg.trim().length() > 0)
					kontakt.setVorname(neuvnameArg);
				if ((neuemailArg != null) && nameArg.trim().length() > 0)
					kontakt.setEMail(neuemailArg);

				KontakteHandler.getInstance().updateKontakte();
				resRet = Response.created(uriInfo.getAbsolutePath()).build();
			}
		} 

		return resRet;
	}

Zum Testen kann die Java Client Klasse wie folgt erweitert werden:

package org.jkhofmann.dyndns;

import java.net.URI;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.representation.Form;

public class JerseyJAXBRestTest1Client {
	public static void main(String[] args) {
		ClientConfig config = new DefaultClientConfig();
		Client client = com.sun.jersey.api.client.Client.create(config);
		WebResource service = client.resource(getBaseURI());
		// Get XML
		System.out.println(service.path("kontakte").accept(
				MediaType.TEXT_XML).get(String.class));
		// Get XML for application
		System.out.println(service.path("kontakte").accept(
				MediaType.APPLICATION_JSON).get(String.class));
		// Get JSON for application
		System.out.println(service.path("kontakte").accept(
				MediaType.APPLICATION_XML).get(String.class));
		// Testen von @QueryParam, Methode queryParam baut URL entsprechend zusammen,
		// z.B. GET http://localhost:8080/JerseyJAXBRestTest1/kontakte?name=Name1:
		System.out.println(service.queryParam("name", "Name1").path("kontakte").accept(
				MediaType.APPLICATION_XML).get(String.class));

		// Check PUT operation:
		// Simulate a HTML form and send PUT request to server to update existing resource:
		Form form = new Form();
		form.add("name", "Name2");
		form.add("nameNeu", "Name2Neu");
		form.add("vnameNeu", "Vorname2Neu");
		form.add("emailNeu", "eMail2Neu");
		ClientResponse response = service.path("kontakte").type(MediaType.APPLICATION_FORM_URLENCODED)
								   .put(ClientResponse.class, form);
	    System.out.println( response.getStatus() + " " + response.getClientResponseStatus() );
	    System.out.println( response.getEntity( String.class ) );
	}

	   private static URI getBaseURI() {
		return UriBuilder.fromUri(
				"http://localhost:8080/JerseyJAXBRestTest1").build();
	}

}

Schaut man sich anschließend die „Kontakte.xml“ Datei im Root Verzeichnis der Web-Applikation an, sieht sie so aus:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Kontakte>
    <Kontakt>
        <Name>Name1</Name>
        <Vorname>Vorname1</Vorname>
        <eMail>eMail1</eMail>
    </Kontakt>
    <Kontakt>
        <Name>Name2Neu</Name>
        <Vorname>Vorname2Neu</Vorname>
        <eMail>email2Neu</eMail>
    </Kontakt>
    <Kontakt>
        <Name>Name3</Name>
        <Vorname>Vorname3</Vorname>
        <eMail>eMail3</eMail>
    </Kontakt>
</Kontakte>

 

Man erkennt, dass der zweite Eintrag verändert wurde.

Mit dem Advanced Rest Client von Google, kann man beispielsweise folgende Werte testen:

Das Ergebnis:

 

Schaut man sich anschließend die „Kontakte.xml“ Datei im Root Verzeichnis der Web-Applikation an, sieht sie so aus:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Kontakte>
    <Kontakt>
        <Name>Name1</Name>
        <Vorname>Vorname1</Vorname>
        <eMail>eMail1</eMail>
    </Kontakt>
    <Kontakt>
        <Name>Name2Neu</Name>
        <Vorname>Vorname2Neu</Vorname>
        <eMail>eMail2Neu</eMail>
    </Kontakt>
    <Kontakt>
        <Name>Name3Neu</Name>
        <Vorname>Vorname3Neu</Vorname>
        <eMail>eMail3Neu</eMail>
    </Kontakt>
</Kontakte>

Jetzt wurde der dritte Eintrag verändert.

Anstelle des @FormParam Parameters kann man auch direkt JAXB Klassen übergeben. Zu diesem Zweck muss die Server Klasse um folgende Methode erweitert werden:

...
import javax.xml.bind.JAXBElement;
...
	@PUT
	@Consumes(MediaType.APPLICATION_XML)
	public Response putContact(JAXBElement<Kontakte> kontakteArg) {
		Response resRet = Response.noContent().build();

		// Set path to the contacts xml source file (it is the real path on the
		// tomcat server):
		String strBas = context.getRealPath("/") + "Kontakte.xml";
		KontakteHandler.getInstance().setXmlFileName(strBas);

		// extract the name to search for:
		String searchName = kontakteArg.getValue().getKontakt().get(0).getName();
		// extract the remaining attributes:
		String newVName = kontakteArg.getValue().getKontakt().get(0).getVorname();
		String newEMail = kontakteArg.getValue().getKontakt().get(0).getEMail();

		Kontakte kontakte = KontakteHandler.getInstance().searchKontakte(
				searchName);

		// Check if kontakt was found:
		if (kontakte != null) {
			Kontakte.Kontakt kontakt = kontakte.getKontakt().get(0);
			// if ((neunameArg != null) && nameArg.trim().length() > 0)
			// kontakt.setName(neunameArg);
			if ((newVName != null) && newVName.trim().length() > 0)
				kontakt.setVorname(newVName);
			if ((newEMail != null) && newEMail.trim().length() > 0)
				kontakt.setEMail(newEMail);

			KontakteHandler.getInstance().updateKontakte();
			resRet = Response.created(uriInfo.getAbsolutePath()).build();
		}

		return resRet;
	}

Der Client kann folgenden Aufruf verwenden:

		// Check PUT Operation with JAXB class:
		Kontakte kontakteUpdate = new Kontakte();
		Kontakte.Kontakt kontaktUpdate = new Kontakte.Kontakt();
		kontaktUpdate.setName("Name1");
		kontaktUpdate.setVorname("NeuVorname1");
		kontaktUpdate.setEMail("NeuEMail1");
		kontakteUpdate.getKontakt().add(kontaktUpdate);
		ClientResponse response2 = service.path("kontakte")
				.type(MediaType.APPLICATION_XML)
				.put(ClientResponse.class, kontakteUpdate);
		System.out.println(response2.getStatus() + " "
				+ response2.getClientResponseStatus());
		System.out.println(response2.getEntity(String.class));

Man beachte, dass sich der Name nicht ändern läßt, weil er gleichzeitig als Suchargument verwendet wird. Würde man für jeden Kontakt noch ein weiteres, eindeutiges Attribut definieren, beispielsweise eine ID, dann könnte man das als Suchargument verwenden und auch den Namen ändern.

 

POST – Create

Um die POST Operation zu implementieren, also um einen neuen Kontakt zu erstellen, kann man im Prinzip ähnlich wie bei der PUT Operation vorgehen. Im Beispiel wird wieder der @FormParam verwendet, um die Attribute des neuen Kontaktes festzulegen. Beim PUT habe ich „Response“ als Rückgabetyp gewählt, hier werde ich einmal „text/plain“, also String und einmal „MediaType.APPLICATION_XML“, also XML als Rückgabetyp wählen. Man kann natürlich auch andere Möglichkeiten der Parameterübergabe wählen (z.B. @QueryParam, etc.), das Gleiche gilt für den Response.

Die Server Klasse (mit „text/plain“ als Rückgabetyp):

	@POST
	@Produces("text/plain")
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public String postContact(@FormParam("nameNeu") String neunameArg,
			@FormParam("vnameNeu") String neuvnameArg,
			@FormParam("emailNeu") String neuemailArg,
			@Context HttpServletResponse servletResponse) {

		// Set path to the contacts xml source file (it is the real path on the
		// tomcat server):
		String strBas = context.getRealPath("/") + "Kontakte.xml";
		KontakteHandler.getInstance().setXmlFileName(strBas);

		Kontakte kontakte = KontakteHandler.getInstance().getKontakte();
		Kontakte.Kontakt kontakt = new Kontakte.Kontakt();

		// Check if there is something to create:
		if ((neunameArg != null) && neunameArg.trim().length() > 0) {
			if ((neunameArg != null) && neunameArg.trim().length() > 0)
				kontakt.setName(neunameArg);
			if ((neuvnameArg != null) && neuvnameArg.trim().length() > 0)
				kontakt.setVorname(neuvnameArg);
			if ((neuemailArg != null) && neuemailArg.trim().length() > 0)
				kontakt.setEMail(neuemailArg);
			kontakte.getKontakt().add(kontakt);
			KontakteHandler.getInstance().updateKontakte();
		}
		return "Customer " + kontakt.getName() + " added !";
	}

Die Server Klasse (mit „MediaType.APPLICATION_XML“ als Rückgabetyp):

	@POST
	@Produces(MediaType.APPLICATION_XML)
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public Kontakte postContact(@FormParam("nameNeu") String neunameArg,
			@FormParam("vnameNeu") String neuvnameArg,
			@FormParam("emailNeu") String neuemailArg,
			@Context HttpServletResponse servletResponse) {

		// Set path to the contacts xml source file (it is the real path on the
		// tomcat server):
		String strBas = context.getRealPath("/") + "Kontakte.xml";
		KontakteHandler.getInstance().setXmlFileName(strBas);

		Kontakte kontakte = KontakteHandler.getInstance().getKontakte();
		Kontakte.Kontakt kontakt = new Kontakte.Kontakt();

		// Check if there is something to create:
		if ((neunameArg != null) && neunameArg.trim().length() > 0) {
			if ((neunameArg != null) && neunameArg.trim().length() > 0)
				kontakt.setName(neunameArg);
			if ((neuvnameArg != null) && neuvnameArg.trim().length() > 0)
				kontakt.setVorname(neuvnameArg);
			if ((neuemailArg != null) && neuemailArg.trim().length() > 0)
				kontakt.setEMail(neuemailArg);
			kontakte.getKontakt().add(kontakt);
			KontakteHandler.getInstance().updateKontakte();
		}

		// create a "Kontakte" class with one "Kontakt" (the created one),
		// and use it for the response (in XML format):
		Kontakte kontakteRet = new Kontakte();
		kontakteRet.getKontakt().add(kontakt);

		return kontakteRet;
	}

 

Als Client verwende ich wieder den Advanced Rest Client:

Der Response (in der XML Version der Server Methode):

 

DELETE – Delete

Für die Operation Löschen werde ich wieder mit @QueryParam arbeiten und JSON zurückgeben. Auch hier gilt wieder, dass man andere Möglichkeiten der Parameterübergabe wählen könnte (Klasse direkt übergeben, @FormParam etc.), das Gleiche gilt für den Response.

Die Server Klasse wie folgt erweitern:

	@DELETE
	@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
	public Kontakte deleteContact(@QueryParam("name") String nameArg) {
		// Set path to the contacts xml source file (it is the real path on the
		// tomcat server):
		String strBas = context.getRealPath("/") + "Kontakte.xml";
		KontakteHandler.getInstance().setXmlFileName(strBas);

		Kontakte.Kontakt kontaktRet = new Kontakte.Kontakt();

		if ((nameArg != null) && nameArg.trim().length() > 0) {
			// if QueryParam is set, it will be searched for it:
			Kontakte kontakte = KontakteHandler.getInstance().searchKontakte(
					nameArg);
			// Check if kontakt was found:
			if (kontakte != null) {
				// save attributes for return value:
				kontaktRet.setName(new String(kontakte.getKontakt().get(0)
						.getName()));
				kontaktRet.setVorname(new String(kontakte.getKontakt().get(0)
						.getVorname()));
				kontaktRet.setEMail(new String(kontakte.getKontakt().get(0)
						.getEMail()));

				// delete contact:
				Kontakte.Kontakt kontakt = kontakte.getKontakt().remove(0);
				KontakteHandler.getInstance().updateKontakte();
			}
		}
		// create a "Kontakte" class with one "Kontakt" (the created one),
		// and use it for the response (in XML format):
		Kontakte kontakteRet = new Kontakte();
		kontakteRet.getKontakt().add(kontaktRet);

		return kontakteRet;
	}

 

Test mit dem Advanced Rest Client:

Das Ergebnis:

 

Links:

vogella: REST with Java (JAX-RS) using Jersey – Tutorial

IBM developerWorks: Build a RESTful Web service using Jersey and Apache Tomcat

Thorsten Horn: RESTful Web Services mit JAX-RS und Jersey

devx.com: JAX-RS: Developing RESTful Web Services in Java

 
Hinterlasse einen Kommentar

Verfasst von - Februar 11, 2012 in Formate, WebServices

 

Schlagwörter: , , , ,

JSON Provider erstellen. Part 4: Mit Tomcat und Jersey REST Services erstellen

JSON Provider erstellen. Part 4: Mit Tomcat und Jersey REST Services erstellen

JAX-RS ist die Spezifikation einer Java-API zur Implementierung von RESTful web services und Jersey ist eine JAX-RS Referenz Implementation. Es gibt weitere Referenz Implementierungen, wie z.B. RESTEasy (from JBoss), Restlet, Apache CXF.

Um RESTful Webservices auf Tomcat mit Jersey zu implementieren, sind folgende Voraussetzungen notwendig:

Hinweis: Die Beispiele wurden entnommen aus http://www.vogella.de/articles/REST/article.html#first_class, erweitert und angepasst!

 

Exkurs: REST

Mit REpresentational State Transfer oder kurz REST kann man, wie mit SOAP, WebServices realisieren. Die Informationen, auf die man mit REST zugreifen kann, werden als Ressourcen bezeichnet.

Beispiel: Onlinehandel

Ein Benutzer (Kunde) kann in einem Onlineskatalog Waren auswählen und in einen Warenkorb legen.. Alle Informationen, die dazu nötig sind, können über REST abgebildet werden. Es gibt Objekte wie Warenkorb, zugeordneter Kunde, Inhalt bzw. Artikel, etc. Die Objekte werden als Ressourcen bezeichnet und sind miteinander verknüpft (Mashup):

Ein Warenkorb ist einem Kunden zugeordnet und enthält einen oder mehrere Artikel. Es gibt viele Möglichkeiten dieses Modell abzubilden, eine Möglichkeit wäre es vom Kunden ausgehend alle Warenkörbe zu suchen und für jeden Warenkorb jeweils alle Artikel, die darin enthalten sind, zu ermitteln. In REST könnte man das beispielsweise so abbilden:

GET /kunde/<kundennr> ==> 1..n Warenkörbe

GET /warenkorb/<warenkorb id> ==> 1..n Artikel

GET /artikel/<artikelnr>

Die Rückgabe der jeweiligen Aufrufe kann in unterschiedlichen Formaten aka Repräsentationen erfolgen, z.B. HTML, XML oder JSON.

Um sog. CRUD (Create, Read, Update, Delete) Operationen auf eine Ressource durchzuführen,  können die HTTP Methoden POST, GET, PUT und DELETE verwendet werden.

Jeder Dienst, den ein REST-konformer Server zur Verfügung stellt, hat eine eindeutige Adresse, den Uniform Resource Identifier (URI). Die Verkettung von Aufrufen (Mashups) bedeuten, dass Teile der Information im Client gespeichert werden. Im obigen Beispiel würde man zunächst über „GET /kunde“ alle Kunden ermitteln, im Client eine Kundennummer heraussuchen und mit „GET /kunde/<kundennr>“ alle Warenkörbe ermitteln. Auch hier würde man auf Client-Seite eine Auswahl der Warenkorb ID treffen, um in einem folgenden Aufruf „GET /warenkorb/<warenkorb id>“ alle Artikel in einem Warenkorb zu ermitteln. D.h. der Rest-Service liefert Informationen, die auf Client-Seite verarbeitet bzw. verknüpft werden, um Folge-Aufrufe an den Rest-Service zu senden, damit weitere Informationen abgerufen werden können.

Der Rest-Server muss zwischen den Request keine Informationen zwischenspeichern, eine Session für alle Client-Requests zu einem bestimmten Kontext, muss ebenfalls nicht zwischengespeichert werden. D.h. Rest ist ein zustandsloses (stateless) Protokoll. Damit wird auch die Skalierbarkeit von Rest-basierenden Anwendungen deutlich erhöht: im Grunde ist es dem Client egal, von welchem Server er sich die Informationen holt, er hat immer alle Informationen bei sich gespeichert und kan von Request zu Request beliebig den Rest-Server wechseln.

Will man auf eine bestimmte Ressource zugreifen, kann dies u.a. über eine Parametrisierung des URI-Pfades geschehen (PathParam), z.B. „GET /artikel/123„, oder durch einen oder mehrere Aufrufparameter (QueryParam), z.B. „GET /artikel?id=123“ geschehen.

 

Erstellen eines einfachen REST Services

  1. Erstellen Sie ein „Dynamic Web Project“ mit Eclipse:
    File > New > Dynamic Web Project
  2. Finish
  3. Kopieren der Jersey-Jars in das Verzeichnis WebContent/WEB-INF/lib des Projektes (Evtl. Refreshen des Verzeichnisses, damit die Inhalte sichtbar werden):
  4. Erstellen einer Service-Klasse:
  5. Finish
  6. Source-Code eingeben:
    package de.rew.jerseytest.server;
    
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;
    
    // POJO, no interface no extends
    
    // The class registers its methods for the HTTP GET request using the @GET annotation.
    // Using the @Produces annotation, it defines that it can deliver several MIME types,
    // text, XML and HTML. 
    
    // The browser requests per default the HTML MIME type.
    
    //Sets the path to base URL + /hello
    @Path("/hello")
    public class Hello {
    
    	// This method is called if TEXT_PLAIN is request
    	@GET
    	@Produces(MediaType.TEXT_PLAIN)
    	public String sayPlainTextHello() {
    		return "Hello Jersey";
    	}
    
    	// This method is called if XML is request
    	@GET
    	@Produces(MediaType.TEXT_XML)
    	public String sayXMLHello() {
    		return "<?xml version="1.0"?>" + "<hello> Hello Jersey" + "</hello>";
    	}
    
    	// This method is called if HTML is request
    	@GET
    	@Produces(MediaType.TEXT_HTML)
    	public String sayHtmlHello() {
    		return "<html> " + "<title>" + "Hello Jersey" + "</title>"
    				+ "<body><h1>" + "Hello Jersey" + "</body></h1>" + "</html> ";
    	}
    
    }
  7. Anpassen der Servlet Einstellungen in der Datei „web.xml“:
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    	id="WebApp_ID" version="2.5">
    	<display-name>JerseyTest1</display-name>
    	<welcome-file-list>
    		<welcome-file>index.html</welcome-file>
    		<welcome-file>index.htm</welcome-file>
    		<welcome-file>index.jsp</welcome-file>
    		<welcome-file>default.html</welcome-file>
    		<welcome-file>default.htm</welcome-file>
    		<welcome-file>default.jsp</welcome-file>
    	</welcome-file-list>
     <servlet>
     <servlet-name>Jersey REST Service</servlet-name>
     <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
     <init-param>
     <param-name>com.sun.jersey.config.property.packages</param-name>
     <param-value>de.rew.jerseytest.server</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
     </servlet>
     <servlet-mapping>
     <servlet-name>Jersey REST Service</servlet-name>
     <url-pattern>/*</url-pattern>
     </servlet-mapping>
    </web-app>
  8. Erstellen eines WAR Archives:
    Rechtsklick auf das Projekt > Export > WAR file > Zielverzeichnis angeben. Datei als „JerseyTest1.war“ benennen.
  9. Deployen des WAR Archives:
    Kopieren des WAR Archives in das Verzeichnis „webapps“ der Tomcat Installation oder über die Manager GUI des Tomcat Servers (siehe hier: „JSON Provider erstellen. Part 1„).
  10. Testen:
    http://localhost:8080/JerseyTest1/hello

Erstellen eines passenden REST Clients

Man kann sich das Ergebnis direkt im Browser anschauen, oder einen eigenen Java-Client erstellen. ACHTUNG: Die Client Klasse nicht einfach „Client“ nennen, sonst kommt es zu Konflikten mit den Jersey-Libraries!

package de.rew.jerseytest.client;

import java.net.URI;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;

public class HelloClient {
	public static void main(String[] args) {
		ClientConfig config = new DefaultClientConfig();
		Client client = Client.create(config);
		WebResource service = client.resource(getBaseURI());
		// Fluent interfaces
		System.out.println(service.path("hello").accept(
				MediaType.TEXT_PLAIN).get(ClientResponse.class).toString());
		// Get plain text
		System.out.println("TEXT_PLAIN: " + service.path("hello").accept(
				MediaType.TEXT_PLAIN).get(String.class));
		// Get XML
		System.out.println("  TEXT_XML: " + service.path("hello").accept(
				MediaType.TEXT_XML).get(String.class));
		// The HTML
		System.out.println(" TEXT_HTML: " + service.path("hello").accept(
				MediaType.TEXT_HTML).get(String.class));

	}

	private static URI getBaseURI() {
		return UriBuilder.fromUri(
				"http://localhost:8080/JerseyTest1").build();
	}

}

 

Im nächsten Teil „JSON Provider erstellen. Part 5: Ressourcen, CRUD, JSON- und XML-Response„werde ich mit Tomcat und Jersey einen Webservice erstellen, der mit eigenen Klassen für die Ressourcen arbeitet, JSON zurückgibt und die Implementierung der CRUD Operationen zeigt.

 

Links:

 

 
Hinterlasse einen Kommentar

Verfasst von - Januar 8, 2012 in Formate, WebServices

 

Schlagwörter: , , ,

JSON Provider erstellen. Part 3: Axis2 spricht JSON


In diesem letzten Teil geht es darum, Axis2 Services, Antworten in JSON schicken zu lassen.

In Teil 1 ging es darum „Apache Tomcat zu installieren„, in Teil 2 ging es darum „Axis2 auf Tomcat zu installieren„. In diesem dritten Teil geht es nur noch darum die Antworten von Axis2 Services nicht mehr in XML, sondern auch in JSON zu liefern.

Alles was ich im Folgenden beschreibe geht letztendlich auf den Artikel „Building a JSON web service with Java and Axis2“ von Markus Schiesser zurück. Im Wesentlichen geht es um einen Bug in Axis2, bei der Nutzung der Jettison API, um JSON Nachrichten zu parsen. In einem weiteren Artikel „JSON web service with Java and Axis2„, von DJaka PM, wird die Beschreibung von Markus Schiesser nochmals vereinfacht und soll im Folgenden veranschaulicht werden.

  1. Laden Sie sich die modifizierte WAR Datei hier oder hier herunter.
  2. Sichern Sie Ihre Inhalte in Axis2, diese werden überschrieben !
  3. Installieren Sie die neue WAR Datei in Axis2:
    sudo cp <Download Verzeichnis>/axis2.war ./webapps/

    Warten Sie einen Augenblick

  4. Stellen Sie sicher, daß Tomcat gestartet ist und rufen Sie folgenden Link auf:
    http://localhost:8080/axis2/services/Version/getVersion?response=application/json

    Es müsste folgende Antwort in Ihrem Web-Browser erscheinen:

  5. Wollen Sie die herkömmliche XML-formatierte Antwort, dann rufen Sie einfach folgenden Link auf:
    http://localhost:8080/axis2/services/Version/getVersion

    Es müsste folgende Antwort in Ihrem Web-Browser erscheinen:

Je nach URL, erhalten Sie also eine JSON- oder XML-formatierte Antwort des WebServices.

 
Hinterlasse einen Kommentar

Verfasst von - Dezember 31, 2011 in WebServices

 

Schlagwörter: , , ,

JSON Provider erstellen. Part 2: Axis2 auf Tomcat installieren

JSON Provider erstellen. Part 2: Axis2 auf Tomcat installieren

Nachdem im ersten Teil der Tomcat Server zum Laufen gebracht wurde, geht es hier darum, Axis2 auf dem Tomcat Server zu installieren.

Apache Axis2™ ist eine Web Services/SOAP/WSDL Engine, die es auf relative einfache Weise erlaubt Webservices bereitzustellen. Eine Möglichkeit besteht darin sog. POJOs (Plain Old Java Objects), also mehr oder weniger einfache Java-Klassen zu definieren und diese mit Axis2 in einen Web-Service zu „transformieren“. Eine genauere Beschreibung ist hier zu finden.

Man kann Axis2 als Standalone Server, oder auf einem Servlet Container (z.B. Tomcat) bzw. einem vollständigen JEE Server (Applikationsserver wie JBoss etc.) betreiben.

Installation (Tomcat)

1) Download und Entpacken von http://axis.apache.org/axis2/java/core/download.cgi

2) Im entpackten Verzeichnis nach „webapp“ wechseln

3) Zusammenbauen der WAR Datei:

/opt/axis2-1.6.1/webapp$ ant
Buildfile: /opt/axis2-1.6.1/webapp/build.xml

init:
...
prepare.repo:
...
create.war:
      [war] Building war: /opt/axis2-1.6.1/dist/axis2.war
   [delete] Deleting directory /opt/axis2-1.6.1/dist/temp

BUILD SUCCESSFUL
Total time: 3 seconds

4) Kopieren der WAR Datei in das Verzeichnis „webapps“ des Servlet-Containers:

/opt/apache-tomcat-6.0.35$ sudo cp /opt/axis2-1.6.1/dist/axis2.war ./webapps/

5) Durch das Kopieren in den „webapps“  Folder, wird die Datei (bei laufendem Tomcat) automatisch deployed. Man kann das, nach kurzer Zeit, im Log File (/opt/apache-tomcat-6.0.35/logs$ sudo tail -50 catalina.out), in der Manager Applikation (http://localhost:8080/manager/html) und durch Aufrufen der URL (localhost:8080/axis2) sehen.

Bei Problemen kann im Log File bzw. im Manager überprüft werden, ob die Web-Applikation auch gestartet wurde!

Axis2 Admin Konsole

Für Axis2 gibt es eine Admin-Konsole mit dem Default-Account „admin“/“axis2“ unter http://localhost:8080/axis2/axis2-admin/login.

Sie können den Benutzernamen und das Kennwort in der Datei „axis2.xml“ nach Bedarf ändern.

WebServices erstellen:

Axis2 bietet mehrere Möglichkeiten WebServices zu erstellen:

– über JAX-WS, siehe auch Apache Axis2 – JAX-WS Guide

– über sog. POJOs, siehe auch POJO Web Services using Apache Axis2

– aus einem vorhandenen WSDL Dokument

– etc.

Im Folgenden beziehe ich  mich auf die Nutzung sog. POJOs.

Axis2 WebService mit POJOs

Mit Axis2 kann man durch eine sog. Service-Klasse einen WebService in Java programmieren. Zudem ist es möglich über diesen WebService JavaBeans anzusprechen (nicht mit EJBs – Enterprise Java Beans zu verwechseln). Die Verwendung von JavaBeans ermöglicht eine Modularisierung des Web-Applikation.

Service Klasse und services.xml

Die Erstellung eines Axis2 WebServices mit POJOs (ohne JavaBeans) lässt sich relativ schnell erledigen. Sie erstellen eine Service-Klasse, in einem beliebigen Projekt-Verzeichnis und anschließend eine services.xml Datei.

Service-Klasse:

package sample;

public class SampleService {

    public String echo(String value) {
        return value;
    }

    public int add(int a, int b) {
        return a + b;
    }

    public void update(int c) {

    }
}

 

services.xml Datei:

<service name="SampleService">
 <description>This is my Sample Service</description>
    <messageReceivers>
        <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only"
                         class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/>
        <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"
                         class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
    </messageReceivers>
    <parameter name="ServiceClass">sample.SampleService</parameter>
</service>

 

Verwendung von Eclipse als IDE

Ich  habe in Eclipse ein Projekt „SampleService“ angelegt und die Klasse „SampleService“ im Paket „sample“ unter „src“ angelegt. Außerdem habe in „src“ ein Verzeichnis „META-INF“ erstellt und darin die Datei „services.xml“ abgelegt:

Anschließend habe ich die Datei „build.xml“ aus „Axis2_HOME/samples/pojoguide“ in das Projektverzeichnis kopiert und angepasst: build.xml

Führt man nun build.xml mit ant aus, wird eine aar Datei (Tomcat Webservice Paket) erstellt, die man nun auf Axis2 im Tomcat deployen kann.

Deployment

Wie bringt man nun den Service auf den Tomcat Server?

  1. Rufen Sie die URL für den Tomcat Server auf, z.B.: http://localhost:8080/
  2. Selektieren Sie Administration > Tomcat Manager
  3. Selektieren Sie unter „Application“ den Pfad „/axis2“
  4. Selektieren Sie den Link „Administration“
  5. Geben Sie Username und Passwort ein (Default: admin/axis2) und drücken Sie den „Login“ Knopf
  6. Wählen Sie den Link: Tools > Upload Service
  7. Wählen Sie „Durchsuchen“ und selektieren Sie das aar File
  8. Drücken Sie den „Upload“ Knopf
  9. Wenn alles glatt gelaufen ist, sehen Sie unter „System Components“ > „Available Services“ den Service „“. (Hinweis: Es kann sein, dass Sie einen Augenblick warten müssen und die Anzeige refreshen müssen, bis der Service sichtbar ist).

Die WSDL des WebServices lautet: „http://localhost:8080/axis2/services/SampleService?wsdl&#8220;.

Testen des WebServices mit SOAP UI

SoapUI ist ein hervorragendes, freies Tool zum Testen von WebServices, sofern man die WSDL zur Verfügung hat. Die Installation geht einfach und schnell von statten. Man legt nach der Installation ein neues Projekt an und wählt die URL der WSDL (http://localhost:8080/axis2/services/SampleService?wsdl). Anschließend kann man die verschiedenen Operationen des WebServices testen. Alternativ kann man sich auch einen sog, RPCClient programmieren und damit den WebService testen (s.u.).

Testen des WebServices mit einem RPC Client

Alternativ zu SoapUI kann man einen sog. RPC Client programmieren und die Funktionalität des WebServices testen (siehe hierzu: Testing the POJO Web Service Using RPCServiceClient).

Erstellen Sie hierzu in Eclipse eine Java-Klasse „SampleServiceRPCClient“ im Paket „sample.rpcclient“:

package sample.rpcclient;
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;

public class SampleServiceRPCClient {
    public static void main(String[] args1) throws AxisFault {

        RPCServiceClient serviceClient = new RPCServiceClient();

        Options options = serviceClient.getOptions();

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

        // Setting the add Operation
        QName opEcho =
            new QName("http://sample", "echo");

        // Setting the parameters for the Operation:
        Object[] opSetSampleServiceArgs = new Object[] { "jkhofmann" };

        Class[] returnTypes = new Class[] { String.class };

        Object[] response = serviceClient.invokeBlocking(opEcho,
        		opSetSampleServiceArgs, returnTypes);

        String result = (String) response[0];

        if (result == null) {
            System.out.println("SampleService didn't initialize!");
            return;
        }        

        // Displaying the result
        System.out.println("Echo : " + result);

    }
}

 

Beachten Sie, dass in diesem Beispiel keine JavaBean als Business-Klasse verwendet wird, vielmehr wird der Service direkt angesprochen. Um eine JavaBean als Business-Klasse dazwischenzuschalten, verfolgen Sie bitte den Artikel „POJO Web Services using Apache Axis2“.

Hinweis: Die Fehlermeldungen in der Eclipse IDE können Sie ignorieren, es handelt sich dabei um fehlende Einträge im Build-Path. Diese werden über das Target „rpc.client.run“ in build.xml automatisch geladen. Wenn Sie also den Client testen wollen, verwenden Sie die Eclipse IDE oder ant mit dem Target „rpc.client.run“, oder ziehen Sie die fehlenden Libraries aus Axis2 in den Build-Path des Eclipse-Projektes.

Das Ergebnis über Eclipse/build.xml mit dem Target „rpc.client.run“ sollte wie folgt aussehen:

rpc.client.run:
     [java] log4j:WARN No appenders could be found for logger (org.apache.axis2.context.AbstractContext).
     [java] log4j:WARN Please initialize the log4j system properly.
     [java] Echo : jkhofmann
BUILD SUCCESSFUL
Total time: 4 seconds

 

Testen des WebServices mit WSDL2Java.sh

Axis2 liefert ein Skript mit, welches die komfortable Erstellung von Services und Clients erlaubt. Es nennt sich „wsdl2java.sh“ und ist im „bin“ Verzeichnis der Axis2-Installation zu findet. Hierzu muss lediglich die WSDL vorhanden sein, über die WSDL-URI kann man sich mit diesem Skript die Client-Anteile generieren lassen.

Die Clients können auf verschiedene Arten generiert werden. Mit der Option „-d“ kann man festlegen, wie die XML-Struktur des Services in Java-Objekte umgesetzt wird – Databinding. Läßt man die Option weg, werden XML-in-out Stubs generiert, ohne Databinding.

Verwendet man Databinding, kann man zwischen folgenden Optionen wählen:

  • Axis2 Databinding Framework (ADB): einfach, aber gewisse Einschränkungen bei XML Schemas
  • XMLBeans: voller Schema-Kompiler, aber etwas komplizierter als ADB
  • JiBX: JiBXist ein komplettes Databinding-Framework

siehe hierzu auch: „Choosing a Client Generation Method„.

Neben der Option für das Databindung (-d) kann man mit „-s“ synchrone bzw. blockierende Clients erzeugen lassen, also Clients die beinem Request auf den Response warten. Eine weitere nützliche Option ist „-p“, mit ihr kann man den Namespace (Package-Pfad) des Clients festlegen. Zu guter Letzt finde ich die Option „-o“ noch nützlich, da man mit ihr ein Zielverzeichnis für den generierten Code festlegen kann.

Im folgenden will ich beispielhaft veranschaulichen, wie man einen Client, ganz ohne Databinding, generiert und ausprogrammiert.

  1. Erstellen eines temporären Verzeichnisses und wechseln in das Verzeichnis
  2. Generieren des Client-Stubs:
    /opt/axis2-1.6.1/bin/wsdl2java.sh -uri http://localhost:8080/axis2/services/SampleService?wsdl -p
    sample.wsdl2java.client -s

    Das Ergebnis:

    juergen@vostrou64:~/loeschen$ ls -lR
    .:
    insgesamt 12
    -rw-rw-r-- 1 juergen juergen 5151 2011-12-29 03:23 build.xml
    drwxrwxr-x 3 juergen juergen 4096 2011-12-29 03:23 src
    ...
    ./src/sample/wsdl2java/client:
    -rw-rw-r-- 1 juergen juergen 132306 2011-12-29 03:23 SampleServiceStub.java 

     

  3. Projekt in Eclipse anlegen bzw. ergänzen um die Klasse
    sample.wsdl2java.client.SampleServiceStub
  4. Inhalt der Klasse vom temporären Verzeichnis in Eclipse kopieren
  5. Build-Path von Eclipse anpassen. Es müssen die entsprechenden JARs aus der Axis2 Installation im lib Verzeichnis hinzugefügt werden.
  6. Client erstellen:
    package sample.wsdl2java.client;
    
    import sample.wsdl2java.client.SampleServiceStub.*;
    
    public class Client {
    
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) {
            try {
                SampleServiceStub stub =
                    new SampleServiceStub
                    ("http://localhost:8080/axis2/services/SampleService");
    
                // Aufruf der Services:
                echo(stub);
                add(stub);
            } catch(Exception e) {
                e.printStackTrace();
                System.out.println("nnn");
            }	        
    	}
    
        /* Echo Service */
        public static void echo(SampleServiceStub stub){
            try{
                Echo req = new Echo();
                req.setArgs0("Hello World");
                EchoResponse resp = stub.echo(req);
                String response = resp.get_return();
                System.out.println("Response = " + response);
            } catch(Exception e){
                e.printStackTrace();
                System.out.println("nnn");
            }
        }
    	
        /* Add Service */
        public static void add(SampleServiceStub stub){
            try{
                Add req = new Add();
                req.setArgs0(1);
                req.setArgs1(2);
                AddResponse resp = stub.add(req);
                int response = resp.get_return();
                System.out.println("Response = " + response);
            } catch(Exception e){
                e.printStackTrace();
                System.out.println("nnn");
            }
        }
        
    }
  7. Kompilieren und testen.
 
Hinterlasse einen Kommentar

Verfasst von - Dezember 27, 2011 in Linux, WebServices

 

Schlagwörter: , , , , ,

JSON Provider erstellen. Part 1: Apache Tomcat – Installation auf Ubuntu

JSON Provider erstellen. Part 1: Apache Tomcat – Installation auf Ubuntu

Motivation

Ich befasse mich derzeit mit OData und JSON. Die meisten Beispiele, die man hierzu im Internet findet, sind Microsoft-lastig. Ich will versuchen mit Tomcat und AXIS2 einen JSON Server aufzubauen. AXIS2 soll nicht standalone, sondern auf einem Tomcat Server laufen. Die einzelnen Schritte, die dazu nötig sind, will ich in meinem Blog, in einer mehrteiligen Reihe beschreiben, wobei ich noch nicht weiß, ob das alles so funktioniert, wie ich mir das gedacht habe.

In den ersten Teilen will ich beschreiben, wie die Voraussetzungen erfüllt werden:

  • Installation Tomcat
  • Installation Axis2 auf Tomcat

In den darauf folgenden Teilen geht es darum, JSON als Server auf Axis2 bereitzustellen und von einem Cient zu konsumieren.

Tomcat – Quick Start…

Apache Tomcat ist Servlet Container mit JSP Compiler und einem (eingeschränkten) HTTP Server. Er eignet sich hervorragend, um JSP- und Servlet-Anwendungen zu schreiben und zu testen, aber auch, um beispielsweise AXIS2-Webservices anzubieten. Aufgrund seiner weiten Verbreitung ist der Tomcat Server sehr stabil, zudem ist er schlank und schnell und, meiner Meinung nach, falls man keine EJBs oder Portale etc. entwickeln will, einem „schweren“ Applikationsserver vorzuziehen.

Alles, was ich im Folgenden beschreibe, wurde auf Ubuntu Linux 11.10 ausgeführt.

Installation:

1) Download der Binary Distribution (tar.gz)  von hier

2) Entpacken der Distribution

3) Starten:

juergen@vostrou64:/opt/<strong>apache-tomcat-6.0.35/bin$ sudo ./startup.sh</strong>
Using CATALINA_BASE:   /opt/apache-tomcat-6.0.35
Using CATALINA_HOME:   /opt/apache-tomcat-6.0.35
Using CATALINA_TMPDIR: /opt/apache-tomcat-6.0.35/temp
Using JRE_HOME:        /usr
Using CLASSPATH:       /opt/apache-tomcat-6.0.35/bin/bootstrap.jar

4) Testen:

Mit der URL: http://localhost:8080/ können Sie die Installation überprüfen.

Konfiguration:

Die generelle Konfiguration wird in der Datei conf/server.xml festgelegt. Änderungen werden erst nach einem Neustart wirksam.

juergen@vostrou64:/opt/apach.../conf$ sudo vi server.xml

Im  Abschnitt „Connector“ wird u.a. festgelegt, auf welchem Port der Server läuft:

    &lt;!-- A "Connector" represents an endpoint by which requests are received
         and responses are returned. Documentation at :
         Java HTTP Connector: /docs/config/http.html (blocking &amp; non-blocking)
         Java AJP  Connector: /docs/config/ajp.html
         APR (HTTP/AJP) Connector: /docs/apr.html
         Define a non-SSL HTTP/1.1 Connector on port 8080
    --&gt;
    &lt;Connector <strong>port="8080"</strong> protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" /&gt;
    &lt;!-- A "Connector" using the shared thread pool--&gt;
    &lt;!--
    &lt;Connector executor="tomcatThreadPool"
               <strong>port="8080"</strong> protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" /&gt;
    --&gt;

Im Abschnitt „GlobalNamingRessources/UserDatabase“ wird festgelegt, wo die Benutzer konfiguriert werden:

  &lt;GlobalNamingResources&gt;
    &lt;!-- Editable user database that can also be used by
         UserDatabaseRealm to authenticate users
    --&gt;
    &lt;Resource name="<strong>UserDatabase</strong>" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="<strong>conf/tomcat-users.xml</strong>" /&gt;
  &lt;/GlobalNamingResources&gt;

Diese Datei sieht defaultmäßig wiefolgt aus:

<!--
  <role rolename="tomcat"/>
  <role rolename="role1"/>
  <user username="tomcat" password="tomcat" roles="tomcat"/>
  <user username="both" password="tomcat" roles="tomcat,role1"/>
  <user username="role1" password="tomcat" roles="role1"/>
-->

Es gibt Rollen und User mit Username, Password und Rolle. Im Standard sind diese Rollen und Benutzer auskommentiert („<!–“ und „–>“). Die Kommentierung muss entfernt werden, falls man Änderungen vornehmen will!

Der Manager-User ist quasi der Administrator, seit Tomcat 6.0.30 wurde die Managerrolle in vier Teilrollen aufgeteilt:

  • manager-gui – allows access to the HTML GUI and the status pages
  • manager-script – allows access to the text interface and the status pages
  • manager-jmx – allows access to the JMX proxy and the status pages
  • manager-status – allows access to the status pages only

Um nun die Rolle manager-gui dem User tomcat mit dem Passwort s3cret zuzuweisen,  müssen folgende Zeilen zu conf/tomcat-users.xml hinzugefügt werden:

<role rolename="manager-gui"/>
<user username="tomcat" password="s3cret" roles="manager-gui"/>

Zum Aktivieren ist ein Neustart des Tomcat Servers notwendig (shutdown.sh und dann startup.sh)! Anschließend auf http://localhost:8080/ den Link „Tomcat Manager“ (http://localhost:8080/manager/html) aufrufen und den oben konfigurierten User eingeben.

 

 

Deployment:

Auf Tomcat werden sog. Web-Applikation deployed. Seit der Servlet API Specification, Version 2 werden hierfür sog. Web Application Archives (WAR) Dateien verwendet. Die WAR Dateien haben eine festgelegte Verzeichnisstruktur und dienen als „Transportformat“ für das Deployment, also dem Verteilen bzw. Installieren einer Web-Applikation auf einem Server.

Die Verzeichnisstruktur ist wie folgt:

Verzeichnis Inhalt
/ Wurzelverzeichnis, enthält html, jsp, js etc. Dateien
/WEB-INF/web.xml der sog. Web Application Deployment Descriptor, welcher die Servlets etc. der Web-Applikation beschreibt
/WEB-INF/classes Klassendateien (class), aber keine JAR Dateien. Reflektiert die Struktur bei Packages in Form von Unterverzeichnissen
/WEB-INF/lib JAR Dateien

Weitere Informationen sind hier zu finden.

Um WAR-Dateien auf Tomcat zu deployen, kann man sie direkt in das „webapps“ Verzeichnis der Tomcat-Installation kopieren, oder man verwendet die Manager-GUI. Mit der Manager-GUI kann man die WAR-Datei lokal auswählen und deployen:

Falls die deployte Applikation anschließend nicht in der Liste erscheint, sollte man sich die Tomcat Logdateien anschauen.

Eigene Applikationen erstellen

Wie man eigene Applikationen für Tomcat erstellt, wird hier erklärt.

 
Hinterlasse einen Kommentar

Verfasst von - Dezember 22, 2011 in Linux, WebServices

 

Schlagwörter: ,

 
Erstelle eine Website wie diese mit WordPress.com
Jetzt starten