Client Configuration - BloomReach Experience - Open Source CMS
26-09-2016

Client Configuration

Previous - Next

In the previous step, you developed a simple REST client to be used in your Hippo-based project. Typically the connection parameters will be different per environment. For example, between test, staging, and production environments, you might want to use different values for baseAddress or connectionTimeout. This page describes how to create a custom configuration namespace and configuration nodes to store this configuration in the repository and how to reload that configuration using a JCR event listener.

Create the Custom Namespace

Add a new file called gogreenclient.cnd to bootstrap/configuration/src/main/resources/namespaces/:

<'gogreenclient'='http://www.onehippo.org/gogreenclient/nt/1.0'>
<'nt'='http://www.jcp.org/jcr/nt/1.0'>

[gogreenclient:config] > nt:base
- gogreenclient:baseAddress (string)
- gogreenclient:path (string)
- gogreenclient:connectionTimeout(long)
- gogreenclient:receiveTimeout (long)

Also, add a new initialization item for the CND to the bootstrap/configuration/src/main/resources/hippoecm-extension.xml:

<sv:node sv:name="gogreenclient">
  <sv:property sv:name="jcr:primaryType" sv:type="Name">
    <sv:value>hippo:initializeitem</sv:value>
  </sv:property>
  <sv:property sv:name="hippo:sequence" sv:type="Double">
    <sv:value>30000.1</sv:value>
  </sv:property>
  <sv:property sv:name="hippo:namespace" sv:type="String">
    <sv:value>http://www.onehippo.org/gogreenclient/nt/1.0</sv:value>
  </sv:property>
  <sv:property sv:name="hippo:nodetypesresource" sv:type="String">
    <sv:value>namespaces/gogreenclient.cnd</sv:value>
  </sv:property>
</sv:node>

Rebuild and restart the project. Make sure you start with a fresh repository. The gogreenclient namespace and node types should be available in the console.

Create the Client Configuration Node

Log in to the Console and add a node under the root node of type gogreenlient:config called gogreenclient:config, by importing the following XML:

<sv:node sv:name="gogreenclient:config" xmlns:sv="http://www.jcp.org/jcr/sv/1.0">
  <sv:property sv:name="jcr:primaryType" sv:type="Name">
    <sv:value>gogreenclient:config</sv:value>
  </sv:property>
  <sv:property sv:name="gogreenclient:baseAddress" sv:type="String">
    <sv:value>https://www.demo.onehippo.com/</sv:value>
  </sv:property>
  <sv:property sv:name="gogreenclient:connectionTimeout" sv:type="Long">
    <sv:value>5000</sv:value>
  </sv:property>
  <sv:property sv:name="gogreenclient:path" sv:type="String">
    <sv:value>restapi/topproducts</sv:value>
  </sv:property>
  <sv:property sv:name="gogreenclient:receiveTimeout" sv:type="Long">
    <sv:value>5000</sv:value>
  </sv:property>
</sv:node>

Create the JCR Event Listener

In your project's site module, create a Java class org.example.rest.client.ConfigurationChangeListener and make it implement javax.jcr.observation.EventListener.

In the onEvent() method, load the GoGreenClient and call a (yet-to-be-created) reconfigure() method

site/src/main/java/org/example/rest/client/ConfigurationChangeListener.java:

package org.example.rest.client;

import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;

import org.hippoecm.hst.site.HstServices;

public class ConfigurationChangeListener implements EventListener {

    @Override
    public void onEvent(final EventIterator events) {
        GoGreenClient goGreenClient = HstServices.getComponentManager().getComponent(GoGreenClient.class);
        goGreenClient.reconfigure();
    }

}

Add the following Spring bean configuration to your gogreen-client.xml:

site/src/main/resources/META-INF/hst-assembly/overrides/gogreen-client.xml:

