Post on 27-Jan-2015
description
transcript
About Me
Graduated (finally) as BE in Computers - 2002
Worked with Infosys, Opus Software Solutions and Synerzip
Core expertise in Java Enterprise and Middle-Ware stack
EAI, EII, Rule Engines, ESB, Spring, ORM, Data Virtualization
Currently working as Solutions Architect with Synerzip
Agenda
REST methodology introduction JAX-RS 2.0
History Use cases Features
Odata History Use cases Features
SOA
Service Oriented Architecture is an architecture paradigm where the software components are provided as services accessed through a network accessible endpoint
There is no object broker required as there is no remote object reference held by the clientRegistry
ContractProtocolDefines Format & Operations
Registers
What is REST?
REST stands for REpresentational State Transfer. The largest example of system conforming to REST
architecture is the World Wide Web. In the REST architectural style, data and functionality
are considered resources and are accessed using Uniform Resource Identifiers (URIs), typically links on the Web.
This architecture style is called REST since the state of the client changes with each URI (link in layman’s term) accessed. The URI provides the representation that is returned by the resource.
Resources are manipulated using a fixed set of four CRUD (create, read, update, delete) operations: PUT, GET, POST and DELETE
Current version of JAX-RS in production is JAX-RS 1.1 and JAX-RS 2.0 is currently being drafted.
JAX-RS
JAX-RS is Java API for RESTful Web Services
REST principals Assign URL to everything Link things together for state
transition(called HyperMedia as the engine of application state)
Use common methods Multiple representations of state Stateless communication
Introduced in JEE 5
Pros/Cons: JAX-WS Vs JAX-RS
JAX-WSJAX-WS JAX-RSJAX-RS
• Formal contract that describes the
web service (in the form of WSDL) is
available• Technologies defined by the
WorldWide Web Consortium (W3C):
HTTP (forTransport protocol), SOAP and
WSDL• Implemented either using an
EJB 3endpoint or using servlet
endpoint.• Can provide transactions,
security,Reliability and asynchronous
messages
• Formal contract that describes the
web service (in the form of WSDL) is
available• Technologies defined by the
WorldWide Web Consortium (W3C):
HTTP (forTransport protocol), SOAP and
WSDL• Implemented either using an
EJB 3endpoint or using servlet
endpoint.• Can provide transactions,
security,Reliability and asynchronous
messages
• Does not require creation of
client/server proxies• Requires only HTTP forapplication protocol - data interchange using XML, HTML,JSON,URL encoded forms etc• Implemented as a servletendpoint only • Possible to discover
resourceswithout centralized repository
• Does not require creation of
client/server proxies• Requires only HTTP forapplication protocol - data interchange using XML, HTML,JSON,URL encoded forms etc• Implemented as a servletendpoint only • Possible to discover
resourceswithout centralized repository• Requires client/server
proxies to make the SOAP based web
service call
• Requires client/server proxies to
make the SOAP based web service call
• Service provider and client need
to have understanding of thecontext and content provided
byservice (Not now as WSDL 2.0 /WADL / XML schema can beused to describe REST web
service) butthey don’t have standard
client support
• Service provider and client need
to have understanding of thecontext and content provided
byservice (Not now as WSDL 2.0 /WADL / XML schema can beused to describe REST web
service) butthey don’t have standard
client support
JAX-RS annotations
Annotation Description
@Path The @Path annotation defines the relative path where the web service is hosted. You could also embed variables in path like “/employee/{id}. A @Path value isn’t required to have leading or trailing slashes (/).The path can be applied to a root resource or to a sub-resource.
@GET, @POST@DELETE, @PUT
These annotations are request method designators and correspond to HTTP request method that will be serviced by this class method
@PathParam The @PathParam annotation is a type of parameter that you can extract from the URI path and use in the class/method
@QueryParam The @QueryParam annotation is a type of parameter that you can extract from the request URI query parameters and use in the class/method
@Consumes The @Consumes annotation is used to specify the MIME types of representations sent by the client that a resource can consume.
@Produces The @Produces annotation is used to specify the MIME types of representations sent by the resource to the client e.g. “application/xml”
Basic REST Web Service@Path("rest")public class RootResource {
/* * The @Context makes the HTTP context related objects available to the * resource class */@Contextprivate transient SecurityContext secContext;
@Contextprivate transient HttpServletRequest request;
@Injectprivate Provider<BaseProducer> producer;
@Path("employee")public EmployeeResource getEmployeeResource() {
this.request.setAttribute("test", "Memory");EmployeeResource returnResource = new EmployeeResource();returnResource.setContext(this.secContext);producer.get();return returnResource;
}@GET@Produces({ "application/xml; qs=0.9", MediaType.APPLICATION_JSON })public String sayXMLHello() {
return "<?xml version=\"1.0\"?>" + "<hello> Hello Jersey" + "</hello>";}
}
Resources
Dependency
Injection
HTTP Method Binding
Web Deployment Descriptor
<web-app id="WebApp_ID" version="2.4"xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-
app_2_4.xsd"><display-name>JAXRS_REST_WebServices</display-name>
<servlet><servlet-name>Jersey REST Service</servlet-name><servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class><init-param>
<param-name>javax.ws.rs.Application</param-name><param-value>com.anil.jaxb.resource.config.ApplicationConfigSetter</
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>
There are various ways in which we can have Jersey discover the resources to be deloyed.
For simple deployments, no web.xml is needed at all. Instead, an @ApplicationPath annotation can be used to annotate the user defined application class and specify the the base resource URI of all application resources.
Basic Jersey Client
/** * This method is used to test get/delete request for an employee to the * REST API API * * @throws IOException */@Testpublic void testDeleteEmployeeRequest() throws IOException {
WebTarget webResource = this.client.target(getBaseURI()).path("rest/employee/3");
// Register the authentication to be used for logging in the web// applicationwebResource.configuration().register(
new HttpBasicAuthFilter("tomcat", "tomcat"));
String getResponse = webResource.request(MediaType.APPLICATION_XML).get(String.class);
String deleteResponse = webResource.request(MediaType.APPLICATION_XML).delete(String.class);
System.out.println("The response received from get is: " + getResponse);System.out.println("The response received from delete is: "
+ deleteResponse);}
Web Service Security
Since REST web services are essentially HTTP resources, they can be protected using the Java EE web authentication and authorization mechanism using elements in web.xml file.
<!-- The web resources with root /rest are protected --><security-constraint>
<web-resource-collection><web-resource-name>REST</web-resource-name><url-pattern>/rest/employee/*</url-pattern>
</web-resource-collection><auth-constraint>
<!-- Use the tomcat-users.xml for authentication --><role-name>tomcat</role-name>
</auth-constraint></security-constraint>
<!-- Define the Login Configuration for this Application --><login-config>
<auth-method>BASIC</auth-method><realm-name>UserDatabaseRealm</realm-name>
</login-config>
<!-- Security roles referenced by this web application --><security-role>
<description>The unlimited role allowed to login to the application.</description>
<role-name>tomcat</role-name></security-role>
Sub-resource Locators
We can delegate the handling of request to sub resources by using methods annotated with @Path BUT not annotated with resource method designators such as @GET or @POST.
Note that the runtime will not manage the life-cycle or perform any field injection onto instances returned from sub-resource locator methods.
However, sub-resources support method injection.@Path("rest")public class RootResource {
.............@Path("employee")public EmployeeResource getEmployeeResource() {
this.request.setAttribute("test", "Memory");EmployeeResource returnResource = new EmployeeResource();returnResource.setContext(this.secContext);return returnResource;
}}
Exceptions, URIBuilder, JAXB Based JSON support
JAX-RS provides exceptions to be thrown which match to HTTP error codes; examples include javax.ws.rs.NotFoundException, javax.ws.rs.ServerErrorException
The JAX-RS runtime provides URIBuilder class which takes care of specifics like encoding etc which you would need to otherwise do manually for java.net.URI class.
JAXB/JSON support is provided by using custom Message readers and writers.
@Produces(MediaType.APPLICATION_XML)
public Response insertEmployee(final Employee employee,
@Context UriInfo uriInfo) {...........}
Custom Serialization for JAXB
Injecting Types
We can define fields/method params etc to be injected with object of the described type by the JAX-RS runtime.
Injection can be performed on fields, constructor parameters, resource/sub-resource/sub-resource locator method parameters and bean setter methods.
For JAX-RS 1.1, @Context annotation was used to indicate injectables to JAX-RS runtime.
JAX-RS 2.0 has integrated with JSR-330 (CDI) and Jersey supports CDI using HK2. You can use @Context or @Inject though @Context is still preferred.
The proposal for this area is not finalized yet in JAX-RS 2.0 specifications
JAX-RS 2.0 features
Client API Filters & handlers
Asynchronous
Processing
Validation (JSR-349)
Hypermedia
CDI (JSR-330)
Server Side
Connection
Negotiation
Client API
The JAX-RS 1.1 specifications was focussed on server side and there was no client API.
Need for a standard to also share server side API(readers/writer) and encapsulate boiler plate codeClient
FactoryClient
Target
Request Builder
Invocation
Response
Configuration
Client API
Create a new client (This is heavy!!)this.client = ClientFactory.newClient();
Use builder pattern to invoke server resources – supports adding query params, target entities etc.
Close the client after use.
WebTarget webResource = this.client.target(getBaseURI()).path("rest/employee");// Register the authentication to be used for logging in the web// applicationwebResource.configuration().register(new HttpBasicAuthFilter("tomcat", "tomcat"));
Response response = webResource.request(MediaType.APPLICATION_XML).put(Entity.entity(employeeToAdd, MediaType.APPLICATION_XML),Response.class);
Client API
Support for generic invocation using command pattern for batch processing
Invocation invGoodRequest = this.client.target(getBaseURI()).path("rest/employee").request(MediaType.APPLICATION_XML).buildPut(Entity.entity(inputXMLBuilder.toString(),
MediaType.APPLICATION_XML));
invGoodRequest.configuration().register(new HttpBasicAuthFilter("tomcat", "tomcat"));
Collection<Invocation> invCollection = Arrays.asList(invGoodRequest,invBadRequest);
// Execute the invocation as a batch processfor (Invocation currentInvocation : invCollection) {
// By default invoke() returns a response but we also have an// overloaded method that takes the target class as parameterResponse response = currentInvocation.invoke();
}
Filters and Handlers
Message request pre-processing and response post-processing via well-defined extension points on the client and server side.
Use cases – logging, stream marshalling(Gzip etc), security Filters
Each filter can decide to continue or break the chain Filters in the filter chain are ordered according to their binding
priority The binding priority is an annotation that specifies an integer
based priority You can match what filters are applied to what resources –
default is global Do not directly invoke the next filter in the chain – hence is
called Non wrapping filter chain Filters implementing this interface must be annotated with
@Provider to be discovered by the JAX-RS runtime
Filters and Handlers@Provider@Logging@BindingPriority(1)public class LoggingFilter implements ContainerRequestFilter,
ContainerResponseFilter {private static Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
/* * @see * javax.ws.rs.container.ContainerResponseFilter#filter(javax.ws.rs.container * .ContainerRequestContext, javax.ws.rs.container.ContainerResponseContext) */@Overridepublic void filter(ContainerRequestContext reqContext,
ContainerResponseContext responseContext) throws IOException {logger.info("POST request filter for server and the response entity class
is: "+ responseContext.getEntity().getClass().getCanonicalName());
}/** @see * javax.ws.rs.container.ContainerRequestFilter#filter(javax.ws.rs.container * .ContainerRequestContext) */@Overridepublic void filter(ContainerRequestContext reqContext) throws IOException {
logger.info("PRE request filter for server: "+ reqContext.getRequest().toString());
}}
Filters and Handlers
@Target({ ElementType.TYPE, ElementType.METHOD })@Retention(value = RetentionPolicy.RUNTIME)@NameBindingpublic @interface Logging {
}
@GET@Produces({ "application/xml; qs=0.9", MediaType.APPLICATION_JSON })@Loggingpublic String sayXMLHello() {
return "<?xml version=\"1.0\"?>" + "<hello> Hello Jersey" + "</hello>";
}
Filters and Handlers
Handlers are wrapping i.e. It directly invokes the next handler in the handler chain
Typically used for message data marshalling and un-marshalling
By default handlers are global but mechanism is provided for static(@NameBinding) as well as dynamic binding(DynamicBinding interface) of a filter or handler to a particular resource or resource method
Typically used to say compress streams API still work in progress
Asynchronous Messaging
Server API support Execute long running server processes Frees up container threads to service other
requests By default remain suspended till the server
event completes Resume operation once the server event is
generated Client API support
Asynchronous request invocation API
Asynchronous Messaging - Serverpublic static final String NOTIFICATION_RESPONSE = "Hello async world!";private static final Logger LOGGER = LoggerFactory.getLogger(HelloResource.class.getName());private static final int SLEEP_TIME_IN_MILLIS = 1000;private static final ExecutorService TASK_EXECUTOR = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("long-running-resource-executor-%d").build());private static int count = 0;
/** * Asyc method server support * * @param asyncResponse */@Path("async")@GETpublic void longGet(@Suspended final AsyncResponse asyncResponse) {
TASK_EXECUTOR.submit(new Runnable() {
@Overridepublic void run() {
try {Thread.sleep(SLEEP_TIME_IN_MILLIS);LOGGER.debug("Received request for async processing: "
+ HelloResource.count++);} catch (InterruptedException ex) {
LOGGER.error("Response processing interrupted", ex);}asyncResponse.resume(NOTIFICATION_RESPONSE);
}});
}
Asynchronous Messaging - Client@Testpublic void testAsyncClientRequests() throws InterruptedException {
Client client = ClientFactory.newClient();WebTarget webResource = client.target(getBaseURI()).path("hello/async");final int REQUESTS = 10;final CountDownLatch latch = new CountDownLatch(REQUESTS);for (int i = 0; i < REQUESTS; i++) {
webResource.request(MediaType.TEXT_PLAIN).async().get(new InvocationCallback<Response>() {
@Overridepublic void completed(Response response) {
try {final String result = response
.readEntity(String.class);Assert.assertEquals("Hello Jersey", result);
} finally {latch.countDown();
}}@Overridepublic void failed(ClientException exception) {
System.out.println("Exception while invocation: "+ exception.getMessage());
latch.countDown();}
});}
}
Validation
Services need to validate data before processing Bean Validation is a Java specification which:
provides a unified way of declaring and defining constraints on an object model.
defines a runtime engine to validate objects Already have JSR 349: Bean Validation 1.1 which
needs to be integrated to JAX-RS Support for constraint annotations in
Methods (response entities) Fields & properties Parameters (in request entity) Resource classes
Validation
@POST@Consumes(MediaType.APPLICATION_FORM_URLENCODED)@Produces(MediaType.APPLICATION_XML)public String searchEmployee(@NotNull @FormParam("name") String name,
@OrderNumber @FormParam(“orderNumber") String orderNumber,@FormParam(“department") String department) {
@Constraint(validatedBy = OrderNumberValidator.class) @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) @Retention(RUNTIME) public @interface OrderNumber {
String message() default "{custom message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {};
}
public class OrderNumberValidator implements ConstraintValidator<OrderNumber, String> {/** Configure the constraint validator based on the elements specified at the
time it was defined. */ public void initialize(OrderNumber constraint) { ... } /** Validate a specified value. returns false if the specified value does not conform to the definition */ public boolean isValid(String value, ConstraintValidatorContext context) {
//validate value }
}
Default
Custom
HyperMedia
Use HATEOAS (Hypermedia As The Engine Of App State) REST principle
Structural links are used to avoid sending a complete representation of a resource and enable lazy loading. The clients can follow these type of links to retrieve the "pieces" they need.
Transitional link is used to update the state of a resource and is typically identified by a "rel" attribute.
Structural links are normally in the entity; transitional links could be in link headers or the entity.
Support transitional links only
Improved Connection Negotiation This would allow a server to specify a
preferred MIME type if the client does not care about it.
An unspecified value takes the default value of 1
The rule says "application/json" will be served as the preferred type if there is no Accept header from the client.
@GET@Produces({ "application/xml; qs=0.9", MediaType.APPLICATION_JSON })@Loggingpublic String sayXMLHello() {return "<?xml version=\"1.0\"?>" + "<hello> Hello Jersey" + "</hello>";}
WADL/WSDL 2.0
The Web Application Description Language (WADL) is a machine-readable XML description of HTTP-based web applications (typically REST web services).
REST doesn’t really require description; follow links
Additionally because the WADL generates machine readable code, it would break when the interface changes – tight coupling
WSDL 2.0 adds supports for REST services Sample WADL available at
http://odata4j-sample.appspot.com/datastore.svc/application.wadl
Odata - Introduction
Open Data Protocol (OData) is a Web protocol for querying and updating data
Based on Web technologies such as HTTP, Atom Publishing Protocol (AtomPub) and JSON
The OData Protocol is different from other REST-based web service approaches in that it provides a uniform way to describe both the data and the data model
The current version of Odata specifications is version 3; however the java implementation for OData (called OData4j) supports version 2
OData4j will move to version 3 after release 1.0; currently at 0.7
ATOM
Atom is an XML-based document format that describes lists of related information known as "feeds“
Feeds are composed of a number of items, known as "entries", each with an extensible set of attached metadata
The "atom:entry" element represents an individual entry, acting as a container for metadata and data associated with the entry.
It can be child of an atom:feed element OR it can be the top level element
ATOM Example
<?xml version="1.0" encoding="utf-8"?> <feed xmlns="http://www.w3.org/2005/Atom">
<title>Example Feed</title> <link href="http://example.org/"/> <updated>2003-12-13T18:30:02Z</updated> <author>
<name>John Doe</name> </author> <id>urn:uuid:60a76c80-d399-11d9-b93C-
0003939e0af6</id> <entry> <title>Atom-Powered Robots Run Amok</title> <link
href="http://example.org/2003/12/13/atom03"/> <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-
80da344efa6a</id> <updated>2003-12-13T18:30:02Z</updated>
<summary>Some text.</summary> </entry>
</feed>
XML Namespace
ATOM feedMetadat
a
Entry
Odata Structure
Feed Metadata (title, id, updated etc) Collection of entries
Entry Properties (primitives & complex) Links (related entries and related feeds)
Service document that lists all the top level feeds – usually serviced by the service root URI endpoint
OData services can also expose Service Operations, which are simple, service-specific functions that accept input parameters and return entries or complex/primitive values.
The data is usually serviced by a producer who can expose data from relational databases, web services etc
The producer takes care of transformation between EDM and the underlying data access layer
EDM
Entity Data Model (EDM) - is the underlying abstract data model used by OData services to formalize the description of the resources it exposes
All data services may also expose a Service Metadata Document that describes the data model (i.e. structure and organization of all the resources) exposed as HTTP endpoints by the service.
Metadata is available at the endpoint using convention $metadata
The central concepts in the EDM are entities and associations.
EDM is defined using an XML language called conceptual schema definition language (CSDL)
EDM
EntityTypes – data model definitions(for example customer, product etc)
Entities – instances of Entity types with a key and structured type consisting of list of properties
Complex Types - structured types also consisting of a list of properties but with no key
Entity Key – primary key either single or composite Associations - define the relationship between two
or more Entity Types Navigation Properties - special properties on Entity
Types which are bound to a specific association and can be used to refer to associations of an entity
OData Producers
Create a factory that OData4j can use to initialize the producer
OData4j currently supports JPAProducer & InMemoryProducer. It also plans to support JDBCProducer in the near future.
You can write your own producer and it has to implement the org.odata4j.producer.ODataProducer interface.
Registering Producer
public class ODataJPAProducerFactory implements ODataProducerFactory {
private String persistenceUnitName = "odataJPAService";private Strig namespace = "odataJPA";private int maxResults = 50;
@Overridepublic ODataProducer create(Properties arg0) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnitName);
JPAProducer producer = new JPAProducer(emf, namespace, maxResults);return producer;}
}<servlet>
<servlet-name>OData</servlet-name><servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-
class><init-param>
<param-name>javax.ws.rs.Application</param-name><param-value>org.odata4j.jersey.producer.resources.ODataApplication</
param-value></init-param><init-param>
<param-name>odata4j.producerfactory</param-name><param-value>com.synerzip.odata.producer.ODataJPAProducerFactory</
param-value></init-param><load-on-startup>1</load-on-startup>
</servlet>
Inject Producer
Register Producer
URI Convention
URI Used for Example
$links Get all associations between entries
http://localhost:8080/odata_example/odatajpa.svc/SupplierParts(1L)/$links/part
$orderby
Order data based on desc or asc (default) options
http://localhost:8080/odata_example/odatajpa.svc/SupplierParts?$orderby=quantity desc
$top Return first N items of the set
http://localhost:8080/odata_example/odatajpa.svc/SupplierParts?$orderby=quantity desc&$top=4
$skip Skip the first N records of the entity set and get next
http://localhost:8080/odata_example/odatajpa.svc/SupplierParts?$skip=2&$top=2
$filter Select only subset of entities that match the predicates provided – rich set of operators and functions
http://localhost:8080/odata_example/odatajpa.svc/SupplierParts?$filter=(quantity gt 200 and quantity lt 300) or shipperId eq 10
URI Convention
URI Used for Example
$expand
Eagerly load associations inline
http://localhost:8080/odata_example/odatajpa.svc/Supplier?$expand=supplierParts
$format
Specify what media type to be used for response(Atom/Xml/Json)
http://localhost:8080/odata_example/odatajpa.svc/Supplier?$expand=supplierParts&$format=Json
$select Return only subset of properties
http://localhost:8080/odata_example/odatajpa.svc/Supplier?$select=supplierCity, supplierId
$inlinecount
Response should include the count on entities after applying $filter. Valid values are allpages/none
http://localhost:8080/odata_example/odatajpa.svc/Supplier?$inlinecount=allpages<m:count>16</m:count>
CUD Operations using Consumer// create the new productOEntity newSupplier = consumer.createEntity("Supplier")
.properties(OProperties.string("supplierId", "S200"))
.properties(OProperties.string("supplierName", "Smith A"))
.properties(OProperties.string("supplierCity", "Boston"))
.properties(OProperties.string("supplierState", "MA"))
.properties(OProperties.decimal("supplierStatus", 20L))
.execute();
// update the newly created productconsumer.updateEntity(newSupplier)
.properties(OProperties.string("supplierName", "Carl A"))
.execute();
report("newSupplier name after update: "+ consumer.getEntity("Supplier", "S200").execute().getProperty("supplierName").getValue());
// update the newly create product using mergeconsumer.mergeEntity("Supplier", "S101")
.properties(OProperties.string("supplierName", "Zack A"))
.execute();
report("newPart rating after merge: "+ consumer.getEntity("Supplier", "S101").execute().getProperty("supplierName").getValue());
// clean up, delete the new productconsumer.deleteEntity("Supplier", "S200").execute();
Batch Operations
Odata supports executing multiple operations sent in a single HTTP request through the use of Batching
The batch requests can be sent as POST with the path containing $batch
OData Batch Request is represented as a Multipart MIME v1.0 message
The OData4j implementation is inefficient in the sense that it executes the individual batch items in a separate transaction
Questions?
References
JAX-RS 2.0 http://jersey.java.net/nonav/documentation/
snapshot/index.html http://bitworking.org/news/193/Do-we-need
-WADL http://www2008.org/papers/pdf/p805-pauta
ssoA.pdf http://docs.oracle.com/javaee/6/tutorial/doc
/giepu.html OData
http://www.odata.org/documentation/IndexV2
http://code.google.com/p/odata4j/