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

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):

<!--
Enabling to use '_format' parameter name instead of the CXF default
_type parameter name for the plain JAX-RS pipeline. Also, if you set
'additionalQueryString' property, then all the JAX-RS requests will
have the additional parameters forcefully. For example, if you set it
to '_type=json', then you can force the output format to JSON format
globally without considering 'Accept' HTTP request header.
-->
<bean id="jaxrsRestPlainServiceQueryStringReplacingInterceptor"
class="org.hippoecm.hst.jaxrs.cxf.QueryStringReplacingInterceptor">
<property name="paramNameReplaces">
<map>
<!-- The following will replace '_format' parameter name with
'_type' parameter name before JAX-RS processing. -->
<entry key="_format" value="_type" />
</map>
</property>
<property name="additionalQueryString">
<value></value>
<!-- The following will append additional query string before JAX-RS
processing
<value>_type=json</value>
-->
</property>
</bean>
<!--
Enabling to use '_format' parameter name instead of the CXF default
_type parameter name for the Content/Context-Aware JAX-RS pipeline.
Also, if you set 'additionalQueryString' property, then all the JAX-RS
requests will have the additional parameters forcefully. For example,
if you set it to '_type=json', then you can force the output format to
JSON format globally without considering 'Accept' HTTP request header.
-->
<bean id="jaxrsRestContentServiceQueryStringReplacingInterceptor"
class="org.hippoecm.hst.jaxrs.cxf.QueryStringReplacingInterceptor">
<property name="paramNameReplaces">
<map>
<!-- The following will replace '_format' parameter name with
'_type' parameter name before JAX-RS processing. -->
<entry key="_format" value="_type" />
</map>
</property>
<property name="additionalQueryString">
<value></value>
<!-- The following will append additional query string before JAX-RS
processing
<value>_type=json</value>
-->
</property>
</bean>

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

Due to bug HSTTWO-3639 this feature is currently not available in Hippo 11.x.

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:

package org.hippoecm.hst.demo.jaxrs.ext;
/**
* This extension provider can be configured to be invoked whenever
* MyCustomSecurityException occurs. In that case, this provider simply
* returns a forbidden access status code. This provider can make the
* remaining JAX-RS Resource operation implementations much more simplified.
* Refer to the JAX-RS Specification for more detail.
*/
@Provider
public class MyCustomSecurityExceptionMapper
implements ExceptionMapper<MyCustomSecurityException> {
public Response toResponse(MyCustomSecurityException ex) {
return Response.status(Response.Status.FORBIDDEN).build();
}
}

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.

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.

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.