RESTful API Support - Plain JAX-RS Services
1. Introduction
HST-2 supports Plain JAX-RS Components integration. So developers can easily develop JAX-RS components for their own RESTful APIs and make use of full HST-2 content retrieval/management features in their JAX-RS components.
In order to use plain JAX-RS Services, you need to configure mount(s) in the repository configuration to use the JaxrsPlainRestPipeline, as well as enable that pipeline in the overriding Spring configurations.
2. How to enable a Plain RESTful Mount
To enable a Plain RESTful JAX-RS Services endpoint, you should configure a mount for that purpose first.
For example, you can configure a " restservices" mount like the following:
<sv:node sv:name="restservices">
  <sv:property sv:name="jcr:primaryType" sv:type="Name">
    <sv:value>hst:mount</sv:value>
  </sv:property>
  <sv:property sv:name="hst:alias" sv:type="String">
    <sv:value>restservices</sv:value>
  </sv:property>
  <sv:property sv:name="hst:ismapped" sv:type="Boolean">
    <sv:value>false</sv:value>
  </sv:property>
  <sv:property sv:name="hst:namedpipeline" sv:type="String">
    <sv:value>JaxrsRestPlainPipeline</sv:value>
  </sv:property>
  <sv:property sv:multiple="true" sv:name="hst:types" sv:type="String">
    <sv:value>rest</sv:value>
  </sv:property>
</sv:node>
In the above example we configured a /restservices mount to enable Plain JAX-RS RESTful services endpoint. The mount is processed via the JaxrsRestPlainPipeline which is provided by default by the HST-2 Container for the Plain RESTful services.
3. How to develop and configure Plain JAX-RS Components
Plain JAX-RS Components are just standard based JAX-RS Components. So, you can follow the best practices for building JAX-RS Components.
First, your JAX-RS resource component should be mapped by a path. In the example below, it is mapped to the " /products/" path.
package org.hippoecm.hst.demo.jaxrs.services;
@Path("/products/")
public class ProductPlainResource 
          extends org.hippoecm.hst.jaxrs.services.AbstractResource {
    @GET
    @Path("/{productType}/")
    public List<ProductRepresentation> getProductResources(
            @Context HttpServletRequest servletRequest,
            @Context HttpServletResponse servletResponse,
            @Context UriInfo uriInfo,
            @PathParam("productType") String productType) {
        // do nothing for now...
        return null;
    }
}   
The JaxrsRestPlainPipeline will select a target JAX-RS services endpoint through the configured mount path.
For example, when you navigate to http://localhost:8080/site/restservices/products/bike/, HST-2 Container will resolve the request to the " restservices" mount endpoint and its JaxrsRestPlainPipeline will delegate the discovery and invocation of the ProductPlainResource component to the JAX-RS engine by the remainder of the path, " /products/bike/", which will resolve " bike" as a path parameter named ' productType'. The JAX-RS engine then will invoke #getProductResources() method because the path is best matched with that method.
In order to register the JAX-RS resource component above, you must add the bean definition to the sourceList of customRestPlainResourceProviders like in the following example:
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
  <!-- The following three imports will include pipeline configurations for
       both JaxrsRestPlainPipeline and JaxrsRestContentPipeline !!! -->
  <import resource="classpath:/org/hippoecm/hst/site/optional/jaxrs/
                    SpringComponentManager-rest-jackson.xml" />
  <import resource="classpath:/org/hippoecm/hst/site/optional/jaxrs/
                    SpringComponentManager-rest-plain-pipeline.xml" />
  <import resource="classpath:/org/hippoecm/hst/site/optional/jaxrs/
                    SpringComponentManager-rest-content-pipeline.xml" />
  <!-- Your custom JAX-RS REST Plain Resource Providers will be added into
       the following list !!! -->
  <bean id="customRestPlainResourceProviders"
        class="org.springframework.beans.factory.config.ListFactoryBean">
    <property name="sourceList">
      <list>
        <!-- Wrap your JAX-RS component by SingletonResourceProvider. -->
        <bean class=
             "org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider">
          <constructor-arg>
            <bean class=
             "org.hippoecm.hst.demo.jaxrs.services.ProductPlainResource" />
          </constructor-arg>
        </bean>
      </list>
    </property>
  </bean>
  <!-- Your custom JAX-RS REST Resource Providers will be added into the
       following list !!! -->
  <!-- The following sourceList is not used for Plain JAX-RS Services,
       but used for Content/Context Aware JAX-RS Services. -->
  <bean id="customRestContentResourceProviders"
        class="org.springframework.beans.factory.config.ListFactoryBean">
    <property name="sourceList">
      <list>
      </list>
    </property>
  </bean>
