cdi, seam & resteasy: you haven't seen rest yet!
DESCRIPTION
JSR-311 (JAX-RS) is one of the simplest, most elegant of all the Java EE specifications. It enables you to create RESTful web services from POJOs by sprinkling a handful of annotations on them. As of Java EE 6, JAX-RS resources can now tie into the rest of the Java EE platform through the use of the standard contexts and dependency injection. facility (JSR-299: CDI). Seam's RESTEasy module takes this a step further by allowing you to use JAX-RS annotations on your existing Seam components, giving your REST resources access to the Seam container, infusing them with enhanced security, persistence management and other Seam portable extensions. You'll also discover that Seam eliminates the configuration required to add JAX-RS to your application and you'll be enthralled by the module's innovative approach to doing CRUD over REST. Using Seam, CDI and JAX-RS together let's you REST like never before.TRANSCRIPT
CDI, Seam & RESTEasy
You haven’t seen REST yet!
Dan AllenSenior Software EngineerJBoss, by Red Hat
Agenda
REST principles
JAX-RS
Seam RESTEasy integration
JAX-RS enhanced with CDI
Demo
Abusing HTTP with SOAP
REST to the rescue
Web ServiceWeb
Staying grounded with REST
Simple
Lightweight
High performance
Simple ingredients of the Web
HTTP application protocol
URI naming standard
XML markup language (and alternatives)
A tale of two webs
Browsable web
Programmable web
HTML +images +CSS, etc
XML(or JSON)
Document
Every web site is a service
Enabling automation
REST, spelled out
REpresentational State Transfer
RESTful architectural principles
Addressable resources
Uniformed, constrained interface
Representation-oriented
Stateless communication
Addressable resources
URI for every resource in system
Resource reachable by unique ID
Provides scoping information
– Query string used to narrow result set
Stepping stones
– Makes it possible to link (linkability)– Allows disparate applications to interact
http://socialize.com/rest/updates/311http://socialize.com/rest/updates/311
Uniformed, constrained interface
Protocol method == operation
– 4 HTTP methods: GET, PUT, DELETE, POST
An architecture based on 4 methods?
– SQL (SELECT, INSERT, UPDATE, DELETE)– JMS (send, receive)
HTTP methods
GET - read only, idempotent and safe
PUT - insert or update, idempotent
DELETE - remove services, idempotent
POST - NOT idempotent NOR unsafe
– constraints are relaxed for flexibility
Representation-oriented
Data has a representation
– Negotiated between client and server
HTTP was designed for this purpose
Client – “I would prefer...”
– Accept (MIME type)– Accept-Language– Accept-Encoding
Server – “Here's what I'll give you...”
– Content-type header (MIME type)
Stateless communication
More scalable
– GET lends itself well to caching
Client maintains state
Takes burden off server
Respect the medium
Request
– HTTP method– URI– Request headers– Entity body
Response
– HTTP response code– Response headers– Entity body
What do you need to REST?
HTTP client (browser, bot, smart phone)
HTTP server that speaks REST
JAX-RS
JSR-311: JAX-RS
Java APIs for developing Web Services following the REST architectural style
Served via an HTTP servlet
Goals:
– POJO-based (annotations)– HTTP-centric– Format independent (MIME type)– Container independent– Inclusion in Java EE 5+
http://socialize.com/rest/timelinehttp://socialize.com/rest/timeline
Our first REST resource
@Path("/timeline")public class TimelineService {
@GET public String getUpdates() { return "<updates><update>...</update></updates>"; }
}
@Path("/timeline")public class TimelineService {
@GET public String getUpdates() { return "<updates><update>...</update></updates>"; }
}
Our first JAX-RS resource
How it works
REST Servlet handles GET request
Instance of TimelineService is created
@GET method called
Return value sent as response
Resource instance thrown away
JAX-RS component model is intentionally simple!
http://socialize.com/rest/timeline?count=25http://socialize.com/rest/timeline?count=25
Throttling the response
@Path("/timeline")public class TimelineService {
@GET public String getUpdates(@QueryParam("count") @DefaultValue("50") int count) { ... }
}
@Path("/timeline")public class TimelineService {
@GET public String getUpdates(@QueryParam("count") @DefaultValue("50") int count) { ... }
}
Accepting a query parameter
http://socialize.com/rest/timeline http://socialize.com/rest/timeline
http://socialize.com/rest/timeline?count=50http://socialize.com/rest/timeline?count=50
↴
Parameter types
@QueryParam – Query string
@HeaderParam – HTTP header
@CookieParam – HTTP cookie
@FormParam – Form input
@PathParam – URI path
@MatrixParam – Matrix URI segment
Stepping into a sub-resource
http://socialize.com/rest/timeline/mojavelinuxhttp://socialize.com/rest/timeline/mojavelinux
@Path("/timeline")public class TimelineService {
@GET @Path("/{username}") public String getUpdates(@PathParam("username") String u) { ... }
}
@Path("/timeline")public class TimelineService {
@GET @Path("/{username}") public String getUpdates(@PathParam("username") String u) { ... }
}
Mapping a path parameter
Name defined in path expression;segment injected into method
@Path("/timeline")public class TimelineService {
@GET @Path("/{id:[0-9]+}") public String getUpdatesById(@PathParam("id") long id) { ... }
@GET @Path("/{username}") public String getUpdatesByUsername( @PathParam("username") String u) { ... }}
@Path("/timeline")public class TimelineService {
@GET @Path("/{id:[0-9]+}") public String getUpdatesById(@PathParam("id") long id) { ... }
@GET @Path("/{username}") public String getUpdatesByUsername( @PathParam("username") String u) { ... }}
Mapping different patterns
Fallback if patterns don't match
Negotiating a response
Which representation?
– Plain text?– HTML?– XML?– JSON?
The client needs to tell us
– Accept formats, weighted by preference
We have to decide what we support
– Respond with best match
@Path("/timeline")public class TimelineService {
@GET @Path("/{u}") @Produces("application/xml") public String getUpdatesAsXml(@PathParam("u") String u) { ... }
...}
@Path("/timeline")public class TimelineService {
@GET @Path("/{u}") @Produces("application/xml") public String getUpdatesAsXml(@PathParam("u") String u) { ... }
...}
Producing explicitly
Specify which formats aresupported using @Produces
@Path("/timeline")public class TimelineService {
@GET @Path("/{u}") @Produces("application/json") public String getUpdatesAsJson(@PathParam("u") String u) { ... }
...}
@Path("/timeline")public class TimelineService {
@GET @Path("/{u}") @Produces("application/json") public String getUpdatesAsJson(@PathParam("u") String u) { ... }
...}
Producing explicitly
Specify which formats aresupported using @Produces
Simplifying response production
Creating XML and JSON is laborious :(
JAX-RS supports converters
– HTTP entity body readers/writers
Provides built-in JAXB provider!
– Object ⇔ XML– Object ⇔ JSON
@XmlRootElement(name = "updates")public class Timeline implements Serializable {
private List<Update> updates = new ArrayList<Update>();
// constructors
@XmlElement(name = "update") public List<Update> getUpdates() { return updates; }
public void setUpdates(List<Update> updates) { this.updates = updates; }
}
@XmlRootElement(name = "updates")public class Timeline implements Serializable {
private List<Update> updates = new ArrayList<Update>();
// constructors
@XmlElement(name = "update") public List<Update> getUpdates() { return updates; }
public void setUpdates(List<Update> updates) { this.updates = updates; }
}
A model with XML hints
@Entity@XmlRootElementpublic class Update implements Serializable {
private Long id; private User user; private Date created; private String text;
// getters and setters
}
@Entity@XmlRootElementpublic class Update implements Serializable {
private Long id; private User user; private Date created; private String text;
// getters and setters
}
A related model with XML hints
@Path("/timeline")public class TimelineService {
@GET @Path("/{u}") @Produces("application/xml") public Timeline getUpdates(@PathParam("u") String u) { List<Update> updates = ...; return new Timeline(updates); }
}
@Path("/timeline")public class TimelineService {
@GET @Path("/{u}") @Produces("application/xml") public Timeline getUpdates(@PathParam("u") String u) { List<Update> updates = ...; return new Timeline(updates); }
}
Turning production over to JAXB
RESTEasy
Fully certified JAX-RS implementation
Portable to any container
Embedded server for testing
Client-side framework for JAX-RS
Response caching and compression
Rich set of providers
– XML, JSON, RSS, Atom, YAML, etc.
Asynchronous support
public interface TimelineClient {
@GET @Path("/timeline") @Produces("application/xml") Timeline getUpdates(@QueryParam("count") int count);
}
public interface TimelineClient {
@GET @Path("/timeline") @Produces("application/xml") Timeline getUpdates(@QueryParam("count") int count);
}
Invoking a service with RESTEasy
TimelineClient client = ProxyFactory.create(TimelineClient.class, ROOT_URI);String response = client.getUpdates(25);
TimelineClient client = ProxyFactory.create(TimelineClient.class, ROOT_URI);String response = client.getUpdates(25);
What does Seam 2 provide?
RESTEasy bootstrap and configuration
– Automatic resource/provider discovery– Resources/providers are Seam components
Seam security– HTTP authentication
– Authorization: @Restrict, @PermissionCheck
Exception to HTTP response mapping
Media type extension mapping
REST CRUD framework
SeamTest support
public abstract class Application { public abstract Set<Class<?>> getClasses(); public abstract Set<Object>getSingletons();}
public SocializeConfig extends Application { ...}
<context-param> <param-name>javax.ws.rs.core.Application</param-name> <param-value>com.socialize.SocializeConfig</param-value></context-param>
public abstract class Application { public abstract Set<Class<?>> getClasses(); public abstract Set<Object>getSingletons();}
public SocializeConfig extends Application { ...}
<context-param> <param-name>javax.ws.rs.core.Application</param-name> <param-value>com.socialize.SocializeConfig</param-value></context-param>
Typical JAX-RS setup (Java EE 5)
REST as a Seam resource
http://socialize.com/seam/resources/rest/timeline/mojavelinuxhttp://socialize.com/seam/resources/rest/timeline/mojavelinux
@Name("timelineService")@Path("/timeline")public class TimelineService { @In TimelineDao timelineDao;
@GET @Path("/{u}") @Produces("application/xml") public Timeline getUpdates(@PathParam("u") String u) { return timelineDao.fetchTimelineForUsername(u); }
}
@Name("timelineService")@Path("/timeline")public class TimelineService { @In TimelineDao timelineDao;
@GET @Path("/{u}") @Produces("application/xml") public Timeline getUpdates(@PathParam("u") String u) { return timelineDao.fetchTimelineForUsername(u); }
}
Seam-infused REST
<exception class="com.socialize.NoSuchUserException"> <http-error error-code="404"> <message>No such user</message> </http-error></exception>
<exception class="com.socialize.NoSuchUserException"> <http-error error-code="404"> <message>No such user</message> </http-error></exception>
Trapping exceptions
REST in a few fragments
<components> <framework:entity-home name="userHome" entity-class="com.socialize.model.User"/>
<resteasy:resource-home name="userResourceHome" path="/users" entity-home="#{userHome}" entity-id-class="java.lang.Long" media-types="application/xml application/json" readonly="false"/>
<resteasy:resource-query name="userResourceQuery" path="/users" entity-class="com.socialize.model.User" media-types="application/xml application/json"/></components>
<components> <framework:entity-home name="userHome" entity-class="com.socialize.model.User"/>
<resteasy:resource-home name="userResourceHome" path="/users" entity-home="#{userHome}" entity-id-class="java.lang.Long" media-types="application/xml application/json" readonly="false"/>
<resteasy:resource-query name="userResourceQuery" path="/users" entity-class="com.socialize.model.User" media-types="application/xml application/json"/></components>
Java EE 6, keeping it simple
@ApplicationPath("rest")public class JaxRsConfig extends Application {}@ApplicationPath("rest")public class JaxRsConfig extends Application {}
@Stateless@Path("/timeline")public class TimelineService { @PersistenceContext EntityManager em;
@GET @Path("/{u}") @Produces("application/xml") public Timeline getUpdates(@PathParam("u") String u) { return new Timeline(em.createQuery( "select u from Update u where u.user.username = :u") .setParameter("u", u).getResultList()); }}
@Stateless@Path("/timeline")public class TimelineService { @PersistenceContext EntityManager em;
@GET @Path("/{u}") @Produces("application/xml") public Timeline getUpdates(@PathParam("u") String u) { return new Timeline(em.createQuery( "select u from Update u where u.user.username = :u") .setParameter("u", u).getResultList()); }}
Must be a managedbean to enable CDI
Java EE 6, keeping it clean
@ApplicationPath("rest")public class JaxRsConfig extends Application {}@ApplicationPath("rest")public class JaxRsConfig extends Application {}
@Stateless@Path("/timeline")public class TimelineService { @Inject TimelineDao timelineDao;
@GET @Path("/{u}") @Produces("application/xml") public Timeline getUpdates(@PathParam("u") String u) { return timelineDao.fetchTimelineForUsername(u); }
}
@Stateless@Path("/timeline")public class TimelineService { @Inject TimelineDao timelineDao;
@GET @Path("/{u}") @Produces("application/xml") public Timeline getUpdates(@PathParam("u") String u) { return timelineDao.fetchTimelineForUsername(u); }
}
Socialize demo
Summary and call to action
Respect HTTP
– Resources are the foundation of the web
Expose your data in a standard way
– Don’t ball it up inside web pages!
Embrace simplicity
– Seam 2 + RESTEasy– Java EE 6 (JAX-RS + CDI)– Seam 3 integration coming soon...
Must reads
RESTful Web ServicesRichardson & RubyO’Reilly
RESTful Java with JAX-RSBill BurkeO’Reilly
To follow me
mojavelinux
GET /questions? HTTP/1.1
Presentation resources
JSR-311– http://jcp.org/en/jsr/detail?id=311
RESTEasy– http://jboss.org/resteasy
Seam RESTEasy integration– Web Services chapter of Seam reference guide
Bill Burke’s REST series on DZone– http://java.dzone.com/articles/putting-java-rest
Code samples– http://seaminaction.googlecode.com/svn/demos