RESTful JAX-RS Component Support
On this page
Introduction
Goal
Create custom JAX-RS-based RESTful web services in Bloomreach Experience Manager's delivery tier.
Background
In addition to the generic Content REST API, Bloomreach Experience Manager's delivery tier (a.k.a. HST) provides built-in support for JAX-RS to expose content over custom RESTful web services. Two types of services are supported:
- Plain JAX-RS services are used to expose preconfigured functionality within a site, not directly mapped to content, but can make use of it.
- Context-aware JAX-RS services are used to dynamically expose site content mapped on content type.
Both context-aware and plain JAX-RS services are provided through the HST with full access to its API.
The Essentials setup application provides a REST Services Setup tool which enables easy setup of plain JAX-RS services.
Information on implementing the custom services can be found on this page and the dedicated pages about plain and context-aware services.
How to Enable JAX-RS Services Support
If you used the Bloomreach Experience Manager Maven archetype to bootstrap your project then support for JAX-RS services is already enabled and you can skip this paragraph.
Otherwise JAX-RS support can be added to any Bloomreach Experience Manager project as follows:
-
Add the following dependencies to your site/components module's pom.xml:
- Add the following Spring configuration file to your site/components module as /META-INF/hst-assembly/overrides/custom-jaxrs-resources.xml:
In the configuration above, the three imports should be added first to use either the JaxrsRestPlainPipeline or the JaxrsRestContentPipeline.
Your custom Plain RESTful JAX-RS components will be added into the "sourceList" of "customRestPlainResourceProviders", which is merged and used by the JaxrsRestPlainPipeline later.
Your custom Content/Context-Aware RESTful JAX-RS components will be added into the "sourceList" of "customRestContentResourceProviders", which is merged and used by the JaxrsRestContentPipeline later.
NOTE: Spring Framework Beans assembly configuration under classpath:/META-INF/hst-assembly/overrides/*.xml resources will be automatically read and merged if you do not explicitly set the property assembly.overrides to an empty string in /WEB-INF/hst-config.properties.
Using XML or JSON Payloads
HST-2 uses Apache CXF as the JAX-RS runtime engine. Apache CXF JAX-RS can consume and produce XML or JSON formatted payloads automatically even though the JAX-RS Resource Beans do not specify the format. By default, Apache CXF JAX-RS will read "Accept" HTTP Request header to detect the most proper payload format first. For example, if "Accept" header value from the client is "text/xml" or "application/xml", then the runtime will decide to use XML format by default. If "Accept" header value is "application/json", then the runtime will decide to use JSON format.
In addition, Apache CXF JAX-RS supports a special request parameter "_type". For example, if the request contains a request parameter like " ?_type=xml" or " ...&_type=xml", then the runtime will decide to use XML format by default. If the request contains a request parameter like " ?_type=json" or " ...&_type=json", then the runtime will use JSON format.
How to customize the "_type" parameter name
HST-2 provides customization support for the default Apache CXF JAX-RS request parameter, " _type".
In order to customize this default request parameter, you need to add the following Spring Beans configuration fragments into your overriding spring assembly XML file(s):
In the example above, the bean, " jaxrsRestPlainServiceQueryStringReplacingInterceptor", is for the default Plain JAX-RS Service Pipeline, and the bean, " jaxrsRestContentServiceQueryStringReplacingInterceptor", is for the default Content/Context-Aware JAX-RS Service Pipeline.
In any of those interceptor beans, you can configure " paramNameReplaces" property by parameter name replacement pairs. So, in the example above, if a request parameter named '_format' is provided, the parameter name will be replaced by '_type', which is known to the Apache CXF JAX-RS runtime as a special system parameter name. For example, if your request contains " ?_format=json" or " ...&_format=json", then it will be equivalent to " ?_type=json" or " ...&_type=json" with the configuration example above.
In this way, you can use a different parameter name for the Apache CXF JAX-RS internal "_type" system parameter name.
How to force to use JSON or XML format by default
If you want to use only one format either JSON or XML by default in your system without considering "Accept" HTTP Request header, then you can configure the " additionalQueryString" property value by " _type=json" or " _type=xml".
In the example Spring configuration fragment above (see 3.1), the " additionalQueryString" property value is an empty string by default. But if you set it to " _type=json" like the commented block for instance, then HST-2 Container will append the configured query parameter(s) string into the request message forcefully. So, even though the client prefers XML format by Accept header (e.g., "Accept: text/xml"), Apache CXF JAX-RS runtime will use JSON format only when you configure " _type=json" for " additionalQueryString" property by default.
However, if the client code requests JAX-RS URL by explicitly specifying the format parameter (e.g., " _type=json" or " _type=xml"), then this default configuration will not be applied. In that case, the client-specified request parameter will be applied.
How to configure JAX-RS Extension Providers
The JAX-RS Specification supports the javax.ws.rs.ext.Provider interface which is a marker interface for an implementation of an extension such as javax.ws.rs.ext.MessageBodyReader, javax.ws.rs.ext.MessageBodyWriter, javax.ws.rs.ext.ContextResolver, and javax.ws.rs.ext.ExceptionMapper.
For example, you can add an extension point to return a specific HTTP error on a Java exception by configuring an ExceptionMapper. A simple ExceptionMapper implementation could be like this:
You can configure your providers in an overriding Spring assembly file. For example, you may add the following block in classpath:/META-INF/hst-assembly/overrides/custom-jaxrs-resources.xml:
Your provider(s) will then be registered with the JAX-RS runtime engine (Apache CXF) to provide and use the extension(s).
Security Annotations Support
HST-2 provides security authentication/authorization configurations per site mount or site map item. With that configuration you can manage secured access control per site mount or site map item.
However, sometimes you might need to do secured access control per JAX-RS component operation invocation. For example, you can allow every read access from an operation, but you can allow some updating operations only to some specified roles.
To fulfill this requirement, HST-2 supports the Java EE Security Annotations.
So, you can annotate your methods with the following Java EE Security Annotations:
-
javax.annotation.security.DenyAll
-
javax.annotation.security.PermitAll
-
javax.annotation.security.RolesAllowed
For example, you can add Java EE Security Annotations to your JAX-RS component code like this:
With the example above, the #getProductResource() operation will be allowed for every user having the "everybody" role, while the #getHippoHtmlRepresentation() operation will be allowed only to users having the "author" or "editor" role.
@Persistable Annotation Support
HST-2 supports @Persistable ( org.hippoecm.hst.content.annotations.Persistable) annotation in the JAX-RS Service bean operations (whether it is a Context/Content-Aware JAX-RS Service or Plain JAX-RS Service bean).
If you annotate your JAX-RS Service operations by @Persistable ( org.hippoecm.hst.content.annotations.Persistable) annotation, the following invocation will always return a JCR session from the writable session pool:
-
HstRequestContext#getSession()
So, you don't have to try to use different JCR sessions in an operation context. (e.g., reading with a JCR session from the default session pool and persisting with another JCR session from the writable session)
Instead, you can use only one JCR session from the writable session pool when you read beans and/or persist your beans to the repository. Also, this will reduce possible error-prone codes because you don't have to refresh a JCR session to read some contents again after persisting contents.
Here is an example code, which can be found in the hippo-testsuite project (See the References below).
In the example above, there is no code line to get a writable (persistable) JCR session manually. Instead, the #createProductResources() method is annotated by @Persistable. So, when HstRequestContext#getSession() is invoked, a JCR session will be retrieved from the writable session pool automatically. Every call on HstRequestContext#getSession() in the invoking context of the @Persistable annotated methods, will return a JCR session from the writable session pool automatically.
If your JAX-RS operation needs to persist beans into the repository, it is strongly recommended to use @Persistable annotation rather than to try to get a writable (persistable) JCR session manually.
The ProductBean class that is used in the above example to store a new document must implement the CodeBinderInterface to link the bean properties to node properties.
@ParametersInfo Annotation Support
Since Bloomreach Experience Manager 12.1, HST-2 provides @ParametersInfo annotation support in JAX-RS Service components for both Plain JAX-RS and Context/Content-Aware JAX-RS Service components.
Add the @ParametersInfo annotation to the JAX-RS Service class and the @Context ParametersInfoProvider argument to each method to read parameters in JAX-RS Service components.
You can retrieve the parameters info type instance through the @Context ParametersInfoProvider argument defined in the method.
In Plain JAX-RS Service components, the parameters can be read from its resolved HST Mount. So, add parameter name and value pairs (i.e, @hst:parameternames and @hst:parametervalues) in the mount configuration (hst:mount).
In Context/Content-Aware JAX-RS Service, you can also retrieve the parameters info type instance through the @Context ParametersInfoProvider argument in the same way.
In Context/Content-Aware JAX-RS Service components, the parameters can be read from its resolved HST SiteMapItem or its resolved HST Mount. So, add parameter name and value pairs (i.e, @hst:parameternames and @hst:parametervalues) in the HST SiteMapItem configuration (hst:sitemapitem) or HST mount configuration (hst:mount).