Deploying XIN Mods

Using Tomcat to Deploy your XIN Mods Headless BloomReach XM Instance

Make sure to install the latest official Oracle Java JDK and have your path point at the Java executables.

Create a Bloomreach XM distribution

Checkout the tag you wish to build a distribution for:

$ mvn -Pdist,without-content verify

The target/*tar.gz file contains the distributed version of the hippo instance, complete with shared libs and common libs

Note: Make sure common/lib/jcl-over-slf4j-1.7.25.jar does not exist.

To install new releases you no longer need all of the distribution, you would unpack only the shared, common and webapps folders like so:

$ tar xvzf dist-version.tar.gz shared common webapps

Tomcat Setup

To setup tomcat:

  • grab a bundle from the Tomcat website

  • install it locally by unpacking it

  • unzip the Bloomreach XM distribution

  • create bin/

      REP_OPTS="-Drepo.upgrade=false -Drepo.config=file:${CATALINA_BASE}/conf/repository.xml -Drepo.path=./storage"
      JVM_OPTS="-server -Xmx512m -Xms128m"

Of course make sure to point the JAVA_HOME environment variable at the one relevant for your system.

Setup conf/tomcat-users.xml

Edit the tomcat-users.xml file and make it look similar to the following.

<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users xmlns=""
              xsi:schemaLocation=" tomcat-users.xsd"

  <role rolename="tomcat" />
  <role rolename="manager-gui" />
  <role rolename="admin-gui" />

  <user username="tomcat" password="<password>" roles="tomcat,manager-gui,admin-gui"/>

Setup conf/

Make the following changes to Tomcat's file.

  • replace value for common.loader with the one below:

          common.loader="${catalina.base}/common/lib/*.jar", \
    • create shared.loader property with these values:

  • make sure Tomcat only binds to localhost. Go into tomcat/conf/server.xml and change the Connector to read:

      <Connector port="8080" protocol="HTTP/1.1"
                 redirectPort="8443" />

MySQL setup

Your repository will be using a MySQL database to store most of its information. You have to make sure to install a MySQL server onto your box. The instructions below are for a Debian-based distribution, you might have to do it differently depending on the distribution you are using.

$ apt-get install mysql-server

Login to the MySQL server.

$ mysql -u root -p

Create xinmods database:

$ drop database if exists xinmods;
$ create database xinmods default charset 'utf8';

Grant all access to xinmods database to hippodb

$ grant all privileges on xinmods.* to 'hippodb'@'localhost' identified by '<your password here>'

Add resource definition in tomcat/conf/context.xml

	name="jdbc/repositoryDS" auth="Container" type="javax.sql.DataSource"
	maxTotal="20" maxIdle="10" initialSize="2" maxWaitMillis="10000"
	testWhileIdle="true" testOnBorrow="false" validationQuery="SELECT 1"
	username="<USERNAME>" password="<PASSWORD>"

Create repository.xml at tomcat/conf/repository.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Repository
          PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 2.6//EN"
    <DataSource name="repositoryDS">
      <param name="driver" value="javax.naming.InitialContext"/>
      <param name="url" value="java:comp/env/jdbc/repositoryDS"/>
      <param name="databaseType" value="mysql"/>
  <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
    <param name="dataSourceName" value="repositoryDS"/>
    <param name="schemaObjectPrefix" value="repository_"/>
  <Security appName="Jackrabbit">
    <SecurityManager class=""/>
    <AccessManager class=""/>
    <LoginModule class=""/>
  <Workspaces rootPath="${rep.home}/workspaces" defaultWorkspace="default"/>
  <Workspace name="${}">
    <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
      <param name="dataSourceName" value="repositoryDS"/>
      <param name="schemaObjectPrefix" value="${}_"/>
    <PersistenceManager class="org.apache.jackrabbit.core.persistence.pool.MySqlPersistenceManager">
      <param name="dataSourceName" value="repositoryDS"/>
      <param name="schemaObjectPrefix" value="${}_"/>
      <param name="externalBLOBs" value="true"/>
      <param name="consistencyCheck" value="false"/>
      <param name="consistencyFix" value="false"/>
      <param name="bundleCacheSize" value="64"/>
    <SearchIndex class="org.hippoecm.repository.FacetedNavigationEngineImpl">
      <param name="indexingConfiguration" value="indexing_configuration.xml"/>
      <param name="indexingConfigurationClass" value="org.hippoecm.repository.query.lucene.ServicingIndexingConfigurationImpl"/>
      <param name="path" value="${wsp.home}/index"/>
      <param name="useSimpleFSDirectory" value="true"/>
      <param name="useCompoundFile" value="true"/>
      <param name="minMergeDocs" value="100"/>
      <param name="volatileIdleTime" value="10"/>
      <param name="maxMergeDocs" value="100000"/>
      <param name="mergeFactor" value="5"/>
      <param name="maxFieldLength" value="10000"/>
      <param name="bufferSize" value="1000"/>
      <param name="cacheSize" value="1000"/>
      <param name="onWorkspaceInconsistency" value="log"/>
      <param name="forceConsistencyCheck" value="false"/>
      <param name="enableConsistencyCheck" value="false"/>
      <param name="autoRepair" value="true"/>
      <param name="analyzer" value="org.hippoecm.repository.query.lucene.StandardHippoAnalyzer"/>
      <param name="queryClass" value="org.apache.jackrabbit.core.query.QueryImpl"/>
      <param name="respectDocumentOrder" value="false"/>
      <param name="resultFetchSize" value="1000"/>
      <param name="extractorTimeout" value="100"/>
      <param name="extractorBackLogSize" value="100"/>
      <param name="excerptProviderClass" value="org.apache.jackrabbit.core.query.lucene.DefaultHTMLExcerpt"/>
      <param name="supportSimilarityOnStrings" value="true"/>
      <param name="supportSimilarityOnBinaries" value="false"/>
    <ISMLocking class="org.apache.jackrabbit.core.state.FineGrainedISMLocking"/>
  <Versioning rootPath="${rep.home}/version">
    <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
      <param name="dataSourceName" value="repositoryDS"/>
      <param name="schemaObjectPrefix" value="version_"/>
    <PersistenceManager class="org.apache.jackrabbit.core.persistence.pool.MySqlPersistenceManager">
      <param name="dataSourceName" value="repositoryDS"/>
      <param name="schemaObjectPrefix" value="version_"/>
      <param name="externalBLOBs" value="true"/>
      <param name="consistencyCheck" value="false"/>
      <param name="consistencyFix" value="false"/>
    <ISMLocking class="org.apache.jackrabbit.core.state.FineGrainedISMLocking"/>
    <Journal class="org.apache.jackrabbit.core.journal.DatabaseJournal">
      <param name="dataSourceName" value="repositoryDS"/>
      <param name="databaseType" value="mysql"/>
      <param name="schemaObjectPrefix" value="repository_"/>
      <param name="revision" value="${rep.home}/revision.log"/>
  <DataStore class="">
    <param name="dataSourceName" value="repositoryDS"/>
    <param name="minRecordLength" value="1024"/>
    <param name="maxConnections" value="5"/>
    <param name="copyWhenReading" value="true"/>


Setup Apache Virtualhost

Install Apache:

$ sudo apt-get install apache2
$ sudo a2enmod proxy_http
$ sudo a2enmod headers
$ sudo a2enmod substitute
$ sudo a2enmod rewrite

Create new Virtualhost file. It contains three definitions:

  • http://cms.hippo.local/
  • http://cms.hippo.local/packages/
  • http://api.hippo.local/api/xin (goes to custom-api/)
  • http://api.hippo.local/api/* (goes to api/)

Make sure to adjust the hostnames to your taste. It assumes your Tomcat is running on port 8080.

Create /etc/apache2/sites-available/hippo.conf:

#       CMS definition
<VirtualHost *:80>

    ServerName cms.hippo.local

    <Location />
        Order deny,allow
        Allow from all

    ProxyPreserveHost Off 

    # /packages should redirect to the package manager
    ProxyPass /packages/
    ProxyPassReverse /packages/
    ProxyPassReverseCookiePath /site/packages /packages/

    # / should go to the CMS
    ProxyPass /
    ProxyPassReverse /cms/
    ProxyPassReverseCookiePath /cms /

#       CaaS delivery virtualhost
<VirtualHost *:80>

    ServerName api.hippo.local

    <Location />
        Order deny,allow
        Deny from all

    <Location /api/>
        Order deny,allow
        Allow from all

    <Location /binaries/>
        Order deny,allow
        Allow from all
    <Location /assetmod/>
        Order deny,allow
        Allow from all

    # -- substitute resulting links with correct domain
    AddOutputFilterByType SUBSTITUTE application/json
    Substitute "s|http://localhost(:8080)?/site/|http://api.hippo.local/|i"

    # -- preflight option checks dont send Authorization header causing
    # -- to fail JAAS Realm definition, returning 401. Sending 204 with OPTIONS
    # -- response here.
    Header always set Access-Control-Allow-Origin "*"                                                                                          
    Header always set Access-Control-Allow-Credentials "true"                                                                                  
    Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT, HEAD"                                                     
    Header always set Access-Control-Max-Age "1000"                                                                                            
    Header always set Access-Control-Allow-Headers "x-requested-with, Content-Type, origin, authorization, accept, client-security-token"      
    # -- Added a rewrite to respond with a 204 SUCCESS on every OPTIONS request
    # -- L flag causes breaking of processing chain
    RewriteEngine On
    RewriteRule ^(.*)$ $1 [R=204,L]

    RequestHeader set Host "localhost"
    ProxyPreserveHost On
    ProxyPass /api/xin/
    ProxyPass /
    ProxyPassReverse /site/
    ProxyPassReverseCookiePath /site /


Make sure to replace the host names with proper host names. Enable the virtual host by typing:

$ a2ensite hippo

Useful scripts

This script deletes the current tomcat instance, drops the db and restarts it.


rm logs/*
rm storage -Rf
mysql -u root -p -e "drop database if exists xinmods; create database xinmods default charset 'utf8'";
> logs/catalina.out

Kills the tomcat instance very much:


PID=$(ps aux | grep tomcat | head -n 1 | cut -d' ' -f4)

echo "Killing $PID"
kill -9 $PID