Skip to end of metadata
Go to start of metadata

Original Author: Thu Doan

NOTE: This page is a little out of date. For a good working example of how to create a new filter and bundle it for deployment into Repose, please see the new Hello World custom filter bundle project that this page will eventually reference. This project is located at:




This document takes a bare minimum approach in explaining how to create a Repose filter and run it on an existing Repose proxy server instance.  A robust filter will include unit testing with extensive test cases. Once you have a firm understanding of how to create a filter, look back at the Repose source to see how test cases are written and be sure to include unit testing for your filter.  


Create a hello-world Repose filter so that messages that you configure in hello-world.cfg.xml get printed to the default Repose proxy server log: /var/log/repose/current.log. 

Your hello-world.cfg.xml file will look something like:

Sample hello-world.cfg.xml file
<hello-world xmlns=''>
      <message value="My Hello World!!!" />    


 Click here to expand...

1. Run the command:

sudo wget -O - | sudo apt-key add –


2. Create openrepose.list file:

sudo vi /etc/apt/sources.list.d/openrepose.list


3. Add the line:

deb stable main


4. Save and exit the file


5. Run the command:

sudo apt-get update


You should see the following output:

Get:1 stable Release.gpg [230 B]
Get:2 stable Release [1,595 B]                                                               
Ign stable Release                                                                                             
Ign stable/main TranslationIndex                                                                                
Get:3 stable/main amd64 Packages [9,655 B]                                            
Get:4 stable/main i386 Packages [9,655 B]             
Hit precise Release.gpg                            
Get:5 precise-security Release.gpg [198 B]                                                           
Ign stable/main Translation-en_US                                               
Hit precise-updates Release.gpg                                
Get:6 precise-security Release [49.6 kB]                                  
Ign stable/main Translation-en


6. Run the command:

sudo apt-get install repose-valve repose-filter-bundle


7. Enter “y” at the prompt.

8. Once the install finishes, you will see an executable:





 Click here to expand...

1. After you install Repose, locate the files in:



2. Edit the /etc/repose/container.cfg.xml file.

sudo vi /etc/repose/container.cfg.xml


You will see:

<?xml version="1.0" encoding="UTF-8"?>

<!-- To configure Repose see: -->

<repose-container xmlns=''>

    <deployment-config connection-timeout="30000" read-timeout="30000">
        <deployment-directory auto-clean="false">/var/repose</deployment-directory>
        <artifact-directory check-interval="60000">/usr/share/repose/filters</artifact-directory>
        <logging-configuration href="log4j2.xml"/>


3. Change the auto-clean attribute to true to allow Repose to clean the deployment directory of artifacts.

4. Edit the /etc/repose/system-model.cfg.xml file:

sudo vi /etc/repose/system-model.cfg.xml


You will see:

<?xml version="1.0" encoding="UTF-8"?>
<!-- To configure Repose see: -->
<system-model xmlns="">
  <repose-cluster id="repose">
      <node id="repose_node1" hostname="localhost" http-port="8080"/>



5. Make sure that http-port 8080 is an available port on the server. You can test to see if port 8080 is available via the command:

netstat –na | grep 8080


If port 8080 is available, you will see blank output from the command. 

If port 8080 is not available, the command will output something like:

tcp46      0      0  *.8080                 *.*                    LISTEN  


6. If 8080 is not available, edit the port number to an available port.


Still looking at the file: /etc/repose/system-model.cfg.xml, near the bottom, you will see:

      <!-- Update this endpoint if you want Repose to send requests to a different service -->
      <endpoint id="open_repose" protocol="http" hostname=" " root-path="/" port="80" default="true"/>


The hostname attribute is the pass-through destination that the filter chain forwards to. The default is:  If you would like Repose to forward to a different destination, edit the hostname accordingly.


 Click here to expand...

Error rendering macro 'excerpt-include' : No link could be created for '_Test the Repose server chunk'.

Set Up the OpenRepose Project

 Click here to expand...

These steps are typically carried out on your desktop development environment and not on the same machine that you set up your Repose proxy server.  However, if your desktop is a Linux distribution, you can follow these steps on the same machine that Repose is installed on.

Step-by-step guide

1. Open a terminal shell and change to the desired directory to where you want the Repose source downloaded.  For this example, we use: ~/Documents/workspace3/.

2. Run the command:

git clone

Although you can run the above git command in an IDE like Eclipse, we made the cloning step IDE agnostic.


3. Import the Repose project into your favorite IDE (in this case Eclipse).

a) File > Import

b) Maven > Existing Maven Project


c) Click Next.

d) Select All.

e) Click Next.

f) Click Finish.

g) When prompted with, “Continuing with imports will result in projects with build errors…” , click OK.


In Project Explorer, you should see something like:

i) Ignore all the errors.

j) Expand the filter-bundle folder and right click on pom.xml.

k) Select Run As > m2 1 Maven build.

l) If prompted in the Goals, enter clean install.

m) Click Run. 


Alternatively without an IDE, you could use a terminal command screen, change directories to the repose/filter-bundle, and run the command:

mvn clean install

For all future maven build steps, you can always manually invoke the mvn command in the respective project folders. However, the directions from this point on will be Eclipse specific.

n) Right click on filter-bundle/target and select Refresh.

o) Expand filter-bundle > target. You should see:


Congrats! You have built the Repose project with all the filters disabled! Woohoo!!!

Create the Hello World Filter

The majority of these steps are carried out on your desktop development environment.  Once you have built your new filter, you will copy the filter-bundle-2.12.1.ear to the machine where your proxy server is installed.


1. From a command terminal window, change directories from where you cloned the Repose project to: 


2. Open the file: pom.xml. You will see something like:


Use the groupId and version values in the next commands. (Keep the pom.xml opened for viewing.)

3. In the command terminal window, change directories from where you cloned the Repose project to: 





 4. Run the command:

mvn archetype:generate -DgroupId=org.openrepose -DartifactId=hello-world -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Make sure –DgroupId matches the groupId value.

5. Change directory to the new hello-world folder:

cd hello-world 

6. Open the pom.xml for editing.

7. In this section:


Remove the version so it will be inherited from the parent.

8. In the pom.xml, starting from the line <dependencies>, delete all lines below it.

9. Replace the deleted lines with the following:


10. Save the pom.xml.

11. Import the new hello-world project into your favorite IDE (Eclipse in this case).

a. File > Import

b. Maven > Existing Maven Projects >Next

c. Browse to the hello-world project folder and click Open

d. Click Next.


d. Click Finish. 

e. When prompted with “Continuing with import will result in projects with build errors, …”,  click OK.


When viewing with the Project Navigator view, you should see:

12. Delete the and files.

13.  Create new folders.



14. Create a new file:



15. Cut and paste the following content to the file and save it:

<?xml version="1.0" encoding="UTF-8"?>

<hello-world xmlns=''>
     <!-- This is the message you want to output to the log. -->    
     <message value="My Hello World!!!" />    


16. Create a new file:



17. Cut and paste the following content to the file and save it:

<?xml version="1.0" encoding="UTF-8"?>

<bindings xmlns="" version="2.0"
        <!-- This file name must match the file to be created in step 18. -->
        schemaLocation="hello-world-configuration.xsd[td1] ">        
       <package name="org.openrepose.filters.helloworld.config"/>


18. Create a new file:



19. Copy and paste the following content to the file and save it:

<?xml version="1.0" encoding="UTF-8"?>

<xs:schema elementFormDefault="qualified" attributeFormDefault="unqualified"

<!-- This matches the root element tag in hello-world.cfg.xml created in step 14. -->
  <xs:element name="hello-world[td1] " type="hello-world:HelloWorldConfig"/> 
  <xs:complexType name="HelloWorldConfig">
             <html:p>Hello World can be configured by editing the hello-world.cfg.xml file. The user can specify the following information:</html:p>
                     <!-- This matches the child tag <hello-world> in hello-world.cfg.xml. -->
      <xs:element name="messages" type="hello-world:MessagesList" minOccurs="1" maxOccurs="1"
                                                                       <!-- There must be one and 
                                                                       only one <messages> tag 
                                                                       in hello-world.cfg.xml -->
<xs:complexType name="MessagesList">  
           <html:p>List messages.</html:p>
                    <!-- This matches the child tag 
                    <messages> in hello-world.cfg.xml. -->        <!-- There is one or more instance 
                                                                  of a <message> tag in hello-world.cfg.xml -->
  <xs:element name="message" type="hello-world:HelloWorldMessage" minOccurs="1" maxOccurs="unbounded" />                                                                 
                   <!-- Must match <message> tag (children of messages tag in hello-world.cfg.xml). -->                                    
<xs:assert vc:minVersion="1.1" test="count(distinct-values(hello-world:message /@value)) = count(hello-world:message /@value)"
            xerces:message="A message must have value unique within their containing messages list"
            saxon:message="A message must have value unique within their containing messages list"/>
<!-- This results in the generation of 
with a property named value with type: String -->
<xs:complexType name="HelloWorldMessage[td5] ">
              <html:p>The message</html:p>
                   <!-- There is only one attribute of the <message> tag, and it is required. -->   
   <xs:attribute name="value[td6] " type="xs:string" use="required">
               <html:p>This header key is applied to the x-pp-group header. The header value associated with this key 
                 is applied to the x-pp-user header.</html:p>



20. After steps 14-19, you should see:


21. Right click on the pom.xml and select:

Run As > m2 2 Mavin build.

22. In Goals enter: “clean generate-resources”.

23. Click Run.

This should generate the following files:

24. Create the following files:


25. In, cut and paste the following content and save the file.

package org.openrepose.filters.helloworld;
import org.openrepose.filters.helloworld.config.HelloWorldConfig;
import org.openrepose.core.filter.FilterConfigHelper;
import org.openrepose.core.filter.logic.impl.FilterLogicHandlerDelegate;
import com.rackspace.papi.service.config.ConfigurationService;
import javax.servlet.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
       <!-- Most of this is boiler plate code. -->
public class HelloWorldFilter implements Filter {

     private static final Logger LOG = 
                         <!-- Must match the file name created in step 14. -->
     private static final String DEFAULT_CONFIG = "hello-world.cfg.xml";
     private String config;
     private HelloWorldHandlerFactory handlerFactory;
     private ConfigurationService configurationManager;
     public void doFilter(ServletRequest request, ServletResponse response, 
FilterChain chain) throws IOException, ServletException {

          new FilterLogicHandlerDelegate(request, response, chain).doFilter(handlerFactory.newHandler());   

     public void destroy() {
          configurationManager.unsubscribeFrom(config, handlerFactory);
    public void init(FilterConfig filterConfig) throws ServletException {
          config = new
"Initializing filter using config " + config);
          configurationManager = 
           handlerFactory = new HelloWorldHandlerFactory();
                       <!-- Must match the .xsd file created in step 18. -->
          URL xsdURL = getClass().getResource("/META-INF/schema/config/hello-world-configuration.xsd");

configurationManager.subscribeTo(filterConfig.getFilterName(),config,xsdURL, handlerFactory, 


26.  In, cut and paste the following content and save the file:

package org.openrepose.filters.helloworld;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.openrepose.commons.utils.servlet.http.ReadableHttpServletResponse;
import org.openrepose.filters.helloworld.config.HelloWorldMessage;
import org.openrepose.core.filter.logic.FilterAction;
import org.openrepose.core.filter.logic.FilterDirector;
import org.openrepose.core.filter.logic.common.AbstractFilterLogicHandler;
import org.openrepose.core.filter.logic.impl.FilterDirectorImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HelloWorldHandler extends AbstractFilterLogicHandler {
     private static final Logger LOG = LoggerFactory.getLogger(HelloWorldHandler.class);
     private final List<HelloWorldMessage> helloworldMessages;
     public HelloWorldHandler(List<HelloWorldMessage> helloworldMessages) {
         this.helloworldMessages = helloworldMessages;


<!-- This is where our custom logic is invoked. For the purposes of this exercise, 
we simply log the messages configured in hello-world.cfg.xml. -->
   public FilterDirector handleRequest[td1] (HttpServletRequest request, ReadableHttpServletResponse response)
     final FilterDirector filterDirector = new FilterDirectorImpl();
     filterDirector.setFilterAction(FilterAction.PASS);"~~~helloworldMessages begin:");
     <!-- Get all the messages in hello-world.cfg.xml and print it to /var/log/repose/current.log. -->
     for(HelloWorldMessage hwmess:helloworldMessages){ 
"A message: "+hwmess.getValue());
"~~~helloworldMessages end:");
          return filterDirector;


26. In, cut and paste the following content and save the file:

package org.openrepose.filters.helloworld;
import org.openrepose.commons.config.manager.UpdateListener;
import org.openrepose.filters.helloworld.config.HelloWorldMessage;
import org.openrepose.filters.helloworld.config.HelloWorldConfig;
import org.openrepose.core.filter.logic.AbstractConfiguredFilterHandlerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class HelloWorldHandlerFactory extends 
AbstractConfiguredFilterHandlerFactory<HelloWorldHandler> {
     <!-- List that holds all the messages from hello-world.cfg.xml. -->
     private List<HelloWorldMessage> helloworldMessages;
     public HelloWorldHandlerFactory() {
         helloworldMessages = new ArrayList<HelloWorldMessage>();   
     protected Map<Class,UpdateListener<?>> getListeners() {
         return new HashMap<Class, UpdateListener<?>>() {
               put(HelloWorldConfig.class, new HelloWorldConfigurationListener());

     private class HelloWorldConfigurationListener implements UpdateListener<HelloWorldConfig> {
          private boolean isInitialized = false;
          <!-- This class is generated from.xsd file created in step 18. -->
          public void configurationUpdated(HelloWorldConfig configurationObject) {
                <!-- This updates helloWorldMessages when ever /etc/repose/hello-world.cfg.xml 
                 is updated on the proxy server. -->
                 helloworldMessages = configurationObject.getMessages().getMessage();
          isInitialized = true;

          public boolean isInitialized() {
               return isInitialized;

          protected HelloWorldHandler buildHandler() {
               if (!this.isInitialized()) {
                    return null;
               return new HelloWorldHandler(helloworldMessages);


27. Right click on the pom.xml and select:

Run As > 1 Mavin build.


28. Edit filter-bundle/src/main/application/WEB-INF/web-fragment.xml:

29. Add this filter entry to the bottom of filter-bundle/src/main/application/WEB-INF/web-fragment.xml:


30. Edit filter-bundle/src/deb/control/conffiles.

31. Append the following content to the end of the file and save it:


32. Expand the filter-bundle folder and edit: filter-bundle/pom.xml.

33Cut and paste the following content as the last dependency in filter-bundle/pom.xml and save the file:


34. Expand the components-support folder:

35. Right click on the pom.xml file and select:

Run As > m2 1 Mavin build

If prompted, enter in the Goal: “clean install” and click on Run:

36. Expand the filter-bundle folder.

37. Right click on the target folder and select “Refresh”.

38.  Congrats, filter-bundle- contains your hello-world filter.

39. Log onto your server that the repose-proxy is installed on.

40. Run the command: 

cd /usr/share/repose/filters


41. Run the ls command. You should see something like this:


42. Copy your new filter bundle ear created in step 38 to your Repose proxy server in the same directory in step 40. Make sure you rename filter-bundle- to filter-bundle- so that you will overwrite the current file  /usr/share/repose/filters/filter-bundle- on the Repose proxy server.

43.  Run the command:

sudo vi /etc/repose/system-model.cfg.xml

44. In the <filters> section, add the following content:

<filter name="hello-world" />


The <filters> section should now look like:

   <filter name="http-logging" />   
   <filter name="ip-identity" />
   <filter name="header-identity" />
   <filter name="dist-datastore" />
   <filter name="rate-limiting" />
<filter name="hello-world" /> 


45. Save the file.


46. Create a new file named: /etc/repose/hello-world.cfg.xml.


47. Copy and paste the following content and save the file:

<?xml version="1.0" encoding="UTF-8"?>
<hello-world xmlns=''> 
     <message value="My Hello World!!!" />      

This is the same content in hello-world.cfg.xml that was created in step 15 above.


48. Run the command: 

sudo rm /var/log/repose/current.log


49. Run the command:

sudo service repose-valve stop

50. Run the command:

sudo service repose-valve start

51. Run the command:

sudo curl localhost:8080



Once again you will see output similar to:

<head><title>Document Moved</title></head>
<body><h1>Object Moved</h1>This document may be found <a


52.  Run the command:

sudo tail /var/log/repose/current.log


You should see something similar to:

2015-03-10 05:57:31,412 16763
[repose:repose_node1] INFO 
com.rackspace.papi.components.helloworld.HelloWorldHandler  - ~~~helloworldMessages begin:

2015-03-10 05:57:31,412 16763
[repose:repose_node1] INFO 
com.rackspace.papi.components.helloworld.HelloWorldHandler  - A message:
My Hello World!!!

2015-03-10 05:57:31,412 16763
[repose:repose_node1] INFO 
com.rackspace.papi.components.helloworld.HelloWorldHandler  - ~~~helloworldMessages end:

2015-03-10 06:06:41,000 566351
[repose:repose_node1] INFO 
com.rackspace.papi.components.helloworld.HelloWorldHandler  - ~~~helloworldMessages begin:

2015-03-10 06:06:41,000 566351
[repose:repose_node1] INFO  com.rackspace.papi.components.helloworld.HelloWorldHandler  - A message:
My Hello World!!!

2015-03-10 06:06:41,000 566351
[repose:repose_node1] INFO 
com.rackspace.papi.components.helloworld.HelloWorldHandler  - ~~~helloworldMessages end:


Notice that your message from hello-world.cfg.xml was printed! 

Congrats, you have reached your goal!







  • No labels


  1. I'm trying to follow this process with the latest version of Repose (  At step 22, no files are generated.  Is this process out of date?  I noticed the groupId has changed since this was written.  Is there a different process to generate a filter?

    1. The maven goal at step 22 should now be generate-resources.

    2. The artifact information was changed in Repose v7.0.0.1 as indicated in the Repose Release Notes.

    3. This page has been updated based on this question. Thanks for giving Repose a try. Let us know if you have any more questions.

      1. Thanks for responding.  I was able to get a custom filter built and I'll be able to use Repose as I was hoping.

        1. Hi Trent - I'm Repose dev manager... I'm glad you are using Repose.  Will you tell me a little bit about yourself?  What are you using Repose for - maybe the use case and product Repose is in front of?  If you ever need additional support, please feel free to reach out to us via wiki, or irc - freenode channel: #Repose. Thanks - Kari