<bean id="customJcrObservationEventListenerItems" class="org.springframework.beans.factory.config.ListFactoryBean">
  <property name="sourceList">
    <list>
      <bean class="org.hippoecm.hst.core.jcr.EventListenerItemImpl">
        <property name="nodeAddedEnabled" value="true"/>
        <property name="nodeRemovedEnabled" value="true"/>
        <property name="propertyAddedEnabled" value="true"/>
        <property name="propertyChangedEnabled" value="true"/>
        <property name="propertyRemovedEnabled" value="true"/>
        <property name="absolutePath" value="/gogreenclient:config"/>
        <property name="deep" value="true"/>
        <property name="eventListener">
          <bean class="org.example.rest.client.ConfigurationChangeListener">
          </bean>
        </property>
      </bean>
    </list>
  </property>
</bean>

Read the Configuration in the Client Class

In GoGreenClient, add a configure() method. This method will log into the Spring-provided Repository with the Credentials also provided by Spring and read the configuration settings from the repository.

Add the following instance variables to GoGreenClient:

private Boolean configured = false;
private String configNodePath;
private Repository repository;
private Credentials credentials;

Add the following getters and setters:

    public String getConfigNodePath() {
        return configNodePath;
    }

    public void setConfigNodePath(String configNodePath) {
        this.configNodePath = configNodePath;
    }

    public Repository getRepository() {
        return repository;
    }

    public void setRepository(Repository repository) {
        this.repository = repository;
    }

    public Credentials getCredentials() {
        return credentials;
    }

    public void setCredentials(Credentials credentials) {
        this.credentials = credentials;
    }

Add the configure method:

private void configure() {
    log.info("(Re-)Configuring GoGreenClient");
    Session session = null;
    try {
        session = repository.login(credentials);

        Node configNode = session.getNode(configNodePath);

        setBaseAddress(configNode.getProperty("gogreenclient:baseAddress").getString());
        setReceiveTimeout(configNode.getProperty("gogreenclient:receiveTimeout").getLong());
        setConnectionTimeout(configNode.getProperty("gogreenclient:connectionTimeout").getLong());
        setPath(configNode.getProperty("gogreenclient:path").getString());

        configured = true;
    } catch (LoginException e) {
        log.error("Error (re-)configuring GoGreenClient", e);
    } catch (RepositoryException e) {
        log.error("Error (re-)configuring GoGreenClient", e);
    } finally {
        if (session != null) {
            session.logout();
        }
    }
}

In the getTopTenProducts() method, check if the client has been configured before attempting to access the cache:

public Products getTopTenProducts() {

    if (!configured) {
        configure();
    }

    final Cache testCache = manager.getCache(GO_GREEN_CACHE_NAME);
    // try to retrieve element from cache
    final Element element = testCache.get(KEY_TOP_TEN_PRODUCTS);
    if (element != null) {
        return (Products) element.getObjectValue();
    } else {
        // if cache element does not exist retrieve object and place in cache
        final WebClient client = WebClient.create(baseAddress).path(path).accept(MediaType.APPLICATION_XML)
                .query("sortby", "hippogogreen:rating").query("max", 10);
        setTimeouts(client, this.connectionTimeout, this.receiveTimeout);
        final Products products = client.get(Products.class);
        testCache.put(new Element(KEY_TOP_TEN_PRODUCTS, products));
        return products;
    }
}

Add the reconfigure method that will be triggered by the event listener:

public void reconfigure() {
    configured = false;
}

And finally, modify the bean definition in gogreen-client.xml to add the Repository, Credentials, and configuration location properties:

<bean id="org.example.rest.client.GoGreenClient" class="org.example.rest.client.GoGreenClient" init-method="init">
  <property name="configNodePath" value="/gogreenclient:config"/>
  <property name="repository" ref="javax.jcr.Repository.delegating" />
  <property name="credentials" ref="javax.jcr.Credentials.hstconfigreader.delegating"/>
</bean>

Previous - Next

Full Source Code

For easy reference, the complete source of the GoGreenClient is provided below.

GoGreenClient.java

package org.example.rest.client;

import javax.jcr.Credentials;
import javax.jcr.LoginException;
import javax.jcr.Node;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.ws.rs.core.MediaType;

import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.transport.http.HTTPConduit;
import org.example.jaxb.Products;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import net.sf.ehcache.config.CacheConfiguration;

public class GoGreenClient {

    private static final Logger log = LoggerFactory.getLogger(GoGreenClient.class);

    private String baseAddress = "https://www.demo.onehippo.com/";
    private String path = "restapi/topproducts";

    private long connectionTimeout = 5000L;
    private long receiveTimeout = 5000L;

    private static final String GO_GREEN_CACHE_NAME = "GoGreenCache";
    private static final String KEY_TOP_TEN_PRODUCTS = "topTenProducts";

    // create a singleton CacheManager using defaults
    private CacheManager manager = CacheManager.create();

    private Boolean configured = false;
    private String configNodePath;
    private Repository repository;
    private Credentials credentials;

    public Products getTopTenProducts() {

        if (!configured) {
            configure();
        }

        final Cache testCache = manager.getCache(GO_GREEN_CACHE_NAME);
        // try to retrieve element from cache
        final Element element = testCache.get(KEY_TOP_TEN_PRODUCTS);
        if (element != null) {
            return (Products) element.getObjectValue();
        } else {
            // if cache element does not exist retrieve object and place in cache
            final WebClient client = WebClient.create(baseAddress).path(path).accept(MediaType.APPLICATION_XML)
                    .query("sortby", "hippogogreen:rating").query("max", 10);
            setTimeouts(client, this.connectionTimeout, this.receiveTimeout);
            final Products products = client.get(Products.class);
            testCache.put(new Element(KEY_TOP_TEN_PRODUCTS, products));
            return products;
        }
    }

    public String getBaseAddress() {
        return baseAddress;
    }

    public void setBaseAddress(String baseAddress) {
        this.baseAddress = baseAddress;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public long getConnectionTimeout() {
        return connectionTimeout;
    }

    public void setConnectionTimeout(long connectionTimeout) {
        this.connectionTimeout = connectionTimeout;
    }

    public long getReceiveTimeout() {
        return receiveTimeout;
    }

    public void setReceiveTimeout(long receiveTimeout) {
        this.receiveTimeout = receiveTimeout;
    }

    private void setTimeouts(final WebClient client, final long connectionTimeout, final long receiveTimeout) {
        HTTPConduit conduit = WebClient.getConfig(client).getHttpConduit();
        if (receiveTimeout != 0) {
            conduit.getClient().setReceiveTimeout(receiveTimeout);
        }
        if (connectionTimeout != 0) {
            conduit.getClient().setConnectionTimeout(connectionTimeout);
        }
    }

    public void init() {
        log.info("(Re-)Initializing GoGreenClient");
        // (re)create cache
        manager.removeCache(GO_GREEN_CACHE_NAME);
        Cache testCache = new Cache(new CacheConfiguration(GO_GREEN_CACHE_NAME, 100));
        manager.addCache(testCache);
    }

    private void configure() {
        log.info("(Re-)Configuring GoGreenClient");
        Session session = null;
        try {
            session = repository.login(credentials);

            Node configNode = session.getNode(configNodePath);

            setBaseAddress(configNode.getProperty("gogreenclient:baseAddress").getString());
            setReceiveTimeout(configNode.getProperty("gogreenclient:receiveTimeout").getLong());
            setConnectionTimeout(configNode.getProperty("gogreenclient:connectionTimeout").getLong());
            setPath(configNode.getProperty("gogreenclient:path").getString());

            configured = true;
        } catch (LoginException e) {
            log.error("Error (re-)configuring GoGreenClient", e);
        } catch (RepositoryException e) {
            log.error("Error (re-)configuring GoGreenClient", e);
        } finally {
            if (session != null) {
                session.logout();
            }
        }
    }

    public void reconfigure() {
        configured = false;
    }

    public String getConfigNodePath() {
        return configNodePath;
    }

    public void setConfigNodePath(String configNodePath) {
        this.configNodePath = configNodePath;
    }

    public Repository getRepository() {
        return repository;
    }

    public void setRepository(Repository repository) {
        this.repository = repository;
    }

    public Credentials getCredentials() {
        return credentials;
    }

    public void setCredentials(Credentials credentials) {
        this.credentials = credentials;
    }

}

Previous - Next

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?