RESTful Services With GWT and Apache CXF
Transcript of RESTful Services With GWT and Apache CXF
-
1Building and consuming RESTful JSON services with Apache CXF and Google Web Toolkit
Adrian Trenaman, Distinguished Consultant, IONA [email protected]
-
2 2008 IONA Technologies
IntroductionGoogle Web Toolkit provides an excellent toolkit for RESTful AJAX clients.
but doesnt provide a compelling solution for the server side.
Apache CXF provides a framework for building RESTful servers.GWT and CXF together offer a compelling solution.
Agenda:GWT overviewA RESTful Hello, World (in time honoured tradition)A document-oriented RESTful serviceConvention-based servicesUsing JSON payloadGWT client techniques
This is a technical session; expect to learn enough about GWT and CXF to go out and build your own solutions.
This is a technical session; expect to learn enough about GWT and CXF to go out and build your own solutions.
-
3 2008 IONA Technologies
Google Web Toolkit (GWT) a brief overview
-
4 2008 IONA Technologies
GWT overview
GWT allows you to build dynamic web applications in Java Your Java is compiled into cross-browser Javascript.
Key components: JRE emulation library, web UI library, java-to-jscompiler, and a hosted web browser for debugging.
-
5 2008 IONA Technologies
GWT overview (cont)GWT is available as open-source under Apache Public License (APL) 2.0. Website: http://code.google.com/webtoolkit
Benefits of GWT: Small application footprint (~100Kb) Excellent GUI performance Faster time-to-development: design, develop, debug, refactor in Java using your
favourite IDE, then deploy as JS.
-
6 2008 IONA Technologies
:
:Tomcat
GWT and RPC
GWT provides an RPC approach based on serialized Java over HTTP.
Host a GWT service in a servlet engine the GWT servlet will handle serialization of parameters, return values and exceptions.
Easy to use, but limits the reusability of services.
:ServiceImpl
:ServiceImpl
:Client
:Client
Serialised Java Objects over HTTP
-
7 2008 IONA Technologies
GWT and AJAX
GWT supports AJAX-style services Use asynchronous HTTP requests to transmit text-based payload such as XML
or JSON. Apache CXF (Fuse) can provide the server-side solution.
Rapidly produce JSON and XML services for GWT clients.
:
:Tomcat
:ServiceImpl
:ServiceImpl
:Client
:Client
JSON or XML over HTTPCXF
-
8 2008 IONA Technologies
RESTful JSON Services with Fuse Service Framework / Apache CXF
-
9 2008 IONA Technologies
RESTful services with FUSEApproach:
Annotate your Java service.Deploy - in Spring Framework, Tomcat, J2EE, or standalone.Consume most likely from AJAX clients.
ContactsService.javaContactsService.java@WebService
interface ContactsService {@Get
@HttpResource(location=/contacts/id={id})public Contact getContact(int id);
}
@WebService
interface ContactsService {@Get
@HttpResource(location=/contacts/id={id})public Contact getContact(int id);
}
http://frodo:9000/contacts/id=123 Go >
AdeTrenamanIONA TechnologiesPrincipal [email protected]+353-86-6051026
frodo:
:ContactsService
:ContactsService
HTTP 9000GET
-
10 2008 IONA Technologies
RESTful services with FUSE (cont)No formal interface definition language (WSDL, IDL) is used.
However, XSD is often used for data definition.
A services parameters are passed via payload and URL, e.g.: http://localhost:9000/contacts/id=007
FUSE supports XML and JSON payloads
Services make use of a natural mapping from HTTP verbs to CRUD operations.
POST: Create a new item of data on the service.GET: Retrieve data from the service.PUT: Update data on the service.DELETE: Delete data from services.
-
11 2008 IONA Technologies
A RESTful Hello, World
-
12 2008 IONA Technologies
Hello WorldA simple Hello, World application:
A client performs a HTTP GET using a URL like: http://localhost:9000/hw/sayHello/user=ade&msg=helloThe server receives the parameters and returns a string value.
Steps: Write a simple Java bean to match the URI template: in this case, to hold the user and msg parameters.Write your business logic in JavaUse a browser, or tools such as curl or wget, to perform a HTTP GET.
-
13 2008 IONA Technologies
Parameters beanInput parameters for the sayHello operation can be modelled easily as a Java bean.
Parameters map to bean fields with appropriate getters and setters.
URI: http://localhost:9000/hw/sayHello/user=ade&msg=hello
Java bean:public class SayHello {private String user;private String msg;
public String getMsg() { }public void setMsg(String message) {}public String getUser() {}public void setUser(String user) {}
}
-
14 2008 IONA Technologies
Business Logic
@WebServicepublic class HelloWorld {
@Get@HttpResource(
location="/sayHello/user={user}&msg={msg})public String sayHello(SayHello params) {
System.out.println(params.getUser() + " said '" + params.getMsg() + "'");
return "Thanks for your message!";}
}
Annotate the class as a web service.
Annotate the class as a web service.
This method will respond to a HTTP GET
This method will respond to a HTTP GET
at this location!
at this location!
Everything else is just plain old Java.
Everything else is just plain old Java.
-
15 2008 IONA Technologies
Deploying your serviceYou can deploy your service into a Spring container, Tomcat, a J2EE application server, or run as a Java mainline.
Boiler plate code:
String URL = "http://localhost:9000/hw/";
JaxWsServerFactoryBean svc = new JaxWsServerFactoryBean();svc.setBindingId(HttpBindingFactory.HTTP_BINDING_ID);svc.setAddress(URL);svc.setServiceBean(new HelloWorld());svc.getServiceFactory().setWrapped(false);svc.create();
System.out.println(Listening on " + URL);
-
16 2008 IONA Technologies
Testing your serviceYou can test your REST services by simply pointing a browser at the URL.
This will implicitly perform a GET on your service.
Alternatively, you can use command-line tools like wget or curlcurl X GET
http://localhost:9000/hw/sayHello/user=ade&msg=hello
The output should be:
Thanks for your message!
Namespace derived from Java package.
Namespace derived from Java package.
-
17 2008 IONA Technologies
Hello, world: lessons learntThe Hello, World example shows how expose a Java method as a RESTful service
with the use of just a few annotations.By default the response payload is returned as XML; later well see how to easily change this to JSON.
This approach works well for algorithmic services.Like calculate my tax.
The next section focuses on more resource-based service.Like retrieve customer details for customer 007654321, or create new customer.
-
18 2008 IONA Technologies
A RESTful resource-based service.
-
19 2008 IONA Technologies
Resource-based serviceConsider a resource such as Customer contact details.
Perhaps you have this modelled as a Java class.Alternatively, you might have this modelled as an XML Schema.
If so, then you can easily generate an equivalent Java class using the JAX-B support provided by FUSE.
You want a RESTful service providing CRUD operations for your document:
Create, retrieve, update, delete customer contacts.
FUSE supports this via the use of URI templates (as before), along with @Post, @Get, @Post, @Delete annotations.
FUSE will marshal the payload (if any) into your parameters.
-
20 2008 IONA Technologies
Update
Delete
CreateRetrieve
RESTful HTTP verbsYou can use the full palette of HTTP verbs:
GET http://.../contacts
GET http://.../contacts/id=123
PUT http://.../contacts/id=123
POST http://.../contacts/id=123
DELETE http://.../contacts/id=123
GET http://.../contacts/name=ade
-
21 2008 IONA Technologies
RESTful HTTP verbsHowever: client technologies may only support GET and POST.
Tip: design your service for the lowest common denominator.
Update
Delete
CreateRetrieve
GET http://.../contacts
GET http://.../contacts/id=123
PUT POST http://.../contacts/id=123
POST GET http://.../contacts/create
DELETE GEThttp://.../contacts/del/id=123
GET http://.../contacts/name=ade
-
22 2008 IONA Technologies
Contact service: interfaceDefining an interface for the ContactService:
@WebServicepublic interface ContactService{
@Get@HttpResource(location="/contacts/create")public Contact createContact() throws CannotCreate;
@Get@HttpResource(location="/contacts/delete/id={id}") public void removeContact(RemoveContact params);
-
23 2008 IONA Technologies
Contacts service: interface (cont)@Get@HttpResource(location="/contacts")public Contacts getContacts();
@Get@HttpResource(location="/contacts/id={id}")public Contact getContact(GetContact gc) throws NotFound;
@Get@HttpResource( location="/contacts/firstName={firstName}&lastName={lastName}
)public Contacts findContacts(FindContactsByName params);
-
24 2008 IONA Technologies
Contacts service: interface (cont)
@Post@HttpResource(location="/contacts/{id}") public void updateContact(Contact params);
-
25 2008 IONA Technologies
Convention-based RESTful-services
-
26 2008 IONA Technologies
RESTful services by conventionFUSE can introspect a Java class and deploy as a RESTful service.
You dont have to provide annotations.FUSE adopts a number of conventions to give an intuitive deployment.
The introspection process must determine:What HTTP verb to use POST, PUT, GET or DELETE?What URL context should the method relate to?
Examples:removePerson(long id) DELETE /people/{id}
updatePerson(long id) PUT /people/{id}
-
27 2008 IONA Technologies
ConventionsConventions are intuitive; best learnt by example.
Method: Collection getContacts()Maps to: GET /contacts.
Method: Contact getContact(long id)Maps to: GET /contacts/{id}.Note the use of a pluralizer in constructing the URI template.
Method: void updateContact(long id, Contact c)Maps to: PUT /contacts/{id}.The contact information is transferred as XML payload.
-
28 2008 IONA Technologies
Conventions (cont)Method: void removeContact(long id)
Maps to: DELETE /contacts/{id}Methods that begin with remove or delete are mapped to HTTP DELETE.
Method: void createContact(Contact c)Maps to: POST /contactsMethods that begin with create or add are mapped to HTTP POST.The contact information is transferred as XML payload.
-
29 2008 IONA Technologies
Support for JSON
-
30 2008 IONA Technologies
JSON - JavaScript Object NotationThe RESTful services shown previously return data formatted as XML.
FUSE can generate XML from JAX-B annotated classes, and classes without annotations (applying suitable conventions).
Alternative payload formats, such as JSON, may be preferred for RESTful services.
JSON (JavaScript Object Notation) is a simple name-value format that facilitates rapid marshalling and unmarshalling:
See http://www.json.org.May be preferred by web developers writing Javascript clients.
FUSE supports JSON by replacing the XML marshaller with a JSON marshaller.
-
31 2008 IONA Technologies
Badgerfish vs. mapped notationRecall: XML elements are typically qualified with their namespace.
JoeBlogsIONA Technologies Consultant [email protected] +353-1234567+353-1234567
-
32 2008 IONA Technologies
Badgerfish vs. mapped notation (cont)When marshalling as JSON, the XML namespaces can be inserted in a mangled form, using Badgerfish notation.
{"getContactResponse":{"@xmlns":{"$":"http:\/\/easyrest\/"},"ns2:Contact":{
"@xmlns":{"ns2":"http:\/\/www.iona.com\/demo\/contact"},"@id":"123","firstName":{"$":"Joe"}, "lastName":{"$":"Blogs"},"company":{"$":"IONA Technologies"},"title":{"$":" Consultant"},"email":{"$":"[email protected]"},"mobile":{"$":"+353-1234567"},"phone":{"$":"+353-1234567"}
}}}
-
33 2008 IONA Technologies
Badgerfish vs. mapped notation (cont)Some prefer to perform an explicit namespace mapping:
{"easyrest.getContactResponse":{"contact.Contact":{
"@id":"123","firstName":"Joe","lastName":"Blogs","company":"IONA Technologies","title":"Consultant","email":"[email protected]","mobile":"+353-1234567","phone":"+353-1234567"
}}}
-
34 2008 IONA Technologies
Configuring an endpoint for JSONFUSE supports both Badgerfish and mapped approaches; to use Badgerfish:
Map properties = ;
BadgerFishXMLInputFactory xif = new BadgerFishXMLInputFactory();
properties.put(XMLInputFactory.class.getName(), xif);
BadgerFishXMLOutputFactory xof = new BadgerFishXMLOutputFactory();
properties.put(XMLOutputFactory.class.getName(), xof);
endpoint.setProperties(properties);
-
35 2008 IONA Technologies
Configuring an endpoint for JSON (cont)For mapped JSON:
HashMap nstojns = ;nstojns.put("http://www.iona.com/demo/contact", "contact");nstojns.put("http://easyrest/", "easyrest");
MappedXMLInputFactory xif = new MappedXMLInputFactory(nstojns);
properties.put(XMLInputFactory.class.getName(), xif);
MappedXMLOutputFactory xof = new MappedXMLOutputFactory(nstojns);
properties.put(XMLOutputFactory.class.getName(), xof);
endpoint.setProperties(properties);
-
36 2008 IONA Technologies
Aside: HTTP content-typeWhen returning JSON payload, the HTTP Content-Type header should be set to something other than text/xml
After all, the payload isnt XML, its JSON.
Use the properties map to set the content-type: properties.put("Content-Type", "text/plain");
Could also set to application/json if preferred.
-
37 2008 IONA Technologies
GWT client code
-
38 2008 IONA Technologies
GWT and AJAX boilerplate Java code
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, "http://...");
try {Request req = builder.sendRequest(null, new RequestCallback() {public void onError(Request request, Throwable exception) {}
public void onResponseReceived(Request request,Response response) {
}});
} catch (RequestException e) {}
-
39 2008 IONA Technologies
GWT and AJAX boilerplate Java code - notes
The RequestBuilder approach is favoured. An alternative approach, using the raw HTTPRequest class, is internally-
focussed and may be deprecated.
RequestBuilder only supports HTTP GET and POST.DELETE and PUT and other verbs not supported, due to a bug in Safari
implementation of the XMLHTTPRequest.
-
40 2008 IONA Technologies
GWT support for JSON
GWT provides support for creating and parsing JSON payload. See classes in package com.google.gwt.json.client.
public String toJSON() { JSONObject obj = new JSONObject();obj.put("firstName", new JSONString(Ade));obj.put("lastName", new JSONString(Trenaman));
JSONObject contact = new JSONObject();contact.put("er.Contact", obj);return contact.toString();
}
{"er.Contact":{"firstName":"Ade","lastName":"Trenaman"}}{"er.Contact":{"firstName":"Ade","lastName":"Trenaman"}}
-
41 2008 IONA Technologies
GWT support for JSON (cont)A similar API exists for parsing JSON.
JSONValue jsonValue = JSONParser.parse(responseText);JSONObject obj = jsonValue.isObject();JSONValue contact = obj.get("er.Contact");JSONValue firstName = contact.isObject().get("firstName");
-
42 2008 IONA Technologies
Summary
-
43 2008 IONA Technologies
Summary
Use CXF (Fuse) to provide JSON services for AJAX clients.Native support for RESTful JSON and XML payloads using explicit or implied conventions.CXF first implementation of JSR-311 Java API for RESTful Web Services.
Use GWT to build dynamic, flexible browser-based clients.Full API for JSON and AJAX interactions.
Drawbacks: GWTs JSON API makes you do a lot of the hard work for marshalling and unmarshalling.
Perhaps leverage JSNI?
-
44 2008 IONA Technologies
ResourcesGoogle Web Toolkit:
Go to http://code.google.com/webtoolkit
CXF, Fuse Service Framework and IONA:Learn more: http://open.iona.com/Download: http://open.iona.com/downloads/Browse demos:
samples/restful_http_bindingsamples/restful_dispatch
Contribute!
Need help? Visit the forums on Apache and open.iona.com. Contact us: [email protected]