changeset 1014:6be220a546db

Filters generalization in progress
author Devel 2
date Wed, 25 Mar 2020 11:02:10 +0100
parents f65876d67d33
children 518e5e10d714
files stress-tester/src/main/java/com/passus/st/ReaderMain.java stress-tester/src/main/java/com/passus/st/client/FlowContext.java stress-tester/src/main/java/com/passus/st/client/FlowWorkerBase.java stress-tester/src/main/java/com/passus/st/client/SynchFlowWorker.java stress-tester/src/main/java/com/passus/st/client/dns/filter/DnsRecordTypeFilter.java stress-tester/src/main/java/com/passus/st/client/filter/CounterFilter.java stress-tester/src/main/java/com/passus/st/client/filter/DefaultFlowFilterFactory.java stress-tester/src/main/java/com/passus/st/client/filter/FlowFilterFactory.java stress-tester/src/main/java/com/passus/st/client/filter/FlowFilterNodeDefinitionCreator.java stress-tester/src/main/java/com/passus/st/client/filter/FlowFilterPluginFactory.java stress-tester/src/main/java/com/passus/st/client/filter/MessagePredicate.java stress-tester/src/main/java/com/passus/st/client/filter/MessagePredicateNodeDefinition.java stress-tester/src/main/java/com/passus/st/client/filter/MessageWrapper.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpAbstractLoginFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpBasicAuthLoginFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCounterFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCounterListener.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpDigestAuthLoginFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpFilterMessagePredicateNodeDefinition.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpFiltersUtils.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpFormLoginFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpLogoutFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMarkFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMatchFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessageModificationFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessageModificationOperations.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessagePredicate.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessageWrapper.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpScopeModificationFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpSequenceFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpVarsFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpZoneFilter.java stress-tester/src/main/java/com/passus/st/emitter/RuleBasedSessionMapper.java stress-tester/src/test/java/com/passus/st/ConverterHttpClientTest.java stress-tester/src/test/java/com/passus/st/FilterScanner.java stress-tester/src/test/java/com/passus/st/client/dns/filter/DnsRecordTypeFilterTest.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpCounterFilterTest.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpFilterTestUtils.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpFormLoginFilterTest.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpLogoutFilterTest.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMarkFilterTest.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMatchFilterTest.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMessageModificationOperationsTest.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMessageWrapperTest.java stress-tester/src/test/java/com/passus/st/filter/HttpMessageValueExtractorTest.java stress-tester/src/test/java/com/passus/st/filter/HttpMessageWrapperDynamicExtractorTest.java stress-tester/src/test/java/com/passus/st/filter/HttpMessageWrapperStaticExtractorTest.java stress-tester/src/test/java/com/passus/st/vars/VarsConfiguratorTest.java
diffstat 48 files changed, 518 insertions(+), 689 deletions(-) [+]
line wrap: on
line diff
--- a/stress-tester/src/main/java/com/passus/st/ReaderMain.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/ReaderMain.java	Wed Mar 25 11:02:10 2020 +0100
@@ -6,7 +6,7 @@
 import com.passus.st.client.Event;
 import com.passus.st.client.SessionPayloadEvent;
 import com.passus.st.client.SessionStatusEvent;
-import com.passus.st.client.http.filter.HttpMessagePredicate;
+import com.passus.st.client.filter.MessagePredicate;
 import com.passus.st.emitter.SessionInfo;
 import com.passus.st.filter.Transformers;
 import com.passus.st.source.EventSource;
@@ -38,7 +38,7 @@
 
     private final HttpMessageHelper messageHelper = HttpMessageHelper.get();
 
-    private HttpMessagePredicate filter;
+    private MessagePredicate filter;
 
     private boolean decodeContent = false;
 
@@ -225,7 +225,7 @@
             if (cl.hasOption("f")) {
                 try {
                     Predicate predicate = Transformers.PREDICATE.transform(cl.getOptionValue("f"));
-                    filter = new HttpMessagePredicate(predicate);
+                    filter = new MessagePredicate(predicate);
                 } catch (Exception e) {
                     cliHelper.printError("Invalid filter expression. " + e.getMessage());
                 }
--- a/stress-tester/src/main/java/com/passus/st/client/FlowContext.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/FlowContext.java	Wed Mar 25 11:02:10 2020 +0100
@@ -153,8 +153,8 @@
         this.buffer = buffer;
     }
 
-    public boolean timeouted() {
-        return timeout != -1 && System.currentTimeMillis() > timeout;
+    public boolean timeouted(long now) {
+        return timeout != -1 && now > timeout;
     }
 
     public void setSentEvent(SessionPayloadEvent sentEvent) {
--- a/stress-tester/src/main/java/com/passus/st/client/FlowWorkerBase.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/FlowWorkerBase.java	Wed Mar 25 11:02:10 2020 +0100
@@ -115,59 +115,6 @@
         this.maxEncoderErrors = maxEncoderErrors;
     }
 
-
-
-    /*protected final void changeFlowState(FlowContext flowContext, int state) {
-        try {
-            if (flowContext.state() == state) {
-                return;
-            }
-
-            int oldState = flowContext.state();
-            if (logger.isDebugEnabled()) {
-                debug(flowContext, "Flow status changing {} -> {}.",
-                        contextStateToString(flowContext.state()),
-                        contextStateToString(state)
-                );
-            }
-
-            switch (state) {
-                case FlowContext.STATE_CONNECTING:
-                case FlowContext.STATE_CONNECTED:
-                case FlowContext.STATE_ERROR:
-                case FlowContext.STATE_RESP_RECEIVED:
-                case FlowContext.STATE_DISCONNECTING:
-                    throw new RuntimeException("Removed.");
-                    *//*if (flowContext.state() < FlowContext.STATE_DISCONNECTING) {
-                        if (flowContext.channelContext() != null) {
-                            try {
-                                flowContext.channelContext().close();
-                            } catch (Exception e) {
-                                if (logger.isDebugEnabled()) {
-                                    logger.debug(e.getMessage(), e);
-                                }
-                            }
-                        } else {
-                            changeFlowState(flowContext, STATE_DISCONNECTED);
-                        }
-                    } else {
-                        return;
-                    }*//*
-                case STATE_DISCONNECTED:
-                    flowContext.state(STATE_DISCONNECTED);
-                    flowContext.clear();
-                    removeFlowContext(flowContext);
-                    flowStateChanged(flowContext, oldState);
-                    return;
-            }
-
-            updateFlowState(flowContext, state, oldState);
-            throw new RuntimeException("Removed.");
-        } catch (Exception e) {
-            logger.debug(e.getMessage(), e);
-        }
-    }*/
-
     protected void flowStateChanged(FlowContext context, int oldState) {
 
     }
@@ -602,7 +549,7 @@
                     return false;
                 }
 
-                ByteBuff buffer = null;
+                ByteBuff buffer;
                 FlowHandler client = flowContext.client();
                 FlowHandlerDataEncoder encoder = client.getRequestEncoder(flowContext);
                 buffer = flowContext.buffer();
