GREB (Generic Resource Entity Builder) API

Bloomreach offers Enterprise support for this feature to Bloomreach Experience customers. The release cycle of this feature may differ from our core product release cycle. 

Status

For version 13, the project has been moved to GitHub as open source. See https://bloomreach-forge.github.io/greb-api/

Introduction

The GREB (Generic Resource Entity Builder) API Add-on enables you to provide a simple, flexible JSON data producing application using the standard HstComponent code.

grebe /gri:b/
(By courtesy of Ferran PestaƱa, licensed by CC BY-SA 2.0)

Suppose you simply want to produce content data in JSON output for any REST API clients (single page applicaton or server-side application) quickly in a very flexible way without having to be concerned about considering standards such as JAX-RS or any other restricitions. Also, suppose you or your colleages already know how to implement standard HstComponents and retrieve content there and so you simply want to implement even RESTful services using the same technology, HstComponents.

In this case, GREB (Generic Resource Entity Builder) API can be a good technical choice.

Please see Install page to install this addon module onto your project. Also see the Release Notes to find the proper version for your project.

What is GREB API?

GREB API is simply a new built-in HST-2 Pipeline to do almost the same things as the default HST-2 Site Pipeline, except of the following:

  • The Pipeline of GREB API consists of the same Valves, but overrides the AggregationValve to produce JSON output instead of the default (HTML) output.
  • As it doesn't need to aggregate all the output from templates of each HstComponent, it doesn't executes all the rendering templates of each HstComponent, After executing #doBeforeRender(HstRequest, HstResponse) on each HstComponent, it stops processing and aggregates all the contributed resource entities and to produce an aggregated JSON result to client.
  • Each HstComponent class can (optionally) contribute any resource entity objects by using GREB API in its code (e.g, #doBeforeRender(HstRequest, HstResponse)). In the overriden AggregationValve, GREB API will collect all the contributed resource entity objects based on the contribution paths and serialize the resource entity objects by using Jackson (v2) library.

Here's an architectural view.

 

 

Basically, you need to configure a separate mount (mapped to "hst:root/grebapi", for example) for GREB API, under your default site pipeline (mapped to "hst:root", for example). So the GREB API mount (e.g, "hst:root/grebapi") will inherit everything from the parent mount (e.g, "hst:root"), including sitemap, pages, components, etc. So, the GREB API mount and its Pipeline will use the same configuration and the same HstComponents.

When the GREB API mount is requested by a REST Client (e.g, http://localhost:8080/site/grebapi/a/b/c.html), the delivery tier will invoke the same sitemap item, page and components, not templates. After invoking #doBeforeRender(HstRequest, HstResponse) on each HstComponent, it collects all the contributed resource entity objects from each HstComponent and aggregate the objects into a JSON output to the REST Client.

How to Contribute Resource Entity Objects?

You can contribute any objects (POJOs or any JSON-serializable objects by Jackson v2 library) in HstComponent code or any other code involved in HST-2 request processing.

If you don't contribute any objects in your code (e.g, HstComponents), the GREB API pipeline will produce an empty JSON object by default:

{
}

To contribute an object, you should get com.onehippo.cms7.genericresource.entitybuilder.GenericResourceEntityBuilder instance first:

    GenericResourceEntityBuilder builder = GenericResourceEntityBuilder.get(RequestContextProvider.get());

You can contribute any scalar values on specific paths like the folloiwng:

    builder.addResourceEntity("title", document.getTitle());
    builder.addResourceEntity("timestamp", System.currentTimeMillis());

As two objects were contributed with paths, then the JSON output will look like this:

{
  "title": "Hello, World!",
  "timestamp": 1479249799770
}

You can contribute any POJO or any Java objects that can be serialized to JSON by using Jackson v2 library:

    builder.addResourceEntity("document", document);

Now, the JSON output will look like this:

{
  "title": "Hello, World!",
  "timestamp": 1479249799770,
  "document": {
    "title": "The medusa news",
    "introduction": "This is a news article.",
    // ...
  }
}

If a Java object is contributed, then GREB API simply serialize it into JSON using Jackson v2 library. Therefore, you should make sure that your Java objects to contribute are serializable in Jackson v2 library. Consider using Jackson annotations if you want to exclude some properties or control the serializations.

How to Contribute Resource Entity Objects in a nested path?

You can wrap your resource entity objects in either java.util.Collection (such as java.util.List or java.util.Set) or java.util.Map like the following example:

    List<Object> references = new LinkedList<>();
    references.add(referenceDoc1);
    references.add(referenceDoc2);
    builder.addResourceEntity("references", references);

    Map<String, Object> images = new LinkedHashMap<>();
    images.put("portrait", portrait);
    images.put("landscape", landscape);
    builder.addResourceEntity("images", images);

Now, the JSON output will look like this:

{
  "title": "Hello, World!",
  "timestamp": 1479249799770,
  "document": {
    "title": "The medusa news",
    "introduction": "This is a news article.",
    // ...
  },
  "references": [
    {
      "title": "Referenced Document 1",
      // ...
    },
    {
      "title": "Referenced Document 2",
      // ...
    }
  ],
  "images": {
    "portrait": {
      // SNIP
    },
    "landscape": {
      // SNIP
    }
  }
}

You can nest objects as deep as you want through container (either java.util.Collection or java.util.Map) objects.

You can also retrieve a resource entity object whether it is a scalar value, object value, collection or map value:

    Object value = builder.getResourceEntity(name);
    Collection<Object> collectionValue = builder.getCollectionResourceEntity(name);
    Map<Object> mapValue = builder.getMapResourceEntity(name);

JSON Serialization Support for Built-in HST-2 Objects

GREB API takes care of JSON serialization on built-in HST-2 objects such as:

  • Any classes extending HippoBean interface. e.g, HST-2 Content Beans, generated manually or through Essentials for each document type, built-in HST-2 Content Beans for images, assets, folders, html, mirror, etc.
  • HST-2 Site Menu and Menu Item objects.
  • HST-2 URL objects and HstLink objects.

Therefore, you can contribute objects in those categories directly without having to wrap it to new POJO objects.

Custom Jackson Mixins to Customize JSON Serialization

GREB API support customizing JSON serialization on specific beans by adding custom Jackson Mixins for the specific bean types.

In order to register your custom Jackson Mixin classes (or interfaces) with Jackson annotations, override the following beans in an Spring Beans assembly overriding XML file under site/src/resources/META-INF/hst-assembly/overrides/addon/com/onehippo/cms7/genericresource/entitybuilder/ folder (e.g, my-custom-mixins.xml) like the following example:

<?xml version="1.0" encoding="UTF-8"?>
<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-4.1.xsd">

  <bean id="genericResourceEntityJacksonObjectMapperExtraMixins"
        class="org.springframework.beans.factory.config.MapFactoryBean">
    <property name="sourceMap">
      <map>
        <!-- Adding Jackson Mixin class, MyBeanMixin, for MyBean class type. -->
        <entry key="org.example.beans.MyBean" value="org.example.beans.jackson.MyBeanMixin" />
        <!-- SNIP -->
      </map>
    </property>
  </bean>

</beans>

This also allows you to override the built-in default Jackson Mixins for built-in types (such as HippoGalleryImageSetBean, HippoGalleryImageBean, etc.) by your custom Jacksion Mixins.

 

Did you find this page helpful?
How could this documentation serve you better?
On this page
    Did you find this page helpful?
    How could this documentation serve you better?