С экспоненциальным ростом Интернета, REST как архитектурный стиль [REF-1] нашел свою нишу в ландшафте современных сервисов, и его популярность будет расти и дальше. JAX-RS — это новая спецификация JCP [REF-2], которая предоставляет Java API для Web-сервисов RESTful по протоколу HTTP. JAX-RS использует аннотации к POJO (простые старые объекты Java) для отображения в архитектурный стиль представления RESTful и облегчает поиск распределенных корпоративных ресурсов через унифицированные идентификаторы ресурсов (URI). В этой статье я демонстрирую сервисно-ориентированную архитектуру RESTful, созданную для упаковки схожих функциональных возможностей, подробно описанных в [REF-3], чтобы позволить клиентскому приложению визуализировать форму Adobe и обрабатывать отправленные формы, абстрагированные в фабричные объекты Adobe Form Server Module (FSM). Следствие реализаций Service Endpoint в JAX-WS,здесь мы имеем аннотированные классы веб-ресурсов JAX-RS (термин RESTful для сервиса), создаваемые для каждого HTTP-запроса, который инкапсулирует функциональность сервиса, и провайдеры, которые преобразуют параметры ресурса и результирующий контент в представления времени выполнения в различных типах мультимедиа.Эта статья написана Ризваном Ахмедом и опубликовано в журнале SOA Magazine в августе 2009 года.
Введение
В предыдущей статье [REF-3] я описал решение для простого фасада службы JAX-WS для функциональности Adobe LiveCycle Forms, которое можно вызывать из любого внешнего приложения. Цель этого состояла в том, чтобы скрыть детали того, как рендеринг и обработка форм происходит в реализации сервиса, и все клиенты (включая различные корпоративные приложения), которым необходим доступ к функциональности, могут легко искать и использовать предоставленные сервисы через опубликованные контракты ( Определения WSDL).
Хотя подходы к реализации WS- * SOAP и RESTful представляют разные архитектурные стили, они в основном схожи, поскольку обе они облегчают интеграцию на уровне приложений, поскольку две системы взаимодействуют друг с другом с использованием согласованных пространств имен, протоколов и форматов. Корни различий между двумя технологиями (часто обсуждаемыми в сообществе разработчиков SOA) связаны с тем, что при использовании SOAP вы подключаете сервисы, определяя уровень абстракции над семантикой метода и моделью адресации. В REST сам Интернет функционирует как своего рода «шина интеграции» с небольшим количеством глобально понятных методов («глаголов»), протоколов и общей схемы адресации с использованием URI. Помимо этого,Стоит отметить, что полезные нагрузки сообщений в реализациях служб SOAP и RESTful могут быть одним и тем же XML-документом с маршалингом времени выполнения (un), делегированным соответствующей инфраструктуре и механизму провайдера (JAXB является наиболее распространенным).
Несмотря на то, что большинство поставщиков программного обеспечения предпочитают SOAP, REST и SOAP являются взаимодополняющими технологиями и могут работать в тандеме, как демонстрирует этот пример архитектуры, в которой мы используем ресурс RESTful для инкапсуляции оболочки в конечную точку на основе SOAP (веб-служба Axis FSM). Есть, конечно, варианты использования, которые поддерживают предпочтение одного над другим, но хороший практик SOA должен сделать это определение, взвешивая другие внешние факторы.
Пример с открытым исходным кодом
RESTEasy [REF-4] — это переносимая эталонная реализация спецификации JAX-RS с открытым исходным кодом, реализованная в виде ServletContextListener и сервлета, развернутого в архиве веб-приложений (WAR) и, следовательно, может работать в любом контейнере сервлета (хотя более тесная интеграция с сервер приложений JBoss облегчает работу разработчика в этой среде). Слушатель ResteasyBootstrap отвечает за инициализацию некоторых базовых компонентов RESTEasy, а также за сканирование аннотированных классов в вашем развернутом файле JAR. Сервлет HttpServletDispatcher служит в качестве контроллера для всех HTTP-запросов, отправляемых через инфраструктуру RESTEasy, направляя его на соответствующий веб-ресурс.
Пользовательское приложение JAX-RS состоит из одного или нескольких веб-ресурсов и нуля или нескольких провайдеров (ресурсы и провайдеры подробно описаны в последующих разделах) и представляет собой совокупность всех компонентов приложения, которые составляют архитектуру решения RESTful. Хотя существуют альтернативные механизмы, такие как сканирование классов во время выполнения для поиска классов ресурсов и провайдеров, реализация стандартного класса JAX-RS javax.ws.rs.core.Application для регистрации в среде выполнения RESTEasy списка всех ресурсов JAX-RS, провайдеров и исключения карт для вашего пользовательского приложения, является единственным переносимым средством конфигурации. Реализация класса Application показана в примере 1. По умолчанию один экземпляр класса Provider создается для каждого приложения JAX-RS и доступен во время выполнения. В противоположность,новый экземпляр класса ресурса создается для каждого запроса к этому ресурсу.
Пример 1 :
public class SCRSJAXRSApplication extends Application
{
HashSet<Object> singletons = new HashSet<Object>();
public SCRSJAXRSApplication()
{
singletons.add(new FormClientDemographicsResource()); // JAX-RS Resource
singletons.add(new FormGenericSubmitResource()); // JAX-RS Resource
singletons.add(new FormRestEasyExceptionMapper()); // JAX-RS Exception-Mapper Provider
singletons.add(new FormExceptionWriter()); // JAX-RS MessageBodyWriter<T> Provider
}
@Override
public Set<Class<?>> getClasses()
{
HashSet<Class<?>> set = new HashSet<Class<?>>();
return set;
}
@Override
public Set<Object> getSingletons()
{
return singletons;
}
}
JAX-RS Providers
Provider, an essential component of the JAX-RS runtime, is an implementation of the JAX-RS extension interface and provides the means to marshall and unmarshall many different message bodies and formats. For example, media types such as application/xml, application/json, application/fastinfoset, application/atom can be transformed into their respective Java representations via RESTEasy implemented JAXB providers. Similarly, a media type of application/x-www-form-urlencoded, typically consisting of field data posted from an HTML form, is unmarshalled to a MultiValuedMap prior to being sent to the resource. RESTEasy will select a different Provider based on the return type or parameter type used to define the resource.
The JAX-RS specification also allows you to define your application specific custom media type and plug in your own Provider implementation to perform application specific content (un)marshalling. You create implementations of the javax.ws.rs.ext.MessageBodyWriter and MessageBodyReader respectively annotated with @Provider. At runtime, the return media type of the Web resource method is matched up to the @Produces annotated media type on the Writer (likewise, the resource parameter to the @Consumes type on the Reader) and the type of the requested/returned instance (represented as ) is used to select the correct entity provider implementation. RESTEasy can be configured via a context parameter switch to automatically scan its WEB-INF/lib or classes directories for classes annotated with @Provider, or alternatively, you may register the same within an implementation of javax.ws.rs.core. Application as in Example 1.
JAX-RS Resource
A JAX-RS Resource is the server side implementation of the business functionality that you would want to be wrappered as a Web service and can be as simple as a POJO annotated with @Path (javax.ws.rs.Path), the value attribute of which will indicate the path at which the resource will be available. The POJO would also contain various business methods annotated with one of the HTTP methods (@GET, @PUT, @POST, @DELETE). These annotations indicate what business method should be invoked when the resource receives a request using that particular HTTP method or verb. The @Consumes annotation on the Resource class or method level would indicate the type that the particular resource or resource method expects as a request entity and the @Produces would be used to indicate the media type you want to return on the response.
Creating Contract-First Resources
While one could take a code-first approach to building a RESTful resource, my personal preference is to build services contract-first and present the ideal interface to the calling clients. Since there is no WSDL contract to create in REST you can start off from an XML schema representation of the expected parameters and desired result. The implication here is that your Web service will be working with the application/xml media type. This approach is advantageous as it facilitates JAXB schema compiler (XJC) generation of annotated value classes and ObjectFactory [REF-5] for use with the appropriate RESTEasy JAXB Provider to unmarshall the request and marshall the reponse. Example 2 shows a schema representation of the input parameters required for the Resource.
Example 2:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema targetNamespace='http://scrs.forms.resteasy.service/'
version='1.0'
xmlns:ns1='http://scrs.forms.resteasy.service/'
xmlns:tns='http://scrs.forms.resteasy.service/'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:jxb='http://java.sun.com/xml/ns/jaxb'
jxb:version='2.0'>
<xsd:import namespace='http://scrs.forms.resteasy.service'/>
<xsd:element name='callRenderForm'
type='tns:FormClientDemographicsInputType'/>
<xsd:complexType name='FormClientDemographicsInputType'>
<xsd:sequence>
<xsd:element minOccurs='0' name='contentURL' type='tns:contentURL'/>
<xsd:element minOccurs='0' name='inputSSN' type='xsd:string'/>
<xsd:element name='maskSSN' type='xsd:boolean'/>
<xsd:element minOccurs='0' name='formNum' type='xsd:string'/>
<xsd:element minOccurs='0' name='userAgent' type='xsd:string'/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name='contentURL'>
<xsd:sequence>
<xsd:element minOccurs='0' name='scheme' type='xsd:string'/>
<xsd:element minOccurs='0' name='serverName' type='xsd:string'/>
<xsd:element minOccurs='0' name='serverPort' type='xsd:string'/>
<xsd:element minOccurs='0' name='contextPath' type='xsd:string'/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
Value classes for the input schema generated by the XJC will contain an @XmlType annotation to map Properties and Fields on that class to the schema defined complex type with the propOrder element determining the sequence order of the XML elements. The runtime framework will select the RESTEasyJAXBXmlTypeProvider when the value class is annotated with an @XmlType annotation. This provider attempts to locate the XJC generated ObjectFactory class (please refer to Example 3) which contains the factory methods to programmatically construct a new instance of the Java representation for the XML content which is then returned wrapped within a JAXBElement instance.
Example 3:
@XmlRegistry
public class ObjectFactory {
private final static QName _CallRenderForm_QNAME = new QName("http://scrs.forms.resteasy.service/", "callRenderForm");
/**
* Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: scrs.forms.service.resteasy.parameters.formrender.input
*
*/
public ObjectFactory() {
}
/**
* Create an instance of FormClientDemographicsInputType
*
*/
public FormClientDemographicsInputType createFormClientDemographicsInputType() {
return new FormClientDemographicsInputType();
}
/**
* Create an instance of ContentURL
*
*/
public ContentURL createContentURL() {
return new ContentURL();
}
/**
* Create an instance of JAXBElement< FormClientDemographicsInputType>
*
*/
@XmlElementDecl(namespace = "http://scrs.forms.resteasy.service/", name = "callRenderForm")
public JAXBElement createCallRenderForm(FormClientDemographicsInputType value) {
return new JAXBElement(_CallRenderForm_QNAME, FormClientDemographicsInputType.class, null, value);
} }
Alternatively, if using a code-first approach, you may hand code your JAXB value classes and annotate them with the @XmlRootEntity in which case the JAXBXmlRootElementProvider is selected for handling the basic marshalling and unmarshalling of the JAXB entities.
Please refer to Example 4 for a Web resource that returns the pre-populated form design (passed as a parameter value in the FormClientDemographicsInputType object). The implementation details of how the form is rendered, via invoking the Adobe FSM Client API renderForm() discussed in-depth in the previous article [REF-3], is encapsulated within the resource which simply returns the FormClientDemographicsOutputType object containing the rendered form’s HTML content as a String or PDF content as a binary byte array. The resource path follows the RESTEasy servlet path mapping defined in its web.xml, so you will be able to reach an instance of this class at ://formsRS/renderForm.
By default, a new instance of the resource class is created for each request to that resource with all requested dependencies being injected at runtime. By using the @POST annotation, you indicate that the callRenderForm method is the one you need to respond to HTTP POST requests. The callRenderForm method also both expects and produces an XML entity as indicated by the @Consumes and @Produces annotations. The RESTEasy runtime matches up the MIME type in the request and response to the appropriate Provider class (in our case JAXBXmlTypeProvider for the FormClientDemographicsInputType and FormClientDemographicsOutputType entities) to perform the transformation of XML to object representations and vice versa.
Example 4:
@Path("formsRS")
public class FormClientDemographicsResource
{
@POST
@Path("/renderForm")
@RolesAllowed("friend")
@Produces("application/xml")
@Consumes("application/xml")
public FormClientDemographicsOutputType callRenderForm(FormClientDemographicsInputType inputObj) throws FormRestEasyException
{
try{
// Implementation of the Adobe FSM renderForm() specific logic as detailed in [REF-3]
...
} catch (Exception ex) {
throw new FormRestEasyException(..);
}
}
Exception Handling
As with any remote Web service, you would want your RESTful resource to throw exceptions under certain conditions and deal with them appropriately at the client. The simplest way is to create a response with the HTTP error code you want to set, encapsulate it into an instance of a runtime javax.ws.rs.WebApplicationException and then have it thrown from the RESTful business method [REF-6]. This class suffers from the primary downside in that it does not allow you to set your own custom error mapping elements. Ideally, you would like to create your own application specific class encapsulating the error message, error code, category and stack trace array of the primary exception cause at the resource end (described as FormRestEasyException in Example 5).
JAX-RS allows for the ExceptionMapper interface which can be implemented in custom, application provided components that can catch thrown application exceptions and write specific HTTP responses. You annotate the mapper implementation with @Provider and register it (refer to Example 1) so that the RESTEasy runtime can pick it up. When a resource throws an exception that the runtime has a mapping for, it uses the mapped exception provider class to generate an instance of javax.ws.rs.core.Response, consisting of a HTTP error status code (typically 500) and an entity body upon which you can piggy back details of the specific exception, FormRestEasyException as in our case (an example is shown in Example 6). Conversion between the Java object into the entity body then becomes the responsibility of the entity Provider. The exception class could be marshalled by the RESTEasy built-in default JAXB Provider framework if the class was annotated with binding specific @XmlType or @XmlRootElement annotations.
As an academic exercise, for the sole purpose of demonstration, I have chosen not to take this route instead relying on a custom MessageBodyWriter Provider implementation which the runtime will invoke to marshall an instance of the FormRestEasyException entity (please refer to Example 7). The response is processed at the client end as if the method in your resource that threw the checked or runtime exception had returned it.
Example 5:
public class FormRestEasyException extends Exception
{
private int errorCode;
private String errorCategory;
private String[] stackTraceArr;
public FormRestEasyException(String errorCategory, int errorCode, String message, String[] stackTraceArr)
{
super(message);
this.errorCategory = errorCategory;
this.errorCode = errorCode;
this.stackTraceArr = stackTraceArr;
}
// getters and setters
}
Example 6:
@Provider
public class FormRestEasyExceptionMapper implements ExceptionMapper
{
public Response toResponse(FormRestEasyException formRestEasyException)
{
return Response.status(500)
.entity(formRestEasyException)
.build();
}
}
Example 7 :
@Produces("application/xml")
@Provider
public class FormExceptionWriter implements MessageBodyWriter<FormRestEasyException> {
public boolean isWriteable(Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return FormRestEasyException.class.isAssignableFrom(type);
}
public void writeTo(FormRestEasyException formRestEasyException, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> headers,
OutputStream out) throws IOException {
out.write("<ns1:exception xmlns:ns1='http://scrs.forms.resteasy.service/'>".getBytes());
out.write(“<error-code>”.getBytes());
out.write(formRestEasyException.getErrorCode().getBytes());
out.write(“</error-code>”.getBytes());
out.write(“<error-message>”.getBytes());
out.write(formRestEasyException.getMessage().getBytes());
out.write(“</error-message>”.getBytes());
...
out.write("</ns1:exception>".getBytes());
}
public long getSize(FormRestEasyException formRestEasyException,
java.lang.Class<?> type,
java.lang.reflect.Type genericType,
java.lang.annotation.Annotation[] annotations,
MediaType mediaType) {
return -1;
}
}
An alternate, albeit much simpler, approach to exceptions handling would involve creating a complex type for the application specific exception elements and embedding that as an element within the schema representing the output FormClientDemographicsOutputType object that is sent back from the RESTful resource. No custom Exception Mappers need to be defined here as the exception is simply sent back as part of the return result object.
Security Considerations
The option we have for authentication and authorization of HTTP requests routed to a RESTful resource is via configuring the appropriate security related elements in the deployment descriptor web.xml of the RESTEasy Web application. You need to first add a standard security constraint element to the web.xml defining the Web resource collection, that is, the HTML files, servlets, URL patterns and HTTP methods that must be protected from public access. A user must have the proper authorization to access resources identified and secured under the Web resource collection. Therefore, you define an authorization constraint element which identifies the role (assignable to the user) that is allowed access to the Web resource collection. Please refer to the relevant snippet of the RESTEasy web.xml in Example 8.
Example 8:
<security-constraint>
<web-resource-collection>
<web-resource-name>Resteasy</web-resource-name>
<description>An example security config that only allows users with the
role ‘friend’ to access the RESTEasy web application
</description>
<url-pattern>/formsRS</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>friend</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>resteasy</realm-name>
</login-config>
<security-role>
<role-name>friend</role-name>
</security-role>
A security realm for RESTEasy is then defined by creating a new descriptor jboss-web.xml containing a element referencing the security context defined in login-config.xml and using the UserRolesLoginModule with user/password and user/role combination property files. The client can use HTTP Basic authentication and pass in user credentials in the “Authorization” header of the HTTP request. At the resource end the @RolesAllowed specifies the role(s) allowable access to the Resource methods by performing a runtime injection of HttpServletRequest.isUserInRole(rolename). If one of the @RolesAllowed passes, then the request is allowed, otherwise a response is sent back with a 401(Unauthorized) response code.
Additionally, you may use SSL technology to provide all clients needing access to the JAX-RS forms resource the ability to communicate securely with an encrypted session. The URL address needs to use a secure protocol HTTPS which utilizes port 443 by default and the connector to that port needs to be enabled to point to the keystore containing the SSL digital certificate.
Developing RESTful Clients for SOA
RESTEasy has a client proxy framework that allows you to use JAX-RS annotations to invoke on a remote HTTP resource. You need to create a Java class proxy that is a mirror interface of the resource class. You will next need to programmatically create an instance of this client class from a org.resteasy.plugins.client. httpclient.ProxyFactory instance which builds an HTTP request that it uses to invoke the remote RESTful Web service. While this is certainly an elegant way to create RESTful clients, I did not take this approach as it would have necessitated that we bundle the RESTEasy library JARs with the calling applications. Since all the resource class expects is POX (Plain Old XML) over HTTP there are other simpler ways to construct it without the RESTEasy client framework.
Having taken a contract-first approach at constructing the server resource, it was decided to take a similar approach to develop the client side components. Since the ideal «contract» (this word is a misnomer as RESTful implementations do not work off WSDL documents) was already available in the form of XML schemas which defined the resource input and output entity structures, it was deemed straightforward to simply generate value classes using XJC (the JAXB schema compiler) containing client side bindings and JAXB representations of the types defined in the schema. Usually hidden in the midst of the generated classes is the ObjectFactory class which provides an easy way to construct Java representations of XML content [REF-5] (also refer back to Example 3). A simple approach for marshalling the XML payload that needs to be sent to the Web resource would use the schema-derived classes, the ObjectFactory, a JAXBContext object and the call to marshall the content on the OutputStream (refer to Example 9).
Similarly, unmarshalling an XML document, typically the response from the JAX-RS Web resource, consists of creating a JAXBContext object and the call to unmarshall the document (refer to Example 10). The JAXBContext object provides the entry point to the JAXB API and maintains the binding information between XML and Java. One way of creating a context instance is by calling the static method newInstance with the package name containing the JAXB schema-derived classes. From this context, an Unmarshaller or Marshaller object is obtained, which functions as the driver for processing XML to create the equivalent set of Java objects and vice versa.
To simplify portability across various systems that need to use the same client side functionality you would typically package the generated client artifacts (JAXB schema-derived classes, marshaller and unmarshaller utilities) into a separate java application archive (in our case called FormsRSClient.jar) and simply include the file into the classpath of the calling system module.
Lastly, the client calling system or application module’s servlet or action class needs to create a URL that points to the JAX-RS server resource and open a java.net.HttpUrlConnection to that location (please refer to the code segment in Example 9). The HTTP protocol has built in content negotiation headers that allow the client and server to specify what content they are transferring and what content they would prefer to get. We saw earlier how the JAX-RS server resource declares content preferences via the @Produces and @Consumes headers. Based upon the “Content-Type” header sent by the HTTP client, the JAX-RS runtime at the server end would then match up to the correct resource method (annotated with @Consumes) and select the appropriate Provider to unmarshall the request. Likewise, the “Accept” header would be matched up with the method annotated with @Produces and the appropriate Provider would marshall the response. Likewise, authentication credentials from the client application would need to sent in the “Authorization” header which would include the Base64 encoded value of the “user-name:password” string.
Example 9 :
public class FormRenderClientInput {
private ObjectFactory of;
private FormClientDemographicsInputType formClientDemographicsInputType;
private ContentURL contentURL;
public FormRenderInput() {
of = new ObjectFactory();
formClientDemographicsInputType = of.createFormClientDemographicsInputType();
contentURL = of.createContentURL();
}
public void makeContentURL( String scheme, String serverName, String serverPort, String contextPath ) {
contentURL.setScheme(scheme);
contentURL.setServerName(serverName);
contentURL.setServerPort(serverPort);
contentURL.setContextPath(contextPath);
}
public void make( String inputSSN, boolean maskSSN, String formNum, String userAgent ) {
formClientDemographicsInputType.setContentURL(contentURL);
formClientDemographicsInputType.setInputSSN(inputSSN);
formClientDemographicsInputType.setMaskSSN(maskSSN);
formClientDemographicsInputType.setFormNum(formNum);
formClientDemographicsInputType.setUserAgent(userAgent);
}
public void marshal(OutputStream out) {
try {
JAXBElement jel = of.createCallRenderForm(formClientDemographicsInputType);
JAXBContext jc = JAXBContext.newInstance( "scrs.forms.client.resteasy.parameters.formrender.input" );
Marshaller m = jc.createMarshaller();
m.marshal( jel, out );
} catch( JAXBException jbe )
{
jbe.printStackTrace();
}
}
}
Example 10:
public class FormRenderClientOutput {
public FormClientDemographicsOutputType unmarshal( InputStream inputStream ) throws JAXBException {
JAXBContext jc = JAXBContext.newInstance( "scrs.forms.client.resteasy.parameters.formrender.output" );
Unmarshaller u = jc.createUnmarshaller();
JAXBElement<FormClientDemographicsOutputType> doc = (JAXBElement<FormClientDemographicsOutputType>)u.unmarshal( inputStream );
return doc.getValue();
}
}
Example 11:
public class FormRestEasyGetAction extends Action {
...
URL postURL = new URL("https://<machine>:<port>/<RESTEasy servlet mapping>/formsRS/renderForm");
HttpURLConnection connection = (HttpURLConnection) postURL.openConnection();
connection.setDoOutput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/xml");
connection.setRequestProperty("Accept", "application/xml");
String authorization = “<user-name>:<password>";
String encodedAuthorization= new String(Base64.encodeBase64(authorization.getBytes()));
connection.setRequestProperty("Authorization", "Basic " + encodedAuthorization);
OutputStream os = connection.getOutputStream();
FormRenderInput formInput = new FormRenderInput();
formInput.makeContentURL(request.getScheme(), request.getServerName(), request.getServerPort()+"", request.getContextPath());
formInput.make(inputSSN, maskSSN, sFormQuery, request.getHeader("User-Agent"));
formInput.marshal(os);
FormRenderOutput formOutput = new FormRenderOutput();
try {
formClientDemographicsOutputType = formOutput.unmarshal(connection.getInputStream());
} catch (Exception ex) {
throw new IOException(ex.getMessage());
}
formContent = formClientDemographicsOutputType.getFormContent();
...
}
Sequence Diagrams
Finally, Figures 1 and 2 illustrate the sequence diagrams of the RESTful solution architecture created for integrating our external systems with Adobe LiveCycle Forms (for further details about the existing applications landscape please refer to [REF-3] ).
Figure 1: RESTful Implementation for Rendering Adobe LiveCycle Forms (View Larger Figure)
Figure 2: RESTful Implementation for Processing Form Submissions (View Larger Figure)
Conclusion
The sheer variety of Web based devices and tools, pretty much anything that can access and be accessed from the Web (via its common addressing scheme for identification of resources using URIs) has resulted in HTTP increasingly becoming a popular application protocol of choice. The availability of the new JAX-RS specification and reference frameworks (JSR 311 implemented by RESTEasy) has made implementing RESTful architectures convenient and developer-friendly. RESTEasy standardizes the use of annotations to define Web resources which can have multiple runtime representation in a variety of different media types with additional convenience features such as support for mapping Exceptions, enforcing security and an easy to use client API. All transformations and infrastructure plumbing to read/write resource content are facilitated by RESTEasy supplied default and a JAX-RS supported extensible Provider mechanism.
References
[REF-1] «Architectural Styles and the Design of Network-based Software Architectures» by Roy Thomas Fielding, Doctoral dissertation, University of California, Irvine, http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
[REF-2] «JAX-RS: Java API for RESTful Web Services», Java.net, https://jsr311.dev.java.net/drafts/spec20090313.pdf
[REF-3] «An SOA Case Study: Integrating Adobe LiveCycle Forms using JBossWS» by Rizwan Ahmed, SOA Magazine July 2009, http://www.soamag.com/I30/0709-3.asp
[REF-4] «RESTEasy User Documentation», JBoss.org, http://jboss.org/resteasy/docs.html
[REF-5] «Unofficial JAXB User Guide», Java.net, https://jaxb.dev.java.net/guide/
[REF-6] «Java SOA Cookbook» by Eben Hewitt, O’Reilly Media Inc., http://oreilly.com/catalog/9780596520724/
This article was originally published in The SOA Magazine (www.soamag.com), a publication officially associated with «The Prentice Hall Service-Oriented Computing Series from Thomas Erl» (www.soabooks.com). Copyright ©SOA Systems Inc. (www.soasystems.com)