@@ -655,7 +602,7 @@
                 } else if (nextCheckTimeoutsTime > now) {
                     nextCheckTimeoutsTime = now + checkTimeoutsPeriod;
                     for (FlowContext flowContext : sessions.values()) {
-                        if (flowContext.timeouted()) {
+                        if (flowContext.timeouted(now)) {
                             if (logger.isDebugEnabled()) {
                                 debug(flowContext, "Flow for session '{}' timed out (state '{}').",
                                         flowContext.sessionInfo(),
--- a/stress-tester/src/main/java/com/passus/st/client/SynchFlowWorker.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/SynchFlowWorker.java	Wed Mar 25 11:02:10 2020 +0100
@@ -3,7 +3,6 @@
 import com.passus.commons.Assert;
 import com.passus.commons.annotations.Plugin;
 import com.passus.st.emitter.Emitter;
-import com.passus.st.emitter.SessionInfo;
 import com.passus.st.plugin.PluginConstants;
 
 import java.io.IOException;
--- a/stress-tester/src/main/java/com/passus/st/client/dns/filter/DnsRecordTypeFilter.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/dns/filter/DnsRecordTypeFilter.java	Wed Mar 25 11:02:10 2020 +0100
@@ -23,7 +23,7 @@
 @Plugin(name = DnsRecordTypeFilter.TYPE, category = PluginConstants.CATEGORY_FLOW_FILTER)
 public class DnsRecordTypeFilter extends DnsFilter {
 
-    public static final String TYPE = "dns.recordType";
+    public static final String TYPE = "dnsRecordType";
 
     private Set<DnsRecordType> recordTypes = new HashSet<>();
 
--- a/stress-tester/src/main/java/com/passus/st/client/filter/CounterFilter.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/filter/CounterFilter.java	Wed Mar 25 11:02:10 2020 +0100
@@ -6,16 +6,10 @@
 import com.passus.config.annotations.NodeDefinitionCreate;
 import com.passus.config.schema.NodeDefinition;
 import com.passus.config.schema.NodeDefinitionCreator;
-import com.passus.net.http.HttpRequest;
-import com.passus.net.http.HttpResponse;
 import com.passus.st.client.FlowContext;
-import com.passus.st.client.http.filter.HttpFilter;
-import com.passus.st.client.http.filter.HttpFilterMessagePredicateNodeDefinition;
-import com.passus.st.client.http.filter.HttpMessagePredicate;
 import com.passus.st.plugin.PluginConstants;
 
 import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Predicate;
 
 import static com.passus.config.schema.ConfigurationSchemaBuilder.*;
 
@@ -24,7 +18,7 @@
  * @author mikolaj.podbielski
  */
 @NodeDefinitionCreate(CounterFilter.NodeDefCreator.class)
-//@Plugin(name = CounterFilter.TYPE, category = PluginConstants.CATEGORY_FLOW_FILTER)
+@Plugin(name = CounterFilter.TYPE, category = PluginConstants.CATEGORY_FLOW_FILTER)
 public class CounterFilter implements FlowFilter {
 
     public static final String TYPE = "counter";
@@ -105,7 +99,7 @@
         @Override
         public NodeDefinition create() {
             return mapDef(
-                    tupleDef("applyIf", new HttpFilterMessagePredicateNodeDefinition()),
+                    tupleDef("applyIf", new MessagePredicateNodeDefinition()),
                     tupleDef("limit", valueDefInteger()),
                     tupleDef("name", valueDef()).setRequired(false)
             );
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/client/filter/DefaultFlowFilterFactory.java	Wed Mar 25 11:02:10 2020 +0100
@@ -0,0 +1,70 @@
+package com.passus.st.client.filter;
+
+import com.passus.net.http.HttpMessage;
+import com.passus.net.http.HttpRequest;
+import com.passus.net.http.HttpResponse;
+import com.passus.st.client.FlowContext;
+import com.passus.st.client.http.HttpFlowConst;
+import com.passus.st.client.http.HttpFlowContext;
+import com.passus.st.client.http.filter.HttpFilterMessageWrapper;
+import com.passus.st.client.http.filter.HttpFilterRequestWrapper;
+import com.passus.st.client.http.filter.HttpFilterResponseWrapper;
+import com.passus.st.client.http.filter.HttpMessageWrapper;
+
+import static com.passus.st.Protocols.HTTP;
+
+public final class DefaultFlowFilterFactory implements FlowFilterFactory {
+
+    @Override
+    public MessageWrapper createWrapper(Object req, Object resp, FlowContext context) {
+        if (req instanceof HttpRequest || resp instanceof HttpResponse) {
+            return createHttpMessageWrapper((HttpRequest) req, (HttpResponse) resp, context);
+        } else {
+            return new MessageWrapper(req, resp, context);
+        }
+    }
+
+    @Override
+    public MessageWrapper createWrapper(Object obj) {
+        if (obj instanceof HttpMessage) {
+            HttpMessage message = (HttpMessage) obj;
+            if (message.isRequest()) {
+                return createHttpMessageWrapper((HttpRequest) message, null, null);
+            } else {
+                return createHttpMessageWrapper(null, (HttpResponse) message, null);
+            }
+        } else {
+            return new MessageWrapper(obj, null, null);
+        }
+    }
+
+    public HttpMessageWrapper createHttpMessageWrapper(HttpRequest req, HttpResponse resp, FlowContext context) {
+        HttpFilterRequestWrapper reqWrapper = (HttpFilterRequestWrapper) createHttpMessageWrapper(req);
+        HttpFilterResponseWrapper respWrapper = (HttpFilterResponseWrapper) createHttpMessageWrapper(resp);
+
+        HttpFlowContext httpContext;
+        HttpFilterResponseWrapper origResp;
+        if (context != null) {
+            httpContext = context.getParamValue(HttpFlowConst.PARAM_HTTP_CONTEXT);
+            origResp = (HttpFilterResponseWrapper) createHttpMessageWrapper(httpContext.origResponse());
+        } else {
+            httpContext = null;
+            origResp = null;
+        }
+
+        return new HttpMessageWrapper(reqWrapper, respWrapper, context, origResp, httpContext);
+    }
+
+    public HttpFilterMessageWrapper createHttpMessageWrapper(HttpMessage message) {
+        if (message == null) {
+            return null;
+        }
+
+        if (message.isRequest()) {
+            return new HttpFilterRequestWrapper((HttpRequest) message);
+        } else {
+            return new HttpFilterResponseWrapper((HttpResponse) message);
+        }
+    }
+
+}
--- a/stress-tester/src/main/java/com/passus/st/client/filter/FlowFilterFactory.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/filter/FlowFilterFactory.java	Wed Mar 25 11:02:10 2020 +0100
@@ -1,24 +1,18 @@
 package com.passus.st.client.filter;
 
-import com.passus.commons.plugin.PluginFactory;
-import com.passus.st.plugin.PluginConstants;
-
-/**
- * @author Mirosław Hawrot
- */
-public final class FlowFilterFactory extends PluginFactory<FlowFilter> {
-
-    private static FlowFilterFactory instance;
+import com.passus.net.http.HttpRequest;
+import com.passus.net.http.HttpResponse;
+import com.passus.st.client.FlowContext;
+import com.passus.st.client.http.filter.HttpMessageWrapper;
 
-    public FlowFilterFactory() {
-        super(PluginConstants.CATEGORY_FLOW_FILTER, FlowFilter.class);
-    }
+public interface FlowFilterFactory {
 
-    public static synchronized FlowFilterFactory getInstance() {
-        if (instance == null) {
-            instance = new FlowFilterFactory();
-        }
+    FlowFilterFactory DEFAULT_FACTORY = new DefaultFlowFilterFactory();
 
-        return instance;
-    }
+    MessageWrapper createWrapper(Object req, Object resp, FlowContext context);
+
+    MessageWrapper createWrapper(Object obj);
+
+    HttpMessageWrapper createHttpMessageWrapper(HttpRequest req, HttpResponse resp, FlowContext context);
+
 }
--- a/stress-tester/src/main/java/com/passus/st/client/filter/FlowFilterNodeDefinitionCreator.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/filter/FlowFilterNodeDefinitionCreator.java	Wed Mar 25 11:02:10 2020 +0100
@@ -10,7 +10,7 @@
 public class FlowFilterNodeDefinitionCreator implements NodeDefinitionCreator {
 
     public static NodeDefinition createFiltersList(boolean transformToObject) {
-        return new DynaKeyValueVaryListNodeDefinition("type", FlowFilterFactory.getInstance())
+        return new DynaKeyValueVaryListNodeDefinition("type", FlowFilterPluginFactory.getInstance())
                 .setTransformToPluginObject(transformToObject);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/client/filter/FlowFilterPluginFactory.java	Wed Mar 25 11:02:10 2020 +0100
@@ -0,0 +1,24 @@
+package com.passus.st.client.filter;
+
+import com.passus.commons.plugin.PluginFactory;
+import com.passus.st.plugin.PluginConstants;
+
+/**
+ * @author Mirosław Hawrot
+ */
+public final class FlowFilterPluginFactory extends PluginFactory<FlowFilter> {
+
+    private static FlowFilterPluginFactory instance;
+
+    public FlowFilterPluginFactory() {
+        super(PluginConstants.CATEGORY_FLOW_FILTER, FlowFilter.class);
+    }
+
+    public static synchronized FlowFilterPluginFactory getInstance() {
+        if (instance == null) {
+            instance = new FlowFilterPluginFactory();
+        }
+
+        return instance;
+    }
+}
--- a/stress-tester/src/main/java/com/passus/st/client/filter/MessagePredicate.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/filter/MessagePredicate.java	Wed Mar 25 11:02:10 2020 +0100
@@ -4,18 +4,28 @@
 import com.passus.commons.ConversionException;
 import com.passus.config.NodeException;
 import com.passus.st.client.FlowContext;
-import com.passus.st.client.http.filter.HttpMessagePredicate;
+import com.passus.st.filter.Transformers;
 
 import java.io.IOException;
 import java.util.function.Predicate;
 
+import static com.passus.st.client.filter.FlowFilterFactory.DEFAULT_FACTORY;
+
 public class MessagePredicate<T> implements Predicate<T> {
 
-    private final Predicate predicate;
+    protected final Predicate predicate;
+
+    protected final FlowFilterFactory filterFactory;
 
     public MessagePredicate(Predicate predicate) {
+        this(predicate, DEFAULT_FACTORY);
+    }
+
+    public MessagePredicate(Predicate predicate, FlowFilterFactory filterFactory) {
         Assert.notNull(predicate, "predicate");
+        Assert.notNull(filterFactory, "filterFactory");
         this.predicate = predicate;
+        this.filterFactory = filterFactory;
     }
 
     public Predicate getPredicate() {
@@ -23,8 +33,7 @@
     }
 
     public boolean test(Object req, Object resp, FlowContext context) {
-        throw new RuntimeException("Not implemented.");
-        //return test(new HttpMessageWrapper(req, resp, context));
+        return test(filterFactory.createWrapper(req, resp, context));
     }
 
     public boolean test(MessageWrapper wrapper) {
@@ -33,15 +42,7 @@
 
     @Override
     public boolean test(T message) {
-        /*HttpMessageWrapper wrapper;
-        if (message.isRequest()) {
-            wrapper = new HttpMessageWrapper((HttpRequest) message, null, null);
-        } else {
-            wrapper = new HttpMessageWrapper(null, (HttpResponse) message, null);
-        }
-
-        return predicate.test(wrapper);*/
-        throw new RuntimeException("Not implemented.");
+        return predicate.test(filterFactory.createWrapper(message));
     }
 
     @Override
@@ -49,10 +50,8 @@
         return predicate.toString();
     }
 
-    public static HttpMessagePredicate parse(String content) throws ConversionException, IOException, NodeException {
-        /*Predicate predicate = Transformers.PREDICATE.transform(content);
-        return new HttpMessagePredicate(predicate);*/
-
-        throw new RuntimeException("Not implemented.");
+    public static MessagePredicate parse(String content) throws ConversionException, IOException, NodeException {
+        Predicate predicate = Transformers.PREDICATE.transform(content);
+        return new MessagePredicate(predicate);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/client/filter/MessagePredicateNodeDefinition.java	Wed Mar 25 11:02:10 2020 +0100
@@ -0,0 +1,80 @@
+package com.passus.st.client.filter;
+
+import com.passus.commons.ConversionException;
+import com.passus.commons.utils.ArrayUtils;
+import com.passus.config.*;
+import com.passus.config.schema.NodeDefinition;
+import com.passus.config.validation.Errors;
+import com.passus.filter.config.PredicateNodeTransformer;
+import com.passus.lookup.filter.LookupKeyExistsLeftOperatorTransformer;
+import com.passus.lookup.filter.LookupValueExtractorTransformer;
+import com.passus.st.filter.Transformers;
+
+import java.util.Set;
+import java.util.function.Predicate;
+
+import static com.passus.config.validation.ValidationDefaultMessages.GENERAL_CONVERSION_ERROR;
+
+/**
+ * @author Mirosław Hawrot
+ */
+public class MessagePredicateNodeDefinition extends NodeDefinition<MessagePredicateNodeDefinition> {
+
+    private static final PredicateNodeTransformer TRANSFORMER = Transformers.PREDICATE;
+
+    private final static Set<Class<? extends CNode>> SUPPORTED = ArrayUtils.asUnmodifiableSet(CListNode.class, CMapNode.class);
+
+    @Override
+    public Set<Class<? extends CNode>> getSupportedNode() {
+        return SUPPORTED;
+    }
+
+    @Override
+    protected void doValidate(CNode node, Errors errors, ConfigurationContext context) {
+        try {
+            // TODO: refactor
+            LookupKeyExistsLeftOperatorTransformer lookupKeyExistsTransformer = Transformers.lookupKeyExistsTransformer(context);
+            LookupValueExtractorTransformer lookupValueTransformer = Transformers.lookupValueTransformer(context);
+            TRANSFORMER.addLeftOperatorTransformer(lookupKeyExistsTransformer);
+            TRANSFORMER.addValueExtractorTransformer(lookupValueTransformer);
+            TRANSFORMER.transform(node);
+            TRANSFORMER.removeLeftOperatorTransformer(lookupKeyExistsTransformer);
+            TRANSFORMER.removeValueExtractorTransformer(lookupValueTransformer);
+        } catch (NodeConversionException ex) {
+            errors.reject(node, ex.getMessage());
+        } catch (ConversionException ex) {
+            errors.reject(node, GENERAL_CONVERSION_ERROR);
+        }
+    }
+
+    @Override
+    protected CNode doTransform(CNode node, Errors errors, ConfigurationContext context, boolean reverse) {
+        if (reverse) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        } else {
+            try {
+                // TODO: refactor
+                LookupKeyExistsLeftOperatorTransformer lookupKeyExistsTransformer = Transformers.lookupKeyExistsTransformer(context);
+                LookupValueExtractorTransformer lookupValueTransformer = Transformers.lookupValueTransformer(context);
+                TRANSFORMER.addLeftOperatorTransformer(lookupKeyExistsTransformer);
+                TRANSFORMER.addValueExtractorTransformer(lookupValueTransformer);
+                Predicate predicate = TRANSFORMER.transform(node);
+                TRANSFORMER.removeLeftOperatorTransformer(lookupKeyExistsTransformer);
+                TRANSFORMER.removeValueExtractorTransformer(lookupValueTransformer);
+                return new CValueNode(new MessagePredicate(predicate));
+            } catch (NodeConversionException ex) {
+                errors.reject(node, ex.getMessage());
+            } catch (ConversionException ex) {
+                errors.reject(node, GENERAL_CONVERSION_ERROR);
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    protected boolean doEquals(CNode node1, CNode node2) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+}
--- a/stress-tester/src/main/java/com/passus/st/client/filter/MessageWrapper.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/filter/MessageWrapper.java	Wed Mar 25 11:02:10 2020 +0100
@@ -1,14 +1,19 @@
 package com.passus.st.client.filter;
 
+import com.passus.st.client.FlowContext;
+
 public class MessageWrapper<R, S> {
 
-    private final R req;
+    protected final R req;
 
-    private final S resp;
+    protected final S resp;
 
-    public MessageWrapper(R req, S resp) {
+    protected final FlowContext context;
+
+    public MessageWrapper(R req, S resp, FlowContext context) {
         this.req = req;
         this.resp = resp;
+        this.context = context;
     }
 
     public R getReq() {
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpAbstractLoginFilter.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpAbstractLoginFilter.java	Wed Mar 25 11:02:10 2020 +0100
@@ -4,10 +4,6 @@
 import com.passus.config.Configuration;
 import com.passus.config.ConfigurationContext;
 import com.passus.config.annotations.NodeDefinitionCreate;
-import static com.passus.config.schema.ConfigurationSchemaBuilder.mapDef;
-import static com.passus.config.schema.ConfigurationSchemaBuilder.tupleDef;
-import static com.passus.st.client.http.filter.HttpFlowUtils.extractHttpContext;
-
 import com.passus.config.schema.KeyNameVaryListNodeDefinition;
 import com.passus.config.schema.MapNodeDefinition;
 import com.passus.config.schema.NodeDefinition;
@@ -21,25 +17,39 @@
 import com.passus.st.client.credentials.CredentialsProvider.ProviderContext;
 import com.passus.st.client.credentials.CredentialsProviderFactory;
 import com.passus.st.client.credentials.MultiCredentialsProviderTransformer;
+import com.passus.st.client.filter.FlowFilterFactory;
+import com.passus.st.client.filter.MessagePredicate;
+import com.passus.st.client.filter.MessagePredicateNodeDefinition;
 
 import java.util.Collection;
 
+import static com.passus.config.schema.ConfigurationSchemaBuilder.mapDef;
+import static com.passus.config.schema.ConfigurationSchemaBuilder.tupleDef;
+import static com.passus.st.client.http.filter.HttpFlowUtils.extractHttpContext;
+
 /**
- *
  * @author mikolaj.podbielski
  */
 public abstract class HttpAbstractLoginFilter extends HttpFilter {
 
     protected CredentialsProvider credentialsProvider;
 
-    protected HttpMessagePredicate predicate;
+    protected MessagePredicate predicate;
+
+    protected final FlowFilterFactory filterFactory;
 
     public HttpAbstractLoginFilter() {
+        this(null, null);
     }
 
-    public HttpAbstractLoginFilter(CredentialsProvider credentialsProvider, HttpMessagePredicate predicate) {
+    public HttpAbstractLoginFilter(CredentialsProvider credentialsProvider, MessagePredicate predicate) {
+        this(credentialsProvider, predicate, FlowFilterFactory.DEFAULT_FACTORY);
+    }
+
+    public HttpAbstractLoginFilter(CredentialsProvider credentialsProvider, MessagePredicate predicate, FlowFilterFactory filterFactory) {
         this.credentialsProvider = credentialsProvider;
         this.predicate = predicate;
+        this.filterFactory = filterFactory;
     }
 
     public CredentialsProvider getCredentialsProvider() {
@@ -50,18 +60,18 @@
         return credentialsProvider == null ? null : credentialsProvider.getCredentials(context);
     }
 
-    public HttpMessagePredicate getPredicate() {
+    public MessagePredicate getPredicate() {
         return predicate;
     }
 
-    public void setPredicate(HttpMessagePredicate predicate) {
+    public void setPredicate(MessagePredicate predicate) {
         this.predicate = predicate;
     }
 
     @Override
     public void configure(Configuration config, ConfigurationContext context) {
-        predicate = (HttpMessagePredicate) config.get("applyIf");
-        credentialsProvider = (CredentialsProvider) config.get("provider", null);
+        predicate = (MessagePredicate) config.get("applyIf");
+        credentialsProvider = config.get("provider", null);
     }
 
     protected void blockConversation(HttpRequest request, FlowContext context) {
@@ -72,7 +82,7 @@
 
     @Override
     public final int filterOutbound(HttpRequest request, HttpResponse resp, FlowContext context) {
-        if (predicate == null || predicate.test(new HttpMessageWrapper(request, resp, context))) {
+        if (predicate == null || predicate.test(filterFactory.createWrapper(request, resp, context))) {
             doFilterOutbound(request, resp, context);
         } else {
             blockConversation(request, context);
@@ -109,7 +119,7 @@
 
         private static KeyNameVaryListNodeDefinition providersNodeDef;
 
-        private static HttpFilterMessagePredicateNodeDefinition filterMessagePredicateNodeDefinition = new HttpFilterMessagePredicateNodeDefinition();
+        private static MessagePredicateNodeDefinition messagePredicateNodeDefinition = new MessagePredicateNodeDefinition();
 
         private static NodeDefinition providersNodeDef() {
             if (providersNodeDef == null) {
@@ -146,7 +156,7 @@
 
         public final MapNodeDefinition create(boolean applyIfRequired, boolean providerRequired) {
             MapNodeDefinition mapDef = mapDef().setCanBeEmpty(true);
-            mapDef.add(tupleDef("applyIf", filterMessagePredicateNodeDefinition).setRequired(applyIfRequired));
+            mapDef.add(tupleDef("applyIf", messagePredicateNodeDefinition).setRequired(applyIfRequired));
             mapDef.add(tupleDef("provider", providersNodeDef()).setRequired(providerRequired));
             return mapDef;
         }
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpBasicAuthLoginFilter.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpBasicAuthLoginFilter.java	Wed Mar 25 11:02:10 2020 +0100
@@ -16,6 +16,7 @@
 import static com.passus.st.client.http.HttpConsts.PARAM_USERNAME;
 import static com.passus.st.client.http.filter.HttpFlowUtils.extractHttpContext;
 
+import com.passus.st.client.filter.MessagePredicate;
 import com.passus.st.client.http.HttpScopes;
 import com.passus.st.plugin.PluginConstants;
 import java.nio.charset.Charset;
@@ -41,7 +42,7 @@
     public HttpBasicAuthLoginFilter() {
     }
 
-    public HttpBasicAuthLoginFilter(CredentialsProvider credentialsProvider, HttpMessagePredicate predicate) {
+    public HttpBasicAuthLoginFilter(CredentialsProvider credentialsProvider, MessagePredicate predicate) {
         super(credentialsProvider, predicate);
     }
 
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCounterFilter.java	Tue Mar 24 14:36:47 2020 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-package com.passus.st.client.http.filter;
-
-import com.passus.commons.annotations.Plugin;
-import com.passus.config.Configuration;
-import com.passus.config.ConfigurationContext;
-import com.passus.config.annotations.NodeDefinitionCreate;
-import com.passus.config.schema.NodeDefinition;
-import com.passus.config.schema.NodeDefinitionCreator;
-import com.passus.net.http.HttpRequest;
-import com.passus.net.http.HttpResponse;
-import com.passus.st.client.FlowContext;
-import com.passus.st.plugin.PluginConstants;
-
-import java.util.concurrent.atomic.AtomicInteger;
-
-import static com.passus.config.schema.ConfigurationSchemaBuilder.*;
-
-/**
- *
- * @author mikolaj.podbielski
- */
-@NodeDefinitionCreate(HttpCounterFilter.NodeDefCreator.class)
-@Plugin(name = HttpCounterFilter.TYPE, category = PluginConstants.CATEGORY_FLOW_FILTER)
-public class HttpCounterFilter extends HttpFilter {
-
-    public static final String TYPE = "counter";
-
-    private static final AtomicInteger ID = new AtomicInteger();
-
-    private HttpMessagePredicate predicate;
-    private String name;
-    private int limit;
-    private HttpCounterListener listener = (e) -> {
-    };
-
-    private int count;
-
-    HttpMessagePredicate getPredicate() {
-        return predicate;
-    }
-
-    void setPredicate(HttpMessagePredicate predicate) {
-        this.predicate = predicate;
-    }
-
-    String getName() {
-        return name;
-    }
-
-    void setName(String name) {
-        this.name = name;
-    }
-
-    int getLimit() {
-        return limit;
-    }
-
-    void setLimit(int limit) {
-        this.limit = limit;
-    }
-
-    HttpCounterListener getListener() {
-        return listener;
-    }
-
-    void setListener(HttpCounterListener listener) {
-        this.listener = listener;
-    }
-
-    @Override
-    public void configure(Configuration config, ConfigurationContext context) {
-        predicate = (HttpMessagePredicate) config.get("applyIf");
-        limit = config.getInteger("limit");
-        name = config.getString("name", "counter_" + ID.getAndIncrement());
-        // TODO:
-        listener = System.out::println;
-    }
-
-    @Override
-    public int filterInbound(HttpRequest req, HttpResponse resp, FlowContext context) {
-        if (predicate.test(req, resp, context)) {
-            if (++count >= limit) {
-                listener.limitReached(new HttpCounterListener.Event(this));
-            }
-        }
-        return DUNNO;
-    }
-
-    @Override
-    public HttpCounterFilter instanceForWorker(int index) {
-        HttpCounterFilter filter = new HttpCounterFilter();
-        filter.predicate = predicate;
-        filter.name = name;
-        filter.limit = limit;
-        filter.listener = listener;
-        return filter;
-    }
-
-    public static class NodeDefCreator implements NodeDefinitionCreator {
-
-        @Override
-        public NodeDefinition create() {
-            return mapDef(
-                    tupleDef("applyIf", new HttpFilterMessagePredicateNodeDefinition()),
-                    tupleDef("limit", valueDefInteger()),
-                    tupleDef("name", valueDef()).setRequired(false)
-            );
-        }
-
-    }
-}
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCounterListener.java	Tue Mar 24 14:36:47 2020 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-package com.passus.st.client.http.filter;
-
-/**
- *
- * @author mikolaj.podbielski
- */
-public interface HttpCounterListener {
-    
-    public void limitReached(Event event);
-    
-    public static final class Event {
-        private final HttpCounterFilter filter;
-//        HttpRequest req
-
-        public Event(HttpCounterFilter filter) {
-            this.filter = filter;
-        }
-        
-    }
-}
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpDigestAuthLoginFilter.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpDigestAuthLoginFilter.java	Wed Mar 25 11:02:10 2020 +0100
@@ -20,6 +20,7 @@
 import static com.passus.st.client.http.HttpConsts.PARAM_USERNAME;
 import static com.passus.st.client.http.filter.HttpFlowUtils.extractHttpContext;
 
+import com.passus.st.client.filter.MessagePredicate;
 import com.passus.st.client.http.HttpFlowContext;
 import com.passus.st.plugin.PluginConstants;
 import java.util.HashMap;
@@ -55,7 +56,7 @@
     public HttpDigestAuthLoginFilter() {
     }
 
-    public HttpDigestAuthLoginFilter(CredentialsProvider credentialsProvider, HttpMessagePredicate predicate) {
+    public HttpDigestAuthLoginFilter(CredentialsProvider credentialsProvider, MessagePredicate predicate) {
         super(credentialsProvider, predicate);
     }
 
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpFilterMessagePredicateNodeDefinition.java	Tue Mar 24 14:36:47 2020 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-package com.passus.st.client.http.filter;
-
-import com.passus.commons.ConversionException;
-import com.passus.commons.utils.ArrayUtils;
-import com.passus.config.CListNode;
-import com.passus.config.CMapNode;
-import com.passus.config.CNode;
-import com.passus.config.CValueNode;
-import com.passus.config.ConfigurationContext;
-import com.passus.config.NodeConversionException;
-import com.passus.config.schema.NodeDefinition;
-import com.passus.config.validation.Errors;
-import static com.passus.config.validation.ValidationDefaultMessages.GENERAL_CONVERSION_ERROR;
-import com.passus.filter.config.PredicateNodeTransformer;
-import com.passus.lookup.filter.LookupKeyExistsLeftOperatorTransformer;
-import com.passus.lookup.filter.LookupValueExtractorTransformer;
-import com.passus.st.filter.Transformers;
-import java.util.Set;
-import java.util.function.Predicate;
-
-/**
- *
- * @author Mirosław Hawrot
- */
-public class HttpFilterMessagePredicateNodeDefinition extends NodeDefinition<HttpFilterMessagePredicateNodeDefinition> {
-
-    private static final PredicateNodeTransformer TRANSFORMER = Transformers.PREDICATE;
-
-    private final static Set<Class<? extends CNode>> SUPPORTED = ArrayUtils.asUnmodifiableSet(CListNode.class, CMapNode.class);
-
-    @Override
-    public Set<Class<? extends CNode>> getSupportedNode() {
-        return SUPPORTED;
-    }
-
-    @Override
-    protected void doValidate(CNode node, Errors errors, ConfigurationContext context) {
-        try {
-            // TODO: refactor
-            LookupKeyExistsLeftOperatorTransformer lookupKeyExistsTransformer = Transformers.lookupKeyExistsTransformer(context);
-            LookupValueExtractorTransformer lookupValueTransformer = Transformers.lookupValueTransformer(context);
-            TRANSFORMER.addLeftOperatorTransformer(lookupKeyExistsTransformer);
-            TRANSFORMER.addValueExtractorTransformer(lookupValueTransformer);
-            TRANSFORMER.transform(node);
-            TRANSFORMER.removeLeftOperatorTransformer(lookupKeyExistsTransformer);
-            TRANSFORMER.removeValueExtractorTransformer(lookupValueTransformer);
-        } catch (NodeConversionException ex) {
-            errors.reject(node, ex.getMessage());
-        } catch (ConversionException ex) {
-            errors.reject(node, GENERAL_CONVERSION_ERROR);
-        }
-    }
-
-    @Override
-    protected CNode doTransform(CNode node, Errors errors, ConfigurationContext context, boolean reverse) {
-        if (reverse) {
-
-        } else {
-            try {
-                // TODO: refactor
-                LookupKeyExistsLeftOperatorTransformer lookupKeyExistsTransformer = Transformers.lookupKeyExistsTransformer(context);
-                LookupValueExtractorTransformer lookupValueTransformer = Transformers.lookupValueTransformer(context);
-                TRANSFORMER.addLeftOperatorTransformer(lookupKeyExistsTransformer);
-                TRANSFORMER.addValueExtractorTransformer(lookupValueTransformer);
-                Predicate predicate = TRANSFORMER.transform(node);
-                TRANSFORMER.removeLeftOperatorTransformer(lookupKeyExistsTransformer);
-                TRANSFORMER.removeValueExtractorTransformer(lookupValueTransformer);
-                return new CValueNode(new HttpMessagePredicate(predicate));
-            } catch (NodeConversionException ex) {
-                errors.reject(node, ex.getMessage());
-            } catch (ConversionException ex) {
-                errors.reject(node, GENERAL_CONVERSION_ERROR);
-            }
-        }
-
-        return null;
-    }
-
-    @Override
-    protected boolean doEquals(CNode node1, CNode node2) {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
-}
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpFiltersUtils.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpFiltersUtils.java	Wed Mar 25 11:02:10 2020 +0100
@@ -5,6 +5,8 @@
 import com.passus.net.http.HttpRequest;
 import com.passus.net.http.HttpResponse;
 import com.passus.st.client.FlowContext;
+import com.passus.st.client.filter.FlowFilterFactory;
+import com.passus.st.client.filter.MessageWrapper;
 import com.passus.st.client.http.HttpFlowContext;
 
 /**
@@ -16,12 +18,13 @@
     private HttpFiltersUtils() {
     }
 
-    public static Object extractValue(ValueExtractor extractor, HttpRequest req, HttpResponse resp, FlowContext context) {
+    public static Object extractValue(ValueExtractor extractor, HttpRequest req, HttpResponse resp,
+                                      FlowContext context, FlowFilterFactory filterFactory) {
         Object value;
         if (extractor instanceof UnmutableValueExtractor) {
             value = extractor.extract(null);
         } else {
-            HttpMessageWrapper wrapper = new HttpMessageWrapper(req, resp, context);
+            MessageWrapper wrapper = filterFactory.createWrapper(req, resp, context);
             value = extractor.extract(wrapper);
         }
 
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpFormLoginFilter.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpFormLoginFilter.java	Wed Mar 25 11:02:10 2020 +0100
@@ -11,6 +11,7 @@
 import com.passus.st.client.credentials.Credentials;
 import com.passus.st.client.credentials.CredentialsProvider;
 import com.passus.st.client.credentials.CredentialsProvider.ProviderContext;
+import com.passus.st.client.filter.MessagePredicate;
 import com.passus.st.client.http.HttpScopes;
 import com.passus.st.plugin.PluginConstants;
 import org.apache.logging.log4j.LogManager;
@@ -40,7 +41,7 @@
     public HttpFormLoginFilter() {
     }
 
-    public HttpFormLoginFilter(CredentialsProvider credentialsProvider, HttpMessagePredicate predicate, CharSequence userField, CharSequence passwordField) {
+    public HttpFormLoginFilter(CredentialsProvider credentialsProvider, MessagePredicate predicate, CharSequence userField, CharSequence passwordField) {
         super(credentialsProvider, predicate);
         this.userField = userField;
         this.passwordField = passwordField;
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpLogoutFilter.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpLogoutFilter.java	Wed Mar 25 11:02:10 2020 +0100
@@ -10,6 +10,8 @@
 import com.passus.net.http.HttpResponse;
 import com.passus.st.ParametersBag;
 import com.passus.st.client.FlowContext;
+import com.passus.st.client.filter.MessagePredicate;
+import com.passus.st.client.filter.MessagePredicateNodeDefinition;
 import com.passus.st.client.http.HttpScopes;
 import com.passus.st.plugin.PluginConstants;
 
@@ -29,12 +31,12 @@
 
     private boolean invalidateSession = true;
 
-    private HttpMessagePredicate predicate;
+    private MessagePredicate predicate;
 
     public HttpLogoutFilter() {
     }
 
-    public HttpLogoutFilter(HttpMessagePredicate predicate, boolean invalidateSession) {
+    public HttpLogoutFilter(MessagePredicate predicate, boolean invalidateSession) {
         this.predicate = predicate;
         this.invalidateSession = invalidateSession;
     }
@@ -47,17 +49,17 @@
         this.invalidateSession = invalidateSession;
     }
 
-    public HttpMessagePredicate getPredicate() {
+    public MessagePredicate getPredicate() {
         return predicate;
     }
 
-    public void setPredicate(HttpMessagePredicate predicate) {
+    public void setPredicate(MessagePredicate predicate) {
         this.predicate = predicate;
     }
 
     @Override
     public void configure(Configuration config, ConfigurationContext context) {
-        predicate = (HttpMessagePredicate) config.get("applyIf");
+        predicate = (MessagePredicate) config.get("applyIf");
         invalidateSession = config.getBoolean("invalidateSession", true);
     }
 
@@ -96,7 +98,7 @@
 
             return mapDef(
                     tupleDef("invalidateSession", valueDefBool()).setRequired(false),
-                    tupleDef("applyIf", new HttpFilterMessagePredicateNodeDefinition())
+                    tupleDef("applyIf", new MessagePredicateNodeDefinition())
             );
         }
 
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMarkFilter.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMarkFilter.java	Wed Mar 25 11:02:10 2020 +0100
@@ -2,18 +2,8 @@
 
 import com.passus.commons.Assert;
 import com.passus.commons.annotations.Plugin;
-import com.passus.config.CMapNode;
-import com.passus.config.CNode;
-import com.passus.config.CTupleNode;
-import com.passus.config.CValueNode;
-import com.passus.config.Configuration;
-import com.passus.config.ConfigurationContext;
-import com.passus.config.ConfigurationUtils;
+import com.passus.config.*;
 import com.passus.config.annotations.NodeDefinitionCreate;
-import static com.passus.config.schema.ConfigurationSchemaBuilder.listDef;
-import static com.passus.config.schema.ConfigurationSchemaBuilder.mapDef;
-import static com.passus.config.schema.ConfigurationSchemaBuilder.tupleDef;
-import static com.passus.config.schema.ConfigurationSchemaBuilder.valueDef;
 import com.passus.config.schema.MapNodeDefinition;
 import com.passus.config.schema.NodeDefinition;
 import com.passus.config.schema.NodeDefinitionCreator;
@@ -22,19 +12,23 @@
 import com.passus.filter.config.PredicateNodeTransformer;
 import com.passus.net.http.HttpRequest;
 import com.passus.net.http.HttpResponse;
-import static com.passus.st.client.http.HttpConsts.TAG_MARKER;
-
 import com.passus.st.client.FlowContext;
+import com.passus.st.client.filter.MessagePredicate;
+import com.passus.st.client.filter.MessagePredicateNodeDefinition;
+import com.passus.st.client.filter.MessageWrapper;
 import com.passus.st.filter.Transformers;
 import com.passus.st.plugin.PluginConstants;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.function.Predicate;
 
+import static com.passus.config.schema.ConfigurationSchemaBuilder.*;
+import static com.passus.st.client.http.HttpConsts.TAG_MARKER;
+
 /**
- *
  * @author Mirosław Hawrot
  */
 @NodeDefinitionCreate(HttpMarkFilter.HttpMarkFilterNodeDefCreator.class)
@@ -84,7 +78,7 @@
     @Override
     public int filterInbound(HttpRequest req, HttpResponse resp, FlowContext context) {
         if (!markRules.isEmpty()) {
-            HttpMessageWrapper wrapper = new HttpMessageWrapper(req, resp, context);
+            MessageWrapper wrapper = new MessageWrapper(req, resp, context);
             for (MarkerRule rule : markRules) {
                 if (rule.predicate.test(wrapper)) {
                     List<Marker> markers = (List<Marker>) req.getTag(TAG_MARKER);
@@ -135,17 +129,17 @@
 
         private final Marker marker;
 
-        private final HttpMessagePredicate predicate;
+        private final MessagePredicate predicate;
 
-        public MarkerRule(String category, HttpMessagePredicate predicate) {
+        public MarkerRule(String category, MessagePredicate predicate) {
             this(new Marker(category), predicate);
         }
 
-        public MarkerRule(String category, HttpMessagePredicate predicate, String message) {
+        public MarkerRule(String category, MessagePredicate predicate, String message) {
             this(new Marker(category, message), predicate);
         }
 
-        public MarkerRule(Marker tag, HttpMessagePredicate predicate) {
+        public MarkerRule(Marker tag, MessagePredicate predicate) {
             Assert.notNull(tag, "tag");
             Assert.notNull(predicate, "predicate");
             this.marker = tag;
@@ -156,7 +150,7 @@
             return marker;
         }
 
-        public HttpMessagePredicate getPredicate() {
+        public MessagePredicate getPredicate() {
             return predicate;
         }
 
@@ -169,7 +163,7 @@
             MapNodeDefinition markerRuleNodeDef = mapDef(
                     tupleDef("category", valueDef()),
                     tupleDef("message", valueDef().setRequired(false)),
-                    tupleDef("applyIf", new HttpFilterMessagePredicateNodeDefinition())
+                    tupleDef("applyIf", new MessagePredicateNodeDefinition())
             ).setTransformer(new MarkerRuleNodeTransformer());
 
             return mapDef(
@@ -196,7 +190,7 @@
 
             String category = null;
             String message = null;
-            HttpMessagePredicate applyIf = null;
+            MessagePredicate applyIf = null;
 
             for (CTupleNode tuple : tuples) {
                 String opName = tuple.getName();
@@ -210,7 +204,7 @@
                             break;
                         case "applyif":
                             Predicate predicate = PREDICATE_TRANS.transform(tuple.getNode());
-                            applyIf = new HttpMessagePredicate(predicate);
+                            applyIf = new MessagePredicate(predicate);
                             break;
                         default:
                             throw new IllegalArgumentException("Unknwon parameter '" + opName + "'.");
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMatchFilter.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMatchFilter.java	Wed Mar 25 11:02:10 2020 +0100
@@ -1,5 +1,6 @@
 package com.passus.st.client.http.filter;
 
+import com.passus.commons.Assert;
 import com.passus.commons.annotations.Plugin;
 import com.passus.config.Configuration;
 import com.passus.config.ConfigurationContext;
@@ -9,6 +10,9 @@
 import com.passus.net.http.HttpRequest;
 import com.passus.net.http.HttpResponse;
 import com.passus.st.client.FlowContext;
+import com.passus.st.client.filter.FlowFilterFactory;
+import com.passus.st.client.filter.MessagePredicate;
+import com.passus.st.client.filter.MessagePredicateNodeDefinition;
 import com.passus.st.plugin.PluginConstants;
 
 import static com.passus.config.schema.ConfigurationSchemaBuilder.*;
@@ -22,15 +26,26 @@
 
     public static final String TYPE = "matcher";
 
-    private HttpMessagePredicate predicate;
+    private MessagePredicate predicate;
 
     private boolean acceptOnMatch = true;
 
-    public HttpMessagePredicate getPredicate() {
+    private final FlowFilterFactory filterFactory;
+
+    public HttpMatchFilter() {
+        this(FlowFilterFactory.DEFAULT_FACTORY);
+    }
+
+    public HttpMatchFilter(FlowFilterFactory filterFactory) {
+        Assert.notNull(filterFactory, "filterFactory");
+        this.filterFactory = filterFactory;
+    }
+
+    public MessagePredicate getPredicate() {
         return predicate;
     }
 
-    public void setPredicate(HttpMessagePredicate predicate) {
+    public void setPredicate(MessagePredicate predicate) {
         this.predicate = predicate;
     }
 
@@ -44,7 +59,7 @@
 
     @Override
     public void configure(Configuration config, ConfigurationContext context) {
-        predicate = (HttpMessagePredicate) config.get("matches");
+        predicate = (MessagePredicate) config.get("matches");
         acceptOnMatch = config.getBoolean("acceptOnMatch", true);
     }
 
@@ -54,7 +69,7 @@
             return DUNNO;
         }
 
-        boolean match = predicate.test(new HttpMessageWrapper(request, resp, context));
+        boolean match = predicate.test(filterFactory.createWrapper(request, resp, context));
 
         if (!match) {
             return DUNNO;
@@ -77,7 +92,7 @@
         public NodeDefinition create() {
             return mapDef(
                     tupleDef("acceptOnMatch", valueDefBool()),
-                    tupleDef("matches", new HttpFilterMessagePredicateNodeDefinition())
+                    tupleDef("matches", new MessagePredicateNodeDefinition())
             );
         }
 
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessageModificationFilter.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessageModificationFilter.java	Wed Mar 25 11:02:10 2020 +0100
@@ -11,6 +11,10 @@
 import com.passus.net.http.HttpRequest;
 import com.passus.net.http.HttpResponse;
 import com.passus.st.client.FlowContext;
+import com.passus.st.client.filter.FlowFilterFactory;
+import com.passus.st.client.filter.MessagePredicate;
+import com.passus.st.client.filter.MessagePredicateNodeDefinition;
+import com.passus.st.client.filter.MessageWrapper;
 import com.passus.st.client.http.filter.HttpMessageModificationOperations.Operation;
 import com.passus.st.config.FieldValueExtractorTransformerNodeDefCreator;
 import com.passus.st.config.HeaderOperationNodeDefinition;
@@ -38,15 +42,25 @@
 
     private final List<Operation> operations = new ArrayList<>();
 
-    private HttpMessagePredicate predicate;
+    private MessagePredicate predicate;
+
+    private final FlowFilterFactory filterFactory;
 
     private HttpFilterDirection direction = HttpFilterDirection.OUT;
 
-    public HttpMessagePredicate getPredicate() {
+    public HttpMessageModificationFilter() {
+        this(FlowFilterFactory.DEFAULT_FACTORY);
+    }
+
+    public HttpMessageModificationFilter(FlowFilterFactory filterFactory) {
+        this.filterFactory = filterFactory;
+    }
+
+    public MessagePredicate getPredicate() {
         return predicate;
     }
 
-    public void setPredicate(HttpMessagePredicate predicate) {
+    public void setPredicate(MessagePredicate predicate) {
         this.predicate = predicate;
     }
 
@@ -64,6 +78,7 @@
         operations.add(operation);
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public void configure(Configuration config, ConfigurationContext context) {
         List<Operation> ops = (List<Operation>) config.get("operations");
@@ -75,8 +90,8 @@
             }
         }
 
-        direction = (HttpFilterDirection) config.get("dir", HttpFilterDirection.OUT);
-        predicate = (HttpMessagePredicate) config.get("applyIf", null);
+        direction = config.get("dir", HttpFilterDirection.OUT);
+        predicate = config.get("applyIf", null);
     }
 
     public List<Operation> getOperations() {
@@ -87,13 +102,13 @@
         if (req != null && !operations.isEmpty()) {
             boolean exec = true;
             if (predicate != null) {
-                HttpMessageWrapper wrapper = new HttpMessageWrapper(req, resp, context);
+                MessageWrapper wrapper = filterFactory.createWrapper(req, resp, context);
                 exec = predicate.test(wrapper);
             }
 
             if (exec) {
                 for (Operation op : operations) {
-                    op.process(req, resp, context);
+                    op.process(req, resp, context, filterFactory);
                 }
             }
         }
@@ -170,7 +185,7 @@
 
             return mapDef(
                     tupleDef("operations", operationsDef),
-                    tupleDef("applyIf", new HttpFilterMessagePredicateNodeDefinition()).setRequired(false),
+                    tupleDef("applyIf", new MessagePredicateNodeDefinition()).setRequired(false),
                     tupleDef("dir", enumDef(HttpFilterDirection.class)).setRequired(false)
             );
         }
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessageModificationOperations.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessageModificationOperations.java	Wed Mar 25 11:02:10 2020 +0100
@@ -6,6 +6,7 @@
 import com.passus.filter.ValueExtractor;
 import com.passus.net.http.*;
 import com.passus.st.client.FlowContext;
+import com.passus.st.client.filter.FlowFilterFactory;
 import com.passus.st.extractor.ContentReplacer;
 import com.passus.st.extractor.RegexValueExtractor;
 import org.apache.logging.log4j.LogManager;
@@ -24,8 +25,9 @@
 
     private static final Logger LOGGER = LogManager.getLogger(HttpMessageModificationFilter.class);
 
-    static CharSequence extractValue(ValueExtractor extractor, HttpRequest req, HttpResponse resp, FlowContext context) {
-        Object value = HttpFiltersUtils.extractValue(extractor, req, resp, context);
+    static CharSequence extractValue(ValueExtractor extractor, HttpRequest req, HttpResponse resp,
+                                     FlowContext context, FlowFilterFactory filterFactory) {
+        Object value = HttpFiltersUtils.extractValue(extractor, req, resp, context, filterFactory);
         if (value instanceof CharSequence) {
             if (LOGGER.isDebugEnabled()) {
                 LOGGER.debug("extractor={} extracted={}", extractor, value);
@@ -39,7 +41,7 @@
 
     public static interface Operation {
 
-        public abstract void process(HttpRequest req, HttpResponse resp, FlowContext context);
+        public abstract void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory flowFactory);
     }
 
     protected static abstract class AbstractRemoveOperation implements Operation {
@@ -60,14 +62,14 @@
         }
 
         @Override
-        public void process(HttpRequest req, HttpResponse resp, FlowContext context) {
-            CharSequence name = extractValue(nameExtractor, req, resp, context);
+        public void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory flowFactory) {
+            CharSequence name = extractValue(nameExtractor, req, resp, context, flowFactory);
             if (name != null) {
-                doProcess(name, req, resp, context);
+                doProcess(name, req, resp, context, flowFactory);
             }
         }
 
-        protected abstract void doProcess(CharSequence name, HttpRequest req, HttpResponse resp, FlowContext context);
+        protected abstract void doProcess(CharSequence name, HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory flowFactory);
 
     }
 
@@ -107,8 +109,8 @@
         }
 
         @Override
-        public void process(HttpRequest req, HttpResponse resp, FlowContext context) {
-            CharSequence value = extractValue(valueExtractor, req, resp, context);
+        public void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory flowFactory) {
+            CharSequence value = extractValue(valueExtractor, req, resp, context, flowFactory);
             if (value != null) {
                 doProcess(value, req, resp, context);
             }
@@ -129,7 +131,7 @@
         }
 
         @Override
-        protected void doProcess(CharSequence name, HttpRequest req, HttpResponse resp, FlowContext context) {
+        protected void doProcess(CharSequence name, HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
             req.getHeaders().delete(name);
         }
 
@@ -180,7 +182,7 @@
         }
 
         @Override
-        protected void doProcess(CharSequence name, HttpRequest req, HttpResponse resp, FlowContext context) {
+        protected void doProcess(CharSequence name, HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
             HttpMessageHelper.get().removeCookie(req, name);
         }
 
@@ -231,7 +233,7 @@
         }
 
         @Override
-        protected void doProcess(CharSequence name, HttpRequest req, HttpResponse resp, FlowContext context) {
+        protected void doProcess(CharSequence name, HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
             try {
                 HttpMessageHelper.get().removeQueryParameter(req, name);
             } catch (ParseException ex) {
@@ -299,8 +301,8 @@
             super(extractor);
         }
 
-        protected boolean doRemove(HttpParameters params, HttpRequest req, HttpResponse resp, FlowContext context) {
-            CharSequence name = extractValue(nameExtractor, req, resp, context);
+        protected boolean doRemove(HttpParameters params, HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
+            CharSequence name = extractValue(nameExtractor, req, resp, context, filterFactory);
             if (name != null) {
                 return params.remove(name);
             }
@@ -354,8 +356,8 @@
             this.escape = escape;
         }
 
-        protected void doAdd(HttpParameters params, HttpRequest req, HttpResponse resp, FlowContext context) {
-            Object value = HttpFiltersUtils.extractValue(valueExtractor, req, resp, context);
+        protected void doAdd(HttpParameters params, HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
+            Object value = HttpFiltersUtils.extractValue(valueExtractor, req, resp, context, filterFactory);
             try {
                 if (value instanceof CharSequence) {
                     params.add(name, (CharSequence) value);
@@ -382,9 +384,9 @@
             super(name, extractor);
         }
 
-        protected void doSet(HttpParameters params, HttpRequest req, HttpResponse resp, FlowContext context) {
+        protected void doSet(HttpParameters params, HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
             params.remove(name);
-            doAdd(params, req, resp, context);
+            doAdd(params, req, resp, context, filterFactory);
         }
     }
 
@@ -399,14 +401,14 @@
         }
 
         @Override
-        protected void doProcess(CharSequence value, HttpRequest req, HttpResponse resp, FlowContext context) {
+        protected void doProcess(CharSequence value, HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
             try {
                 HttpMessageHelper helper = HttpMessageHelper.get();
 
                 if (helper.isFormUrlencoded(req)) {
                     HttpParameters params = helper.decodeFormUrlencoded(req);
                     if (params != null) {
-                        if (doRemove(params, req, resp, context)) {
+                        if (doRemove(params, req, resp, context, filterFactory)) {
                             helper.setFormUrlencoded(req, params);
                         }
                     }
@@ -416,7 +418,7 @@
                         return;
                     }
 
-                    CharSequence name = extractValue(nameExtractor, req, resp, context);
+                    CharSequence name = extractValue(nameExtractor, req, resp, context, filterFactory);
                     HttpDataPart part = parts.findByContentDispositionName(name);
                     if (part != null) {
                         parts.remove(part);
@@ -442,14 +444,14 @@
         }
 
         @Override
-        public void process(HttpRequest req, HttpResponse resp, FlowContext context) {
+        public void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
             try {
                 HttpMessageHelper helper = HttpMessageHelper.get();
 
                 if (helper.isFormUrlencoded(req)) {
                     HttpParameters params = helper.decodeFormUrlencoded(req, escape);
                     if (params != null) {
-                        doAdd(params, req, resp, context);
+                        doAdd(params, req, resp, context, filterFactory);
                         helper.setFormUrlencoded(req, params, escape);
                     }
                 } else if (helper.isMultipart(req)) {
@@ -458,7 +460,7 @@
                         return;
                     }
 
-                    Object value = HttpFiltersUtils.extractValue(valueExtractor, req, resp, context);
+                    Object value = HttpFiltersUtils.extractValue(valueExtractor, req, resp, context, filterFactory);
                     parts.addFormData(this.name, value);
                     helper.setMultipartContent(req, parts);
                 }
@@ -481,13 +483,13 @@
         }
 
         @Override
-        public void process(HttpRequest req, HttpResponse resp, FlowContext context) {
+        public void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
             try {
                 HttpMessageHelper helper = HttpMessageHelper.get();
                 if (helper.isFormUrlencoded(req)) {
                     HttpParameters params = helper.decodeFormUrlencoded(req, escape);
                     if (params != null) {
-                        doSet(params, req, resp, context);
+                        doSet(params, req, resp, context, filterFactory);
                         helper.setFormUrlencoded(req, params, escape);
                     }
                 } else if (helper.isMultipart(req)) {
@@ -496,7 +498,7 @@
                         return;
                     }
 
-                    Object value = HttpFiltersUtils.extractValue(valueExtractor, req, resp, context);
+                    Object value = HttpFiltersUtils.extractValue(valueExtractor, req, resp, context, filterFactory);
                     HttpDataPart part = parts.findByContentDispositionName(this.name);
                     if (part == null) {
                         parts.addFormData(this.name, value);
@@ -527,7 +529,7 @@
         }
 
         @Override
-        public void process(HttpRequest req, HttpResponse resp, FlowContext context) {
+        public void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory flowFactory) {
             if (req == null) {
                 return;
             }
@@ -569,7 +571,7 @@
         }
 
         @Override
-        public void process(HttpRequest req, HttpResponse resp, FlowContext context) {
+        public void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory flowFactory) {
             req.setMethod(method);
         }
     }
@@ -586,7 +588,7 @@
         }
 
         @Override
-        public void process(HttpRequest req, HttpResponse resp, FlowContext context) {
+        public void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory flowFactory) {
             req.setVersion(version);
         }
     }
@@ -600,7 +602,7 @@
         }
 
         @Override
-        public void process(HttpRequest req, HttpResponse resp, FlowContext context) {
+        public void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory flowFactory) {
             req.setUri(uri);
         }
     }
@@ -608,7 +610,7 @@
     public static abstract class SetUrlPartOperation implements Operation {
 
         @Override
-        public void process(HttpRequest req, HttpResponse resp, FlowContext context) {
+        public void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory flowFactory) {
             try {
                 ByteString urlStr = req.getUrl();
                 URLBuilder builder = new URLBuilder(urlStr);
@@ -679,8 +681,8 @@
         }
 
         @Override
-        public void process(HttpRequest req, HttpResponse resp, FlowContext context) {
-            CharSequence value = extractValue(valueExtractor, req, resp, context);
+        public void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
+            CharSequence value = extractValue(valueExtractor, req, resp, context, filterFactory);
             if (value != null) {
                 try {
                     ByteString urlStr = req.getUrl();
@@ -725,8 +727,8 @@
         }
 
         @Override
-        public void process(HttpRequest req, HttpResponse resp, FlowContext context) {
-            CharSequence value = extractValue(valueExtractor, req, resp, context);
+        public void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
+            CharSequence value = extractValue(valueExtractor, req, resp, context, filterFactory);
             if (value != null) {
                 try {
                     ByteString urlStr = req.getUri();
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessagePredicate.java	Tue Mar 24 14:36:47 2020 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-package com.passus.st.client.http.filter;
-
-import com.passus.commons.Assert;
-import com.passus.commons.ConversionException;
-import com.passus.config.NodeException;
-import com.passus.net.http.HttpMessage;
-import com.passus.net.http.HttpRequest;
-import com.passus.net.http.HttpResponse;
-import com.passus.st.client.FlowContext;
-import com.passus.st.filter.Transformers;
-
-import java.io.IOException;
-import java.util.function.Predicate;
-
-/**
- * @author Mirosław Hawrot
- */
-public class HttpMessagePredicate implements Predicate<HttpMessage> {
-
-    private final Predicate predicate;
-
-    public HttpMessagePredicate(Predicate predicate) {
-        Assert.notNull(predicate, "predicate");
-        this.predicate = predicate;
-    }
-
-    public Predicate getPredicate() {
-        return predicate;
-    }
-
-    public boolean test(HttpRequest req, HttpResponse resp, FlowContext context) {
-        return test(new HttpMessageWrapper(req, resp, context));
-    }
-
-    public boolean test(HttpMessageWrapper wrapper) {
-        return predicate.test(wrapper);
-    }
-
-    @Override
-    public boolean test(HttpMessage message) {
-        HttpMessageWrapper wrapper;
-        if (message.isRequest()) {
-            wrapper = new HttpMessageWrapper((HttpRequest) message, null, null);
-        } else {
-            wrapper = new HttpMessageWrapper(null, (HttpResponse) message, null);
-        }
-
-        return predicate.test(wrapper);
-    }
-
-    @Override
-    public String toString() {
-        return predicate.toString();
-    }
-
-    public static HttpMessagePredicate parse(String content) throws ConversionException, IOException, NodeException {
-        Predicate predicate = Transformers.PREDICATE.transform(content);
-        return new HttpMessagePredicate(predicate);
-    }
-
-}
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessageWrapper.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessageWrapper.java	Wed Mar 25 11:02:10 2020 +0100
@@ -5,7 +5,7 @@
 import com.passus.net.http.HttpResponse;
 import com.passus.st.ParametersBag;
 import com.passus.st.client.FlowContext;
-import com.passus.st.client.http.HttpFlowConst;
+import com.passus.st.client.filter.MessageWrapper;
 import com.passus.st.client.http.HttpFlowContext;
 import com.passus.st.client.http.HttpScopes;
 import com.passus.st.emitter.SessionInfo;
@@ -13,39 +13,17 @@
 /**
  * @author Mirosław Hawrot
  */
-public class HttpMessageWrapper {
-
-    private final HttpFilterRequestWrapper req;
-
-    private final HttpFilterResponseWrapper resp;
+public class HttpMessageWrapper extends MessageWrapper<HttpFilterRequestWrapper, HttpFilterResponseWrapper> {
 
     private final HttpFilterResponseWrapper origResp;
 
-    private final FlowContext context;
-
     private final HttpFlowContext httpContext;
 
-    public HttpMessageWrapper(HttpRequest req, HttpResponse resp, FlowContext context) {
-        this.req = (HttpFilterRequestWrapper) createWrapper(req);
-        this.resp = (HttpFilterResponseWrapper) createWrapper(resp);
-
-        if (context != null) {
-            this.httpContext = context.getParamValue(HttpFlowConst.PARAM_HTTP_CONTEXT);
-            this.origResp = (HttpFilterResponseWrapper) createWrapper(httpContext.origResponse());
-            this.context = context;
-        } else {
-            this.httpContext = null;
-            this.context = null;
-            this.origResp = null;
-        }
-    }
-
-    public HttpFilterRequestWrapper getReq() {
-        return req;
-    }
-
-    public HttpFilterResponseWrapper getResp() {
-        return resp;
+    public HttpMessageWrapper(HttpFilterRequestWrapper req, HttpFilterResponseWrapper resp, FlowContext context,
+                              HttpFilterResponseWrapper origResp, HttpFlowContext httpContext) {
+        super(req, resp, context);
+        this.origResp = origResp;
+        this.httpContext = httpContext;
     }
 
     public HttpFilterResponseWrapper getOrigResp() {
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpScopeModificationFilter.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpScopeModificationFilter.java	Wed Mar 25 11:02:10 2020 +0100
@@ -13,6 +13,10 @@
 import com.passus.net.http.HttpResponse;
 import com.passus.st.ParametersBag;
 import com.passus.st.client.FlowContext;
+import com.passus.st.client.filter.FlowFilterFactory;
+import com.passus.st.client.filter.MessagePredicate;
+import com.passus.st.client.filter.MessagePredicateNodeDefinition;
+import com.passus.st.client.filter.MessageWrapper;
 import com.passus.st.config.FieldValueExtractorTransformerNodeDefCreator;
 import com.passus.st.config.HeaderOperationNodeDefinition;
 import com.passus.st.plugin.PluginConstants;
@@ -35,14 +39,14 @@
 
     public static abstract class Operation {
 
-        public abstract void process(HttpRequest req, HttpResponse resp, FlowContext context);
+        public abstract void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory);
 
     }
 
     public static class RemoveSessionOperation extends Operation {
 
         @Override
-        public void process(HttpRequest req, HttpResponse resp, FlowContext context) {
+        public void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
             extractHttpContext(context).scopes().removeSession(req);
         }
 
@@ -62,7 +66,7 @@
         }
 
         @Override
-        public void process(HttpRequest req, HttpResponse resp, FlowContext context) {
+        public void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
             ParametersBag params = extractHttpContext(context).scopes().getSession(req, false);
             if (params != null) {
                 params.remove(paramName);
@@ -85,7 +89,7 @@
         }
 
         @Override
-        public void process(HttpRequest req, HttpResponse resp, FlowContext context) {
+        public void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
             ParametersBag params = extractHttpContext(context).scopes().getGlobal();
             params.remove(paramName);
         }
@@ -139,14 +143,14 @@
         }
 
         @Override
-        public void process(HttpRequest req, HttpResponse resp, FlowContext context) {
+        public void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
             ParametersBag params = extractHttpContext(context).scopes().getSession(req, autocreate);
             if (params != null) {
                 if (checkValueExists && params.contains(paramName)) {
                     return;
                 }
 
-                Object value = HttpFiltersUtils.extractValue(valueExtractor, req, resp, context);
+                Object value = HttpFiltersUtils.extractValue(valueExtractor, req, resp, context, filterFactory);
                 params.set(paramName, value);
             }
         }
@@ -160,13 +164,13 @@
         }
 
         @Override
-        public void process(HttpRequest req, HttpResponse resp, FlowContext context) {
+        public void process(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
             ParametersBag params = extractHttpContext(context).scopes().getGlobal();
             if (checkValueExists && params.contains(paramName)) {
                 return;
             }
 
-            Object value = HttpFiltersUtils.extractValue(valueExtractor, req, resp, context);
+            Object value = HttpFiltersUtils.extractValue(valueExtractor, req, resp, context, filterFactory);
             params.set(paramName, value);
         }
 
@@ -174,15 +178,26 @@
 
     private final List<Operation> operations = new ArrayList<>();
 
-    private HttpMessagePredicate predicate;
+    private MessagePredicate predicate;
 
     private HttpFilterDirection direction = HttpFilterDirection.OUT;
 
-    public HttpMessagePredicate getPredicate() {
+    private final FlowFilterFactory filterFactory;
+
+    public HttpScopeModificationFilter() {
+        this(FlowFilterFactory.DEFAULT_FACTORY);
+    }
+
+    public HttpScopeModificationFilter(FlowFilterFactory filterFactory) {
+        Assert.notNull(filterFactory, "filterFactory");
+        this.filterFactory = filterFactory;
+    }
+
+    public MessagePredicate getPredicate() {
         return predicate;
     }
 
-    public void setPredicate(HttpMessagePredicate predicate) {
+    public void setPredicate(MessagePredicate predicate) {
         this.predicate = predicate;
     }
 
@@ -232,13 +247,13 @@
         if (req != null && !operations.isEmpty()) {
             boolean exec = true;
             if (predicate != null) {
-                HttpMessageWrapper wrapper = new HttpMessageWrapper(req, resp, context);
+                MessageWrapper wrapper = filterFactory.createWrapper(req, resp, context);
                 exec = predicate.test(wrapper);
             }
 
             if (exec) {
                 for (Operation op : operations) {
-                    op.process(req, resp, context);
+                    op.process(req, resp, context, filterFactory);
                 }
             }
         }
@@ -298,7 +313,7 @@
 
             return mapDef(
                     tupleDef("operations", operationsDef),
-                    tupleDef("applyIf", new HttpFilterMessagePredicateNodeDefinition()).setRequired(false),
+                    tupleDef("applyIf", new MessagePredicateNodeDefinition()).setRequired(false),
                     tupleDef("dir", enumDef(HttpFilterDirection.class)).setRequired(false)
             );
         }
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpSequenceFilter.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpSequenceFilter.java	Wed Mar 25 11:02:10 2020 +0100
@@ -1,24 +1,12 @@
 package com.passus.st.client.http.filter;
 
+import com.passus.commons.Assert;
 import com.passus.commons.annotations.Plugin;
 import com.passus.commons.metric.MapMetric;
 import com.passus.commons.service.Registry;
-import com.passus.config.CMapNode;
-import com.passus.config.CNode;
-import com.passus.config.CTupleNode;
-import com.passus.config.CValueNode;
-import com.passus.config.Configuration;
-import com.passus.config.ConfigurationContext;
+import com.passus.config.*;
 import com.passus.config.annotations.NodeDefinitionCreate;
-import static com.passus.config.schema.ConfigurationSchemaBuilder.mapDef;
-import static com.passus.config.schema.ConfigurationSchemaBuilder.tupleDef;
-import static com.passus.config.schema.ConfigurationSchemaBuilder.valueDef;
-import com.passus.config.schema.ListNodeDefinition;
-import com.passus.config.schema.MapNodeDefinition;
-import com.passus.config.schema.MappingNodeDefinition;
-import com.passus.config.schema.NodeDefinition;
-import com.passus.config.schema.NodeDefinitionCreator;
-import com.passus.config.schema.NodeTransformer;
+import com.passus.config.schema.*;
 import com.passus.config.validation.Errors;
 import com.passus.filter.ValueExtractor;
 import com.passus.filter.ValueExtractorParser;
@@ -26,21 +14,21 @@
 import com.passus.net.http.HttpRequest;
 import com.passus.net.http.HttpResponse;
 import com.passus.st.client.FlowContext;
+import com.passus.st.client.filter.FlowFilterFactory;
+import com.passus.st.client.filter.MessagePredicateNodeDefinition;
+import com.passus.st.client.filter.MessageWrapper;
 import com.passus.st.client.http.ReporterDestination;
 import com.passus.st.filter.Transformers;
 import com.passus.st.plugin.PluginConstants;
+
 import java.io.Serializable;
 import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.function.Predicate;
 
+import static com.passus.config.schema.ConfigurationSchemaBuilder.*;
+
 /**
- *
  * @author mikolaj.podbielski
  */
 @NodeDefinitionCreate(HttpSequenceFilter.NodeDefCreator.class)
@@ -188,12 +176,12 @@
             }
         }
 
-        public void updateValue(HttpMessageWrapper wrapper) {
+        public void updateValue(MessageWrapper wrapper) {
             valueMap.put("req", wrapper.getReq());
             valueMap.put("resp", wrapper.getResp());
         }
 
-        public void persistsValue(HttpMessageWrapper wrapper, String[] aliases) {
+        public void persistsValue(MessageWrapper wrapper, String[] aliases) {
             for (String alias : aliases) {
                 valueMap.put(alias, wrapper);
             }
@@ -239,6 +227,17 @@
     private SequenceItem[] seqItems;
     private Map<String, ValueExtractor> values = Collections.EMPTY_MAP;
 
+    private final FlowFilterFactory filterFactory;
+
+    public HttpSequenceFilter() {
+        this(FlowFilterFactory.DEFAULT_FACTORY);
+    }
+
+    public HttpSequenceFilter(FlowFilterFactory filterFactory) {
+        Assert.notNull(filterFactory, "filterFactory");
+        this.filterFactory = filterFactory;
+    }
+
     public HttpSequenceListener getListener() {
         return listener;
     }
@@ -263,7 +262,7 @@
         this.values = values;
     }
 
-    private void processValue(long now, HttpMessageWrapper value) {
+    private void processValue(long now, MessageWrapper value) {
         Iterator<SeqChain> iterator = chains.iterator();
         while (iterator.hasNext()) {
             SeqChain chain = iterator.next();
@@ -326,7 +325,7 @@
 
     @Override
     public int filterInbound(HttpRequest req, HttpResponse resp, FlowContext context) {
-        HttpMessageWrapper wrapper = new HttpMessageWrapper(req, resp, context);
+        MessageWrapper wrapper = filterFactory.createWrapper(req, resp, context);
         processValue(resp.getTimestamp(), wrapper);
         return DUNNO;
     }
@@ -354,7 +353,6 @@
         }
 
         values = (Map<String, ValueExtractor>) config.get("values", Collections.EMPTY_MAP);
-
         ReporterDestination reporterDestination = Registry.getInstance().get(
                 ReporterDestination.SERVICE_NAME, ReporterDestination.class);
         if (reporterDestination != null) {
@@ -367,7 +365,7 @@
         @Override
         public NodeDefinition create() {
             MapNodeDefinition elementDef = mapDef(
-                    tupleDef("match", new HttpFilterMessagePredicateNodeDefinition()),
+                    tupleDef("match", new MessagePredicateNodeDefinition()),
                     tupleDef("mustOccur", valueDef(Boolean.class)).setRequired(false),
                     tupleDef("time", valueDef(Long.class)).setRequired(false),
                     tupleDef("alias", valueDef()).setRequired(false)
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpVarsFilter.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpVarsFilter.java	Wed Mar 25 11:02:10 2020 +0100
@@ -9,6 +9,7 @@
 import com.passus.net.http.HttpRequest;
 import com.passus.net.http.HttpResponse;
 import com.passus.st.client.FlowContext;
+import com.passus.st.client.filter.FlowFilterFactory;
 import com.passus.st.vars.Var;
 import com.passus.st.vars.VarsCompiler;
 import com.passus.st.vars.VarsExecutor;
@@ -31,22 +32,33 @@
 
     private final VarsExecutor executor;
 
+    private final FlowFilterFactory filterFactory;
+
     public HttpVarsFilter() {
-        compiler = new VarsCompiler();
-        executor = new VarsExecutor();
+        this(new VarsCompiler(), new VarsExecutor());
     }
 
     public HttpVarsFilter(Map<String, ValueExtractor> appVars) {
+        this(appVars, FlowFilterFactory.DEFAULT_FACTORY);
+    }
+
+    public HttpVarsFilter(Map<String, ValueExtractor> appVars, FlowFilterFactory filterFactory) {
         Assert.notNull(appVars, "appVars");
         compiler = new VarsCompiler(new VarsExtractorResolver(appVars));
         executor = new VarsExecutor();
+        this.filterFactory = filterFactory;
     }
 
     public HttpVarsFilter(VarsCompiler compiler, VarsExecutor executor) {
+        this(compiler, executor, FlowFilterFactory.DEFAULT_FACTORY);
+    }
+
+    public HttpVarsFilter(VarsCompiler compiler, VarsExecutor executor, FlowFilterFactory filterFactory) {
         Assert.notNull(compiler, "compiler");
         Assert.notNull(executor, "executor");
         this.compiler = compiler;
         this.executor = executor;
+        this.filterFactory = filterFactory;
     }
 
     @Override
@@ -65,7 +77,7 @@
                     List<Var> vars = compiler.search(buffer);
                     if (vars != null && !vars.isEmpty()) {
                         ByteBuff result = new HeapByteBuff(buffer.readableBytes());
-                        boolean changed = executor.execute(buffer, result, vars, new HttpMessageWrapper(req, resp, context));
+                        boolean changed = executor.execute(buffer, result, vars, filterFactory.createWrapper(req, resp, context));
                         if (changed) {
                             req.setContent(new ByteBuffDataSource(result));
                             HttpMessageHelper.get().setContentLength(req, result.readableBytes());
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpZoneFilter.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpZoneFilter.java	Wed Mar 25 11:02:10 2020 +0100
@@ -12,6 +12,8 @@
 import com.passus.net.http.HttpRequest;
 import com.passus.net.http.HttpResponse;
 import com.passus.st.client.FlowContext;
+import com.passus.st.client.filter.FlowFilterFactory;
+import com.passus.st.client.filter.MessagePredicate;
 import com.passus.st.filter.Transformers;
 import com.passus.st.plugin.PluginConstants;
 
@@ -39,9 +41,9 @@
 
         private final String zone;
 
-        private final HttpMessagePredicate predicate;
+        private final MessagePredicate predicate;
 
-        public Rule(String zone, HttpMessagePredicate predicate) {
+        public Rule(String zone, MessagePredicate predicate) {
             Assert.notNull(zone, "zone");
             Assert.notNull(predicate, "predicate");
             this.zone = zone;
@@ -52,20 +54,29 @@
             return zone;
         }
 
-        public boolean match(HttpRequest req, HttpResponse resp, FlowContext context) {
-            return predicate.test(new HttpMessageWrapper(req, resp, context));
+        public boolean match(HttpRequest req, HttpResponse resp, FlowContext context, FlowFilterFactory filterFactory) {
+            return predicate.test(filterFactory.createWrapper(req, resp, context));
         }
 
     }
 
     private final List<Rule> rules = new ArrayList<>();
 
+    private final FlowFilterFactory filterFactory;
+
     public HttpZoneFilter() {
+        this(Collections.EMPTY_LIST);
     }
 
     public HttpZoneFilter(List<Rule> rules) {
+        this(rules, FlowFilterFactory.DEFAULT_FACTORY);
+    }
+
+    public HttpZoneFilter(List<Rule> rules, FlowFilterFactory filterFactory) {
         Assert.notContainsNull(rules, "rules");
+        Assert.notNull(filterFactory, "filterFactory");
         this.rules.addAll(rules);
+        this.filterFactory = filterFactory;
     }
 
     public void addRule(Rule rule) {
@@ -88,7 +99,7 @@
     public int filterOutbound(HttpRequest req, HttpResponse resp, FlowContext context) {
         if (req != null && !rules.isEmpty()) {
             for (Rule rule : rules) {
-                if (rule.match(req, resp, context)) {
+                if (rule.match(req, resp, context, filterFactory)) {
                     req.setTag(TAG_ZONE, rule.zone);
                     if (resp != null) {
                         resp.setTag(TAG_ZONE, rule.zone);
@@ -165,7 +176,7 @@
 
                         try {
                             Predicate predicate = TRANSFORMER.transform(tuple.getNode());
-                            HttpMessagePredicate msgPredicate = new HttpMessagePredicate(predicate);
+                            MessagePredicate msgPredicate = new MessagePredicate(predicate);
                             CValueNode valNode = new CValueNode(new Rule(tuple.getName(), msgPredicate));
                             listNode.add(valNode);
                         } catch (NodeConversionException ex) {
--- a/stress-tester/src/main/java/com/passus/st/emitter/RuleBasedSessionMapper.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/main/java/com/passus/st/emitter/RuleBasedSessionMapper.java	Wed Mar 25 11:02:10 2020 +0100
@@ -43,7 +43,7 @@
         return Collections.unmodifiableList(rules);
     }
 
-    public void addRule(Rule rule) throws ParseException {
+    public void addRule(Rule rule) {
         Assert.notNull(rule, "rule");
         synchronized (this) {
             rules.add(rule);
--- a/stress-tester/src/test/java/com/passus/st/ConverterHttpClientTest.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/test/java/com/passus/st/ConverterHttpClientTest.java	Wed Mar 25 11:02:10 2020 +0100
@@ -4,6 +4,7 @@
 import com.passus.st.client.SessionPayloadEvent;
 import com.passus.st.client.credentials.Credentials;
 import com.passus.st.client.credentials.CredentialsProvider;
+import com.passus.st.client.filter.MessagePredicate;
 import com.passus.st.client.http.filter.*;
 import com.passus.st.client.http.filter.HttpMessageModificationOperations.PostDataSetParamOperation;
 import com.passus.st.client.http.filter.HttpMessageModificationOperations.SetCookieOperation;
@@ -143,7 +144,7 @@
         HttpResponse resp2 = HttpResponseBuilder.status(HttpStatus.NO_CONTENT).build();
 
         ArrayListEventDestination dst = new ArrayListEventDestination();
-        HttpMessagePredicate predicate = HttpFilterTestUtils.createPredicate("{'@req.url': {$contains: test2}}");
+        MessagePredicate predicate = HttpFilterTestUtils.createPredicate("{'@req.url': {$contains: test2}}");
         HttpMatchFilter f = new HttpMatchFilter();
         f.setPredicate(predicate);
         f.setAcceptOnMatch(false);
@@ -243,7 +244,7 @@
     public void testZone_() {
         HttpRequest req = HttpRequestBuilder.get("http://test.com/test").build();
         HttpResponse resp = HttpResponseBuilder.ok().build();
-        HttpMessagePredicate predicate = HttpFilterTestUtils.createPredicate("{\"@req.url\": {$contains: test}}");
+        MessagePredicate predicate = HttpFilterTestUtils.createPredicate("{\"@req.url\": {$contains: test}}");
 
         HttpZoneFilter f = new HttpZoneFilter();
         f.addRule(new HttpZoneFilter.Rule("testZone", predicate));
@@ -276,7 +277,7 @@
     public void testMarker_() {
         HttpRequest req = HttpRequestBuilder.get("http://test/test").build();
 
-        HttpMessagePredicate predicate = HttpFilterTestUtils.createPredicate("{\"@req.url\": {$contains: test}}");
+        MessagePredicate predicate = HttpFilterTestUtils.createPredicate("{\"@req.url\": {$contains: test}}");
         HttpMarkFilter f = new HttpMarkFilter();
         f.addRule(new HttpMarkFilter.MarkerRule("category1", predicate));
         ConverterHttpClient client = client(f);
--- a/stress-tester/src/test/java/com/passus/st/FilterScanner.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/test/java/com/passus/st/FilterScanner.java	Wed Mar 25 11:02:10 2020 +0100
@@ -1,6 +1,6 @@
 package com.passus.st;
 
-import com.passus.st.client.filter.FlowFilterFactory;
+import com.passus.st.client.filter.FlowFilterPluginFactory;
 
 /**
  *
@@ -9,7 +9,7 @@
 public class FilterScanner {
 
     public static void main(String[] args) {
-        FlowFilterFactory.getInstance().getAll().stream()
+        FlowFilterPluginFactory.getInstance().getAll().stream()
                 .sorted((pi1, pi2) -> pi1.getPluginClass().getSimpleName().compareTo(pi2.getPluginClass().getSimpleName()))
                 .forEach((pi) -> System.out.format("%-28s %s\n", pi.getElementName(), pi.getPluginClass().getSimpleName()));
     }
--- a/stress-tester/src/test/java/com/passus/st/client/dns/filter/DnsRecordTypeFilterTest.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/test/java/com/passus/st/client/dns/filter/DnsRecordTypeFilterTest.java	Wed Mar 25 11:02:10 2020 +0100
@@ -19,7 +19,7 @@
     @Test
     public void testConfigure() throws IOException, NodeException {
         String filterConfig = "filters:\n"
-                + "    - type: dns.recordType\n"
+                + "    - type: dnsRecordType\n"
                 + "      acceptOnMatch: true\n"
                 + "      recordTypes: ['A', 'TXT', 'PTR']\n";
 
--- a/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpCounterFilterTest.java	Tue Mar 24 14:36:47 2020 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-package com.passus.st.client.http.filter;
-
-import com.passus.config.validation.Errors;
-import com.passus.filter.AndPredicate;
-import com.passus.filter.ComparisonOperator;
-import com.passus.filter.ComparisonPredicate;
-import com.passus.net.http.HttpRequest;
-import com.passus.net.http.HttpRequestBuilder;
-import com.passus.net.http.HttpResponse;
-import com.passus.net.http.HttpResponseBuilder;
-import com.passus.net.http.HttpStatus;
-import java.util.ArrayList;
-import java.util.List;
-import static org.testng.AssertJUnit.*;
-
-import com.passus.st.client.filter.FlowFilter;
-import com.passus.st.client.filter.FlowFiltersConfigurator;
-import org.testng.annotations.Test;
-
-/**
- *
- * @author mikolaj.podbielski
- */
-public class HttpCounterFilterTest {
-
-    @Test
-    public void testFilterInbound() {
-        HttpRequest req = HttpRequestBuilder.get("http://example.com").build();
-        HttpResponse resp = HttpResponseBuilder.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
-
-        TestListener listener = new TestListener();
-
-        HttpMessagePredicate predicate = HttpFilterTestUtils.createPredicate("{'@resp.status.code': 500}");
-        HttpCounterFilter filter = new HttpCounterFilter();
-        filter.setLimit(2);
-        filter.setName("filter status code 500");
-        filter.setPredicate(predicate);
-        filter.setListener(listener);
-
-        filter.filterInbound(req, resp, null);
-        assertEquals(0, listener.events.size());
-        filter.filterInbound(req, resp, null);
-        assertEquals(1, listener.events.size());
-    }
-
-    @Test
-    public void testConfigure() throws Exception {
-        String filterConfig = "filters:\n"
-                + "    - type: counter\n"
-                + "      name: 'filter x'\n"
-                + "      limit: 3\n"
-                + "      applyIf: {'@resp.status.code': 404}\n";
-
-        Errors errors = new Errors();
-        List<FlowFilter> filters = FlowFiltersConfigurator.getFilters(filterConfig, errors, null);
-        HttpFilterTestUtils.printErrors(errors);
-
-        assertEquals(0, errors.getErrorCount());
-        assertEquals(1, filters.size());
-        assertTrue(filters.get(0) instanceof HttpCounterFilter);
-
-        HttpCounterFilter filter = (HttpCounterFilter) filters.get(0);
-        assertEquals(3, filter.getLimit());
-        assertEquals("filter x", filter.getName());
-
-        AndPredicate<? extends Object> andPredicate = (AndPredicate) filter.getPredicate().getPredicate();
-        assertEquals(1, andPredicate.getSubPredicates().size());
-        ComparisonPredicate predicate = (ComparisonPredicate) andPredicate.getSubPredicates().get(0);
-        assertEquals("resp.status.code", predicate.getFieldName());
-        assertEquals(ComparisonOperator.EQUAL, predicate.getOperator());
-    }
-
-    private static class TestListener implements HttpCounterListener {
-
-        private final ArrayList<Event> events = new ArrayList<>();
-
-        @Override
-        public void limitReached(Event event) {
-            events.add(event);
-        }
-
-    }
-}
--- a/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpFilterTestUtils.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpFilterTestUtils.java	Wed Mar 25 11:02:10 2020 +0100
@@ -10,6 +10,7 @@
 import static com.passus.st.client.http.HttpConsts.ZONE_DEFAULT;
 
 import com.passus.st.client.FlowContext;
+import com.passus.st.client.filter.MessagePredicate;
 import com.passus.st.client.http.HttpFlowConst;
 import com.passus.st.client.http.HttpFlowContext;
 import com.passus.st.client.http.HttpScopes;
@@ -40,16 +41,16 @@
         return mockContext;
     }
 
-    public static HttpMessagePredicate createPredicate(String config) {
+    public static MessagePredicate createPredicate(String config) {
         return createPredicate(config, DEFAULT_USE_ACCELERATED_EXTRACTORS);
     }
 
-    public static HttpMessagePredicate createPredicate(String config, boolean useAcceleratedExtractor) {
+    public static MessagePredicate createPredicate(String config, boolean useAcceleratedExtractor) {
         try {
             PredicateNodeTransformer transformer = useAcceleratedExtractor
                     ? Transformers.PREDICATE : PredicateNodeTransformer.DEFAULT;
             Predicate predicate = transformer.transform(config);
-            return new HttpMessagePredicate(predicate);
+            return new MessagePredicate(predicate);
         } catch (Exception e) {
             throw new RuntimeException(e.getMessage(), e);
         }
--- a/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpFormLoginFilterTest.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpFormLoginFilterTest.java	Wed Mar 25 11:02:10 2020 +0100
@@ -11,6 +11,8 @@
 import com.passus.st.client.credentials.CredentialsProvider;
 import static com.passus.st.client.http.HttpConsts.PARAM_USERNAME;
 import static com.passus.st.client.http.HttpConsts.TAG_SESSION_ID;
+
+import com.passus.st.client.filter.MessagePredicate;
 import com.passus.st.client.http.HttpFlowContext;
 import com.passus.st.client.http.HttpScopes;
 import com.passus.st.utils.TestHttpUtils;
@@ -49,7 +51,7 @@
 
     public static HttpFormLoginFilter createFilter(CredentialsProvider provider, Predicate predicate) {
         ConfigurationImpl cfg = new ConfigurationImpl();
-        cfg.set("applyIf", new HttpMessagePredicate(predicate));
+        cfg.set("applyIf", new MessagePredicate(predicate));
         cfg.set("provider", provider);
         cfg.set("userField", "_username");
         cfg.set("passwordField", "_password");
--- a/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpLogoutFilterTest.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpLogoutFilterTest.java	Wed Mar 25 11:02:10 2020 +0100
@@ -9,6 +9,7 @@
 import com.passus.st.client.FlowContext;
 import com.passus.st.client.filter.FlowFilter;
 import com.passus.st.client.filter.FlowFiltersConfigurator;
+import com.passus.st.client.filter.MessagePredicate;
 import com.passus.st.client.http.HttpScopes;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
@@ -38,7 +39,7 @@
 
     @Test
     public void testFilter_InvalidateSession() {
-        HttpMessagePredicate predicate = HttpFilterTestUtils.createPredicate("{'@req.uri': \"/logout\"}");
+        MessagePredicate predicate = HttpFilterTestUtils.createPredicate("{'@req.uri': \"/logout\"}");
         HttpRequest req = HttpRequestBuilder.get("http://test.com/logout").build();
         HttpResponse resp = HttpResponseBuilder.ok().build();
         HttpScopes scopes = new HttpScopes();
@@ -59,7 +60,7 @@
 
     @Test
     public void testFilter_NotInvalidateSession() {
-        HttpMessagePredicate predicate = HttpFilterTestUtils.createPredicate("{'@req.uri': \"/logout\"}");
+        MessagePredicate predicate = HttpFilterTestUtils.createPredicate("{'@req.uri': \"/logout\"}");
         HttpRequest req = HttpRequestBuilder.get("http://test.com/logout").build();
         HttpResponse resp = HttpResponseBuilder.ok().build();
         HttpScopes scopes = new HttpScopes();
--- a/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMarkFilterTest.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMarkFilterTest.java	Wed Mar 25 11:02:10 2020 +0100
@@ -8,6 +8,7 @@
 
 import com.passus.st.client.filter.FlowFilter;
 import com.passus.st.client.filter.FlowFiltersConfigurator;
+import com.passus.st.client.filter.MessagePredicate;
 import com.passus.st.client.http.filter.HttpMarkFilter.Marker;
 import com.passus.st.client.http.filter.HttpMarkFilter.MarkerRule;
 import java.util.List;
@@ -34,7 +35,7 @@
 
     @Test
     public void testFilterInbound() throws Exception {
-        HttpMessagePredicate predicate = HttpMessagePredicate.parse("{'@req.url': {$contains: test}}");
+        MessagePredicate predicate = MessagePredicate.parse("{'@req.url': {$contains: test}}");
         HttpMarkFilter filter = new HttpMarkFilter();
         filter.addRule(new MarkerRule("category1", predicate));
 
@@ -72,6 +73,6 @@
         MarkerRule rule = rules.get(0);
         assertEquals("category1", rule.getMarker().getCategory());
         assertEquals("message1", rule.getMarker().getMessage());
-        assertTrue(rule.getPredicate() instanceof HttpMessagePredicate);
+        assertTrue(rule.getPredicate() instanceof MessagePredicate);
     }
 }
--- a/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMatchFilterTest.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMatchFilterTest.java	Wed Mar 25 11:02:10 2020 +0100
@@ -16,6 +16,7 @@
 
 import com.passus.st.client.filter.FlowFilter;
 import com.passus.st.client.filter.FlowFiltersConfigurator;
+import com.passus.st.client.filter.MessagePredicate;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
@@ -38,11 +39,11 @@
     );
 
     private <T extends HttpMessage> List<T> filter(List<T> messages, String config) {
-        HttpMessagePredicate predicate = HttpFilterTestUtils.createPredicate(config);
+        MessagePredicate predicate = HttpFilterTestUtils.createPredicate(config);
         return filter(messages, predicate);
     }
 
-    private <T extends HttpMessage> List<T> filter(List<T> messages, HttpMessagePredicate predicate) {
+    private <T extends HttpMessage> List<T> filter(List<T> messages, MessagePredicate predicate) {
         List<T> out = new ArrayList<>(messages.size());
         for (T message : messages) {
             if (predicate.test(message)) {
@@ -88,7 +89,7 @@
         resps = filter(responses, "{'@resp.status.code': {$gt: 200}}");
         assertEquals(2, resps.size());
 
-        HttpMessagePredicate predicate = HttpFilterTestUtils.createPredicate(
+        MessagePredicate predicate = HttpFilterTestUtils.createPredicate(
                 "{'@resp.status.code': {$gt: 200}}", false);
         resps = filter(responses, predicate);
         assertEquals(2, resps.size());
@@ -110,7 +111,7 @@
         assertTrue(filters.get(0) instanceof HttpMatchFilter);
 
         HttpMatchFilter filter = (HttpMatchFilter) filters.get(0);
-        HttpMessagePredicate predicate = filter.getPredicate();
+        MessagePredicate predicate = filter.getPredicate();
 
         List<HttpRequest> res = filter(requests, "{'@req.url': {$contains: \"test2\"}}");
         assertEquals(1, res.size());
--- a/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMessageModificationOperationsTest.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMessageModificationOperationsTest.java	Wed Mar 25 11:02:10 2020 +0100
@@ -21,7 +21,7 @@
 
     private HttpRequest process(Operation op) {
         HttpRequest req = HttpRequestBuilder.get(url).build();
-        op.process(req, null, null);
+        op.process(req, null, null, null);
         return req;
     }
 
--- a/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMessageWrapperTest.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMessageWrapperTest.java	Wed Mar 25 11:02:10 2020 +0100
@@ -12,6 +12,8 @@
 import com.passus.st.AppUtils;
 import com.passus.st.ParametersBag;
 import com.passus.st.client.FlowContext;
+import com.passus.st.client.filter.FlowFilterFactory;
+import com.passus.st.client.filter.MessageWrapper;
 import com.passus.st.client.http.HttpFlowConst;
 import com.passus.st.client.http.HttpFlowContext;
 import com.passus.st.client.http.HttpScopes;
@@ -55,7 +57,7 @@
         session.set("Var1", "Val1");
     }
 
-    HttpMessageWrapper wrapper = new HttpMessageWrapper(req, resp, context);
+    MessageWrapper wrapper = FlowFilterFactory.DEFAULT_FACTORY.createWrapper(req, resp, context);
     ValueExtractorParser parser = new ValueExtractorParser();
 
     @BeforeClass
--- a/stress-tester/src/test/java/com/passus/st/filter/HttpMessageValueExtractorTest.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/test/java/com/passus/st/filter/HttpMessageValueExtractorTest.java	Wed Mar 25 11:02:10 2020 +0100
@@ -4,6 +4,8 @@
 import com.passus.net.http.*;
 import com.passus.st.ParametersBag;
 import com.passus.st.client.FlowContext;
+import com.passus.st.client.filter.FlowFilterFactory;
+import com.passus.st.client.filter.MessageWrapper;
 import com.passus.st.client.http.HttpFlowConst;
 import com.passus.st.client.http.HttpFlowContext;
 import com.passus.st.client.http.HttpScopes;
@@ -46,7 +48,7 @@
         session.set("Var1", "Val1");
     }
 
-    private final HttpMessageWrapper wrapper = new HttpMessageWrapper(req, resp, context);
+    private final MessageWrapper wrapper = FlowFilterFactory.DEFAULT_FACTORY.createWrapper(req, resp, context);
 
     private void assertExtractor(String expr, Object expected) {
         ValueExtractor e = resolver.resolveValueExtractor(expr);
--- a/stress-tester/src/test/java/com/passus/st/filter/HttpMessageWrapperDynamicExtractorTest.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/test/java/com/passus/st/filter/HttpMessageWrapperDynamicExtractorTest.java	Wed Mar 25 11:02:10 2020 +0100
@@ -7,6 +7,9 @@
 import com.passus.net.http.HttpResponseBuilder;
 import com.passus.net.http.HttpStatus;
 import static com.passus.st.client.http.HttpConsts.TAG_SESSION_ID;
+
+import com.passus.st.client.filter.FlowFilterFactory;
+import com.passus.st.client.filter.MessageWrapper;
 import com.passus.st.client.http.filter.HttpMessageWrapper;
 import static com.passus.st.utils.Assert.*;
 import org.testng.annotations.Test;
@@ -21,14 +24,14 @@
 
     private final HttpResponse RESP;
 
-    private final HttpMessageWrapper WRAPPER;
+    private final MessageWrapper WRAPPER;
 
     public HttpMessageWrapperDynamicExtractorTest() {
         REQ = HttpRequestBuilder.get("http://www.example.com/1")
                 .tag(TAG_SESSION_ID, "sid1").build();
 
         RESP = HttpResponseBuilder.ok().build();
-        WRAPPER = new HttpMessageWrapper(REQ, RESP, null);
+        WRAPPER = FlowFilterFactory.DEFAULT_FACTORY.createWrapper(REQ, RESP, null);
     }
 
     private Object extract(String expr) {
--- a/stress-tester/src/test/java/com/passus/st/filter/HttpMessageWrapperStaticExtractorTest.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/test/java/com/passus/st/filter/HttpMessageWrapperStaticExtractorTest.java	Wed Mar 25 11:02:10 2020 +0100
@@ -5,18 +5,19 @@
 import com.passus.net.http.HttpResponse;
 import com.passus.net.http.HttpResponseBuilder;
 import com.passus.st.client.FlowContext;
+import com.passus.st.client.filter.FlowFilterFactory;
 import com.passus.st.client.http.HttpConsts;
 import com.passus.st.client.http.HttpFlowConst;
 import com.passus.st.client.http.HttpFlowContext;
 import com.passus.st.client.http.HttpScopes;
 import com.passus.st.client.http.filter.HttpMessageWrapper;
-import static com.passus.st.filter.HttpMessageWrapperStaticExtractor.*;
-import static org.testng.AssertJUnit.*;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import static com.passus.st.filter.HttpMessageWrapperStaticExtractor.*;
+import static org.testng.AssertJUnit.*;
+
 /**
- *
  * @author mikolaj.podbielski
  */
 public class HttpMessageWrapperStaticExtractorTest {
@@ -60,19 +61,20 @@
         context.setParam(HttpFlowConst.PARAM_HTTP_CONTEXT, httpContext);
     }
 
-    private final HttpMessageWrapper WRAPPER = new HttpMessageWrapper(REQ, RESP, context);
-    private final HttpMessageWrapper NULL_WRAPPER = new HttpMessageWrapper(null, null, context);
+    private final HttpMessageWrapper WRAPPER = FlowFilterFactory.DEFAULT_FACTORY.createHttpMessageWrapper(REQ, RESP, context);
+
+    private final HttpMessageWrapper NULL_WRAPPER = FlowFilterFactory.DEFAULT_FACTORY.createHttpMessageWrapper(null, null, context);
 
     @DataProvider(name = "invalidExtractorRules")
     public Object[][] invalidExtractorRules() {
         return new Object[][]{
-            {"req.content@unknownLang:$.reqNode"},
-            {"req.content@json:$....reqNode"},
-            {"req.content@json:"},
-            {"req.content@json"},
-            {"req.content@"},
-            {"req.content@   "},
-            {"req.content#   "}
+                {"req.content@unknownLang:$.reqNode"},
+                {"req.content@json:$....reqNode"},
+                {"req.content@json:"},
+                {"req.content@json"},
+                {"req.content@"},
+                {"req.content@   "},
+                {"req.content#   "}
         };
     }
 
--- a/stress-tester/src/test/java/com/passus/st/vars/VarsConfiguratorTest.java	Tue Mar 24 14:36:47 2020 +0100
+++ b/stress-tester/src/test/java/com/passus/st/vars/VarsConfiguratorTest.java	Wed Mar 25 11:02:10 2020 +0100
@@ -2,21 +2,23 @@
 
 import com.passus.config.Configuration;
 import com.passus.config.YamlConfigurationReader;
-import com.passus.filter.BeanValueExtractor;
 import com.passus.filter.MvelValueExtractor;
 import com.passus.filter.UnmutableValueExtractor;
 import com.passus.filter.ValueExtractor;
 import com.passus.net.http.HttpRequest;
 import com.passus.net.http.HttpRequestBuilder;
+import com.passus.st.client.filter.FlowFilterFactory;
 import com.passus.st.client.http.filter.HttpMessageWrapper;
 import com.passus.st.filter.HttpMessageWrapperDynamicExtractor;
-import static com.passus.st.vars.VarsConfigurator.getGlobalVars;
-import java.util.Map;
-import static org.testng.AssertJUnit.*;
 import org.testng.annotations.Test;
 
+import java.util.Map;
+
+import static com.passus.st.vars.VarsConfigurator.getGlobalVars;
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertTrue;
+
 /**
- *
  * @author mikolaj.podbielski
  */
 public class VarsConfiguratorTest {
@@ -43,7 +45,7 @@
 
         ValueExtractor ve = vars.get("var3");
         HttpRequest request = HttpRequestBuilder.get("http://example.com/path").build();
-        HttpMessageWrapper wrapper = new HttpMessageWrapper(request, null, null);
+        HttpMessageWrapper wrapper = (HttpMessageWrapper) FlowFilterFactory.DEFAULT_FACTORY.createWrapper(request, null, null);
         assertEquals("http://example.com/path", ve.extract(wrapper).toString());
         assertTrue(ve instanceof HttpMessageWrapperDynamicExtractor);
 //        assertTrue(ve instanceof BeanValueExtractor || ve instanceof HttpMessageWrapperDynamicExtractor);