</beans>
You can configure and register more custom JAX-RS components when necessary.
4. Detailed Example
The above example JAX-RS component can be further implemented like in the following example:
package org.hippoecm.hst.demo.jaxrs.services;
@Path("/products/")
public class ProductPlainResource 
       extends org.hippoecm.hst.jaxrs.services.AbstractResource {
    @GET
    @Path("/{productType}/")
    public List<ProductRepresentation> getProductResources(
            @Context HttpServletRequest servletRequest,
            @Context HttpServletResponse servletResponse,
            @Context UriInfo uriInfo,
            @PathParam("productType") String productType) {
        List<ProductRepresentation> products =
            new ArrayList<ProductRepresentation>();
        try {
            HstRequestContext requestContext = RequestContextProvider.get();
            HstQueryManager hstQueryManager =
                getHstQueryManager(requestContext.getSession(),
                                requestContext);
            String mountContentPath =
                requestContext.getResolvedMount().getMount()
                                                    .getContentPath();
            Node mountContentNode =
                requestContext.getSession().getRootNode()
                  .getNode(PathUtils.normalizePath(mountContentPath));
            HstQuery hstQuery =
                hstQueryManager.createQuery(mountContentNode,
                                            ProductBean.class);
            Filter filter = hstQuery.createFilter();
            filter.addEqualTo("demosite:product", productType);
            hstQuery.setFilter(filter);
            hstQuery.addOrderByDescending("demosite:price");
            hstQuery.setLimit(10);
            HstQueryResult result = hstQuery.execute();
            HippoBeanIterator iterator = result.getHippoBeans();
            while (iterator.hasNext()) {
                ProductBean productBean =
                    (ProductBean) iterator.nextHippoBean();
                if (productBean != null) {
                    ProductRepresentation productRep =
                        new ProductRepresentation().represent(productBean);
                    productRep.addLink(getNodeLink(requestContext,
                                       productBean));
                    productRep.addLink(getSiteLink(requestContext,
                                                   productBean));
                    products.add(productRep);
                }
            }
        } catch (Exception e) {
            throw new WebApplicationException(e);
        }
        return products;
    }
}
In a client-side HTML page or script you now can invoke the resource service URL. Here's a simple HTML link example invoking the resource service:
<p>  Product :
  <a href=
        '<hst:link path="/restservices/products/${document.product}/" />'
     target='_blank'
     title=
        'Click the left link to see all products of the same product
         type in XML generated by a Plain JAX-RS Service.'>
     ${document.product}</a>
</p>
Unlike Content/Context Aware JAX-RS Services, when using Plain JAX-RS Services, you will need to know how the URL should be like. In the example above, it used <hst:link/> tag with predefined URL paths.
5. Using Matrix Parameters
Plain JAX-RS Services can use matrix parameters by using @MatrixParam annotations.
However, please note that the current JAX-RS runtime library, Apache CXF, adopted by HST-2, does not support matrix parameters in multi path segments.
For example, if your RESTful URL is " http://localhost:8080/site/restservices/a/b" and you need to use two matrix parameters, " p1" and " p2", in your JAX-RS service, you should use URLs ending like " http://localhost:8080/site/restservices/a/b;p1=1;p2=2". If you spread the matrix parameters into multiple path segments like " http://localhost:8080/site/restservices/a;p1=1/b;p2=2", then Apache CXF runtime will fail to match your JAX-RS service. In other words, Apache CXF will fail to find your JAX-RS service or operation with " /a/b" any more.
6. Summary
- 
 
HST-2 supports normal standard based JAX-RS Components.
 - 
 
You can take advantage of HST Content Beans to retrieve/manage JCR contents in your Plain JAX-RS Components.
 - 
 
Unlike with Content/Context Aware JAX-RS Components, you will need to know the URL patterns on each resource service in order to access them.