You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metron.apache.org by ce...@apache.org on 2016/06/16 16:02:52 UTC

[1/4] incubator-metron git commit: METRON-204: Field Transformation Domain Specific Language. This closes apache/incubator-metron#142

Repository: incubator-metron
Updated Branches:
  refs/heads/master 739e2eb52 -> bdbf33a9d


http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/fixed/FixedPcapFilter.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/fixed/FixedPcapFilter.java b/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/fixed/FixedPcapFilter.java
index ea46cc3..022fca2 100644
--- a/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/fixed/FixedPcapFilter.java
+++ b/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/fixed/FixedPcapFilter.java
@@ -21,7 +21,7 @@ package org.apache.metron.pcap.filter.fixed;
 import com.google.common.base.Joiner;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.metron.common.Constants;
-import org.apache.metron.common.query.VariableResolver;
+import org.apache.metron.common.dsl.VariableResolver;
 import org.apache.metron.pcap.PacketInfo;
 import org.apache.metron.pcap.PcapHelper;
 import org.apache.metron.pcap.filter.PcapFilter;
@@ -85,11 +85,11 @@ public class FixedPcapFilter implements PcapFilter {
   @Override
   public boolean test(PacketInfo pi) {
     VariableResolver resolver = new PcapFieldResolver(packetToFields(pi));
-    String srcAddrIn = resolver.resolve(Constants.Fields.SRC_ADDR.getName());
-    String srcPortIn = resolver.resolve(Constants.Fields.SRC_PORT.getName());
-    String dstAddrIn = resolver.resolve(Constants.Fields.DST_ADDR.getName());
-    String dstPortIn = resolver.resolve(Constants.Fields.DST_PORT.getName());
-    String protocolIn = resolver.resolve(Constants.Fields.PROTOCOL.getName());
+    String srcAddrIn = (String) resolver.resolve(Constants.Fields.SRC_ADDR.getName());
+    String srcPortIn = (String) resolver.resolve(Constants.Fields.SRC_PORT.getName());
+    String dstAddrIn = (String) resolver.resolve(Constants.Fields.DST_ADDR.getName());
+    String dstPortIn = (String) resolver.resolve(Constants.Fields.DST_PORT.getName());
+    String protocolIn = (String) resolver.resolve(Constants.Fields.PROTOCOL.getName());
 
     if (areMatch(protocol, protocolIn)) {
       if (matchesSourceAndDestination(srcAddrIn, srcPortIn, dstAddrIn, dstPortIn)) {

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/query/QueryPcapFilter.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/query/QueryPcapFilter.java b/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/query/QueryPcapFilter.java
index e97ed82..d0ca273 100644
--- a/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/query/QueryPcapFilter.java
+++ b/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/query/QueryPcapFilter.java
@@ -21,7 +21,7 @@ package org.apache.metron.pcap.filter.query;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.metron.common.Constants;
 import org.apache.metron.common.query.PredicateProcessor;
-import org.apache.metron.common.query.VariableResolver;
+import org.apache.metron.common.dsl.VariableResolver;
 import org.apache.metron.pcap.PacketInfo;
 import org.apache.metron.pcap.PcapHelper;
 import org.apache.metron.pcap.filter.PcapFieldResolver;

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/style/suppressions.xml
----------------------------------------------------------------------
diff --git a/metron-platform/style/suppressions.xml b/metron-platform/style/suppressions.xml
index be02dda..85d8db1 100644
--- a/metron-platform/style/suppressions.xml
+++ b/metron-platform/style/suppressions.xml
@@ -24,4 +24,8 @@
     <suppress checks="HeaderCheck"
               files="org[\\/]apache[\\/]metron[\\/]common[\\/]query[\\/]generated[\\/].*.java"
               />
+    <suppress checks="HeaderCheck"
+              files="org[\\/]apache[\\/]metron[\\/]common[\\/]transformation[\\/]generated[\\/].*.java"
+              />
+
 </suppressions>


[2/4] incubator-metron git commit: METRON-204: Field Transformation Domain Specific Language. This closes apache/incubator-metron#142

Posted by ce...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/TransformationBaseListener.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/TransformationBaseListener.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/TransformationBaseListener.java
new file mode 100644
index 0000000..d5387b6
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/TransformationBaseListener.java
@@ -0,0 +1,216 @@
+// Generated from org/apache/metron/common/transformation/generated/Transformation.g4 by ANTLR 4.5
+package org.apache.metron.common.transformation.generated;
+
+//CHECKSTYLE:OFF
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.misc.NotNull;
+import org.antlr.v4.runtime.tree.ErrorNode;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+/**
+ * This class provides an empty implementation of {@link TransformationListener},
+ * which can be extended to create a listener which only needs to handle a subset
+ * of the available methods.
+ */
+public class TransformationBaseListener implements TransformationListener {
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterTransformation(TransformationParser.TransformationContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitTransformation(TransformationParser.TransformationContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterTransformationExpr(TransformationParser.TransformationExprContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitTransformationExpr(TransformationParser.TransformationExprContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterTransformationEntity(TransformationParser.TransformationEntityContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitTransformationEntity(TransformationParser.TransformationEntityContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterTransformation_entity(TransformationParser.Transformation_entityContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitTransformation_entity(TransformationParser.Transformation_entityContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterFunc_args(TransformationParser.Func_argsContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitFunc_args(TransformationParser.Func_argsContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterOp_list(TransformationParser.Op_listContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitOp_list(TransformationParser.Op_listContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterList_entity(TransformationParser.List_entityContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitList_entity(TransformationParser.List_entityContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterStringLiteral(TransformationParser.StringLiteralContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitStringLiteral(TransformationParser.StringLiteralContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterIntegerLiteral(TransformationParser.IntegerLiteralContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitIntegerLiteral(TransformationParser.IntegerLiteralContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterDoubleLiteral(TransformationParser.DoubleLiteralContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitDoubleLiteral(TransformationParser.DoubleLiteralContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterVariable(TransformationParser.VariableContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitVariable(TransformationParser.VariableContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterTransformationFunc(TransformationParser.TransformationFuncContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitTransformationFunc(TransformationParser.TransformationFuncContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterList(TransformationParser.ListContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitList(TransformationParser.ListContext ctx) { }
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterEveryRule(ParserRuleContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitEveryRule(ParserRuleContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void visitTerminal(TerminalNode node) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void visitErrorNode(ErrorNode node) { }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/TransformationLexer.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/TransformationLexer.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/TransformationLexer.java
new file mode 100644
index 0000000..ca48a83
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/TransformationLexer.java
@@ -0,0 +1,148 @@
+// Generated from org/apache/metron/common/transformation/generated/Transformation.g4 by ANTLR 4.5
+package org.apache.metron.common.transformation.generated;
+
+//CHECKSTYLE:OFF
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.antlr.v4.runtime.Lexer;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenStream;
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.atn.*;
+import org.antlr.v4.runtime.dfa.DFA;
+import org.antlr.v4.runtime.misc.*;
+
+@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
+public class TransformationLexer extends Lexer {
+	static { RuntimeMetaData.checkVersion("4.5", RuntimeMetaData.VERSION); }
+
+	protected static final DFA[] _decisionToDFA;
+	protected static final PredictionContextCache _sharedContextCache =
+		new PredictionContextCache();
+	public static final int
+		COMMA=1, LBRACKET=2, RBRACKET=3, LPAREN=4, RPAREN=5, INT_LITERAL=6, DOUBLE_LITERAL=7, 
+		IDENTIFIER=8, STRING_LITERAL=9, COMMENT=10, WS=11;
+	public static String[] modeNames = {
+		"DEFAULT_MODE"
+	};
+
+	public static final String[] ruleNames = {
+		"COMMA", "LBRACKET", "RBRACKET", "LPAREN", "RPAREN", "INT_LITERAL", "DOUBLE_LITERAL", 
+		"IDENTIFIER", "SCHAR", "STRING_LITERAL", "COMMENT", "WS"
+	};
+
+	private static final String[] _LITERAL_NAMES = {
+		null, "','", "'['", "']'", "'('", "')'"
+	};
+	private static final String[] _SYMBOLIC_NAMES = {
+		null, "COMMA", "LBRACKET", "RBRACKET", "LPAREN", "RPAREN", "INT_LITERAL", 
+		"DOUBLE_LITERAL", "IDENTIFIER", "STRING_LITERAL", "COMMENT", "WS"
+	};
+	public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
+
+	/**
+	 * @deprecated Use {@link #VOCABULARY} instead.
+	 */
+	@Deprecated
+	public static final String[] tokenNames;
+	static {
+		tokenNames = new String[_SYMBOLIC_NAMES.length];
+		for (int i = 0; i < tokenNames.length; i++) {
+			tokenNames[i] = VOCABULARY.getLiteralName(i);
+			if (tokenNames[i] == null) {
+				tokenNames[i] = VOCABULARY.getSymbolicName(i);
+			}
+
+			if (tokenNames[i] == null) {
+				tokenNames[i] = "<INVALID>";
+			}
+		}
+	}
+
+	@Override
+	@Deprecated
+	public String[] getTokenNames() {
+		return tokenNames;
+	}
+
+	@Override
+
+	public Vocabulary getVocabulary() {
+		return VOCABULARY;
+	}
+
+
+	public TransformationLexer(CharStream input) {
+		super(input);
+		_interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
+	}
+
+	@Override
+	public String getGrammarFileName() { return "Transformation.g4"; }
+
+	@Override
+	public String[] getRuleNames() { return ruleNames; }
+
+	@Override
+	public String getSerializedATN() { return _serializedATN; }
+
+	@Override
+	public String[] getModeNames() { return modeNames; }
+
+	@Override
+	public ATN getATN() { return _ATN; }
+
+	public static final String _serializedATN =
+		"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2\rd\b\1\4\2\t\2\4"+
+		"\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t"+
+		"\13\4\f\t\f\4\r\t\r\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6\3\7\6\7\'"+
+		"\n\7\r\7\16\7(\3\b\6\b,\n\b\r\b\16\b-\3\b\3\b\6\b\62\n\b\r\b\16\b\63\3"+
+		"\t\3\t\7\t8\n\t\f\t\16\t;\13\t\3\n\3\n\3\13\3\13\7\13A\n\13\f\13\16\13"+
+		"D\13\13\3\13\3\13\3\13\7\13I\n\13\f\13\16\13L\13\13\3\13\5\13O\n\13\3"+
+		"\f\3\f\3\f\3\f\6\fU\n\f\r\f\16\fV\3\f\5\fZ\n\f\3\f\3\f\3\r\6\r_\n\r\r"+
+		"\r\16\r`\3\r\3\r\3V\2\16\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\2\25\13"+
+		"\27\f\31\r\3\2\7\5\2C\\aac|\b\2\60\60\62;C\\^^aac|\7\2\f\f\17\17$$))^"+
+		"^\3\3\f\f\5\2\13\f\16\17\"\"k\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t"+
+		"\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\25\3\2\2"+
+		"\2\2\27\3\2\2\2\2\31\3\2\2\2\3\33\3\2\2\2\5\35\3\2\2\2\7\37\3\2\2\2\t"+
+		"!\3\2\2\2\13#\3\2\2\2\r&\3\2\2\2\17+\3\2\2\2\21\65\3\2\2\2\23<\3\2\2\2"+
+		"\25N\3\2\2\2\27P\3\2\2\2\31^\3\2\2\2\33\34\7.\2\2\34\4\3\2\2\2\35\36\7"+
+		"]\2\2\36\6\3\2\2\2\37 \7_\2\2 \b\3\2\2\2!\"\7*\2\2\"\n\3\2\2\2#$\7+\2"+
+		"\2$\f\3\2\2\2%\'\4\62;\2&%\3\2\2\2\'(\3\2\2\2(&\3\2\2\2()\3\2\2\2)\16"+
+		"\3\2\2\2*,\4\62;\2+*\3\2\2\2,-\3\2\2\2-+\3\2\2\2-.\3\2\2\2./\3\2\2\2/"+
+		"\61\7\60\2\2\60\62\4\62;\2\61\60\3\2\2\2\62\63\3\2\2\2\63\61\3\2\2\2\63"+
+		"\64\3\2\2\2\64\20\3\2\2\2\659\t\2\2\2\668\t\3\2\2\67\66\3\2\2\28;\3\2"+
+		"\2\29\67\3\2\2\29:\3\2\2\2:\22\3\2\2\2;9\3\2\2\2<=\n\4\2\2=\24\3\2\2\2"+
+		">B\7$\2\2?A\5\23\n\2@?\3\2\2\2AD\3\2\2\2B@\3\2\2\2BC\3\2\2\2CE\3\2\2\2"+
+		"DB\3\2\2\2EO\7$\2\2FJ\7)\2\2GI\5\23\n\2HG\3\2\2\2IL\3\2\2\2JH\3\2\2\2"+
+		"JK\3\2\2\2KM\3\2\2\2LJ\3\2\2\2MO\7)\2\2N>\3\2\2\2NF\3\2\2\2O\26\3\2\2"+
+		"\2PQ\7\61\2\2QR\7\61\2\2RT\3\2\2\2SU\13\2\2\2TS\3\2\2\2UV\3\2\2\2VW\3"+
+		"\2\2\2VT\3\2\2\2WY\3\2\2\2XZ\t\5\2\2YX\3\2\2\2Z[\3\2\2\2[\\\b\f\2\2\\"+
+		"\30\3\2\2\2]_\t\6\2\2^]\3\2\2\2_`\3\2\2\2`^\3\2\2\2`a\3\2\2\2ab\3\2\2"+
+		"\2bc\b\r\2\2c\32\3\2\2\2\r\2(-\639BJNVY`\3\b\2\2";
+	public static final ATN _ATN =
+		new ATNDeserializer().deserialize(_serializedATN.toCharArray());
+	static {
+		_decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
+		for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
+			_decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/TransformationListener.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/TransformationListener.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/TransformationListener.java
new file mode 100644
index 0000000..c9673cb
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/TransformationListener.java
@@ -0,0 +1,177 @@
+// Generated from org/apache/metron/common/transformation/generated/Transformation.g4 by ANTLR 4.5
+package org.apache.metron.common.transformation.generated;
+
+//CHECKSTYLE:OFF
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.antlr.v4.runtime.misc.NotNull;
+import org.antlr.v4.runtime.tree.ParseTreeListener;
+
+/**
+ * This interface defines a complete listener for a parse tree produced by
+ * {@link TransformationParser}.
+ */
+public interface TransformationListener extends ParseTreeListener {
+	/**
+	 * Enter a parse tree produced by {@link TransformationParser#transformation}.
+	 * @param ctx the parse tree
+	 */
+	void enterTransformation(TransformationParser.TransformationContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link TransformationParser#transformation}.
+	 * @param ctx the parse tree
+	 */
+	void exitTransformation(TransformationParser.TransformationContext ctx);
+	/**
+	 * Enter a parse tree produced by the {@code TransformationExpr}
+	 * labeled alternative in {@link TransformationParser#transformation_expr}.
+	 * @param ctx the parse tree
+	 */
+	void enterTransformationExpr(TransformationParser.TransformationExprContext ctx);
+	/**
+	 * Exit a parse tree produced by the {@code TransformationExpr}
+	 * labeled alternative in {@link TransformationParser#transformation_expr}.
+	 * @param ctx the parse tree
+	 */
+	void exitTransformationExpr(TransformationParser.TransformationExprContext ctx);
+	/**
+	 * Enter a parse tree produced by the {@code TransformationEntity}
+	 * labeled alternative in {@link TransformationParser#transformation_expr}.
+	 * @param ctx the parse tree
+	 */
+	void enterTransformationEntity(TransformationParser.TransformationEntityContext ctx);
+	/**
+	 * Exit a parse tree produced by the {@code TransformationEntity}
+	 * labeled alternative in {@link TransformationParser#transformation_expr}.
+	 * @param ctx the parse tree
+	 */
+	void exitTransformationEntity(TransformationParser.TransformationEntityContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link TransformationParser#transformation_entity}.
+	 * @param ctx the parse tree
+	 */
+	void enterTransformation_entity(TransformationParser.Transformation_entityContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link TransformationParser#transformation_entity}.
+	 * @param ctx the parse tree
+	 */
+	void exitTransformation_entity(TransformationParser.Transformation_entityContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link TransformationParser#func_args}.
+	 * @param ctx the parse tree
+	 */
+	void enterFunc_args(TransformationParser.Func_argsContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link TransformationParser#func_args}.
+	 * @param ctx the parse tree
+	 */
+	void exitFunc_args(TransformationParser.Func_argsContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link TransformationParser#op_list}.
+	 * @param ctx the parse tree
+	 */
+	void enterOp_list(TransformationParser.Op_listContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link TransformationParser#op_list}.
+	 * @param ctx the parse tree
+	 */
+	void exitOp_list(TransformationParser.Op_listContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link TransformationParser#list_entity}.
+	 * @param ctx the parse tree
+	 */
+	void enterList_entity(TransformationParser.List_entityContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link TransformationParser#list_entity}.
+	 * @param ctx the parse tree
+	 */
+	void exitList_entity(TransformationParser.List_entityContext ctx);
+	/**
+	 * Enter a parse tree produced by the {@code StringLiteral}
+	 * labeled alternative in {@link TransformationParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void enterStringLiteral(TransformationParser.StringLiteralContext ctx);
+	/**
+	 * Exit a parse tree produced by the {@code StringLiteral}
+	 * labeled alternative in {@link TransformationParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void exitStringLiteral(TransformationParser.StringLiteralContext ctx);
+	/**
+	 * Enter a parse tree produced by the {@code IntegerLiteral}
+	 * labeled alternative in {@link TransformationParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void enterIntegerLiteral(TransformationParser.IntegerLiteralContext ctx);
+	/**
+	 * Exit a parse tree produced by the {@code IntegerLiteral}
+	 * labeled alternative in {@link TransformationParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void exitIntegerLiteral(TransformationParser.IntegerLiteralContext ctx);
+	/**
+	 * Enter a parse tree produced by the {@code DoubleLiteral}
+	 * labeled alternative in {@link TransformationParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void enterDoubleLiteral(TransformationParser.DoubleLiteralContext ctx);
+	/**
+	 * Exit a parse tree produced by the {@code DoubleLiteral}
+	 * labeled alternative in {@link TransformationParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void exitDoubleLiteral(TransformationParser.DoubleLiteralContext ctx);
+	/**
+	 * Enter a parse tree produced by the {@code Variable}
+	 * labeled alternative in {@link TransformationParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void enterVariable(TransformationParser.VariableContext ctx);
+	/**
+	 * Exit a parse tree produced by the {@code Variable}
+	 * labeled alternative in {@link TransformationParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void exitVariable(TransformationParser.VariableContext ctx);
+	/**
+	 * Enter a parse tree produced by the {@code TransformationFunc}
+	 * labeled alternative in {@link TransformationParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void enterTransformationFunc(TransformationParser.TransformationFuncContext ctx);
+	/**
+	 * Exit a parse tree produced by the {@code TransformationFunc}
+	 * labeled alternative in {@link TransformationParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void exitTransformationFunc(TransformationParser.TransformationFuncContext ctx);
+	/**
+	 * Enter a parse tree produced by the {@code List}
+	 * labeled alternative in {@link TransformationParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void enterList(TransformationParser.ListContext ctx);
+	/**
+	 * Exit a parse tree produced by the {@code List}
+	 * labeled alternative in {@link TransformationParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void exitList(TransformationParser.ListContext ctx);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/TransformationParser.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/TransformationParser.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/TransformationParser.java
new file mode 100644
index 0000000..48fd820
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/TransformationParser.java
@@ -0,0 +1,640 @@
+// Generated from org/apache/metron/common/transformation/generated/Transformation.g4 by ANTLR 4.5
+package org.apache.metron.common.transformation.generated;
+
+//CHECKSTYLE:OFF
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.antlr.v4.runtime.atn.*;
+import org.antlr.v4.runtime.dfa.DFA;
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.misc.*;
+import org.antlr.v4.runtime.tree.*;
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
+public class TransformationParser extends Parser {
+	static { RuntimeMetaData.checkVersion("4.5", RuntimeMetaData.VERSION); }
+
+	protected static final DFA[] _decisionToDFA;
+	protected static final PredictionContextCache _sharedContextCache =
+		new PredictionContextCache();
+	public static final int
+		COMMA=1, LBRACKET=2, RBRACKET=3, LPAREN=4, RPAREN=5, INT_LITERAL=6, DOUBLE_LITERAL=7, 
+		IDENTIFIER=8, STRING_LITERAL=9, COMMENT=10, WS=11;
+	public static final int
+		RULE_transformation = 0, RULE_transformation_expr = 1, RULE_transformation_entity = 2, 
+		RULE_func_args = 3, RULE_op_list = 4, RULE_list_entity = 5, RULE_identifier_operand = 6;
+	public static final String[] ruleNames = {
+		"transformation", "transformation_expr", "transformation_entity", "func_args", 
+		"op_list", "list_entity", "identifier_operand"
+	};
+
+	private static final String[] _LITERAL_NAMES = {
+		null, "','", "'['", "']'", "'('", "')'"
+	};
+	private static final String[] _SYMBOLIC_NAMES = {
+		null, "COMMA", "LBRACKET", "RBRACKET", "LPAREN", "RPAREN", "INT_LITERAL", 
+		"DOUBLE_LITERAL", "IDENTIFIER", "STRING_LITERAL", "COMMENT", "WS"
+	};
+	public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
+
+	/**
+	 * @deprecated Use {@link #VOCABULARY} instead.
+	 */
+	@Deprecated
+	public static final String[] tokenNames;
+	static {
+		tokenNames = new String[_SYMBOLIC_NAMES.length];
+		for (int i = 0; i < tokenNames.length; i++) {
+			tokenNames[i] = VOCABULARY.getLiteralName(i);
+			if (tokenNames[i] == null) {
+				tokenNames[i] = VOCABULARY.getSymbolicName(i);
+			}
+
+			if (tokenNames[i] == null) {
+				tokenNames[i] = "<INVALID>";
+			}
+		}
+	}
+
+	@Override
+	@Deprecated
+	public String[] getTokenNames() {
+		return tokenNames;
+	}
+
+	@Override
+
+	public Vocabulary getVocabulary() {
+		return VOCABULARY;
+	}
+
+	@Override
+	public String getGrammarFileName() { return "Transformation.g4"; }
+
+	@Override
+	public String[] getRuleNames() { return ruleNames; }
+
+	@Override
+	public String getSerializedATN() { return _serializedATN; }
+
+	@Override
+	public ATN getATN() { return _ATN; }
+
+	public TransformationParser(TokenStream input) {
+		super(input);
+		_interp = new ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
+	}
+	public static class TransformationContext extends ParserRuleContext {
+		public Transformation_exprContext transformation_expr() {
+			return getRuleContext(Transformation_exprContext.class,0);
+		}
+		public TerminalNode EOF() { return getToken(TransformationParser.EOF, 0); }
+		public TransformationContext(ParserRuleContext parent, int invokingState) {
+			super(parent, invokingState);
+		}
+		@Override public int getRuleIndex() { return RULE_transformation; }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).enterTransformation(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).exitTransformation(this);
+		}
+	}
+
+	public final TransformationContext transformation() throws RecognitionException {
+		TransformationContext _localctx = new TransformationContext(_ctx, getState());
+		enterRule(_localctx, 0, RULE_transformation);
+		try {
+			enterOuterAlt(_localctx, 1);
+			{
+			setState(14);
+			transformation_expr();
+			setState(15);
+			match(EOF);
+			}
+		}
+		catch (RecognitionException re) {
+			_localctx.exception = re;
+			_errHandler.reportError(this, re);
+			_errHandler.recover(this, re);
+		}
+		finally {
+			exitRule();
+		}
+		return _localctx;
+	}
+
+	public static class Transformation_exprContext extends ParserRuleContext {
+		public Transformation_exprContext(ParserRuleContext parent, int invokingState) {
+			super(parent, invokingState);
+		}
+		@Override public int getRuleIndex() { return RULE_transformation_expr; }
+	 
+		public Transformation_exprContext() { }
+		public void copyFrom(Transformation_exprContext ctx) {
+			super.copyFrom(ctx);
+		}
+	}
+	public static class TransformationEntityContext extends Transformation_exprContext {
+		public Transformation_entityContext transformation_entity() {
+			return getRuleContext(Transformation_entityContext.class,0);
+		}
+		public TransformationEntityContext(Transformation_exprContext ctx) { copyFrom(ctx); }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).enterTransformationEntity(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).exitTransformationEntity(this);
+		}
+	}
+	public static class TransformationExprContext extends Transformation_exprContext {
+		public TerminalNode LPAREN() { return getToken(TransformationParser.LPAREN, 0); }
+		public Transformation_exprContext transformation_expr() {
+			return getRuleContext(Transformation_exprContext.class,0);
+		}
+		public TerminalNode RPAREN() { return getToken(TransformationParser.RPAREN, 0); }
+		public TransformationExprContext(Transformation_exprContext ctx) { copyFrom(ctx); }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).enterTransformationExpr(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).exitTransformationExpr(this);
+		}
+	}
+
+	public final Transformation_exprContext transformation_expr() throws RecognitionException {
+		Transformation_exprContext _localctx = new Transformation_exprContext(_ctx, getState());
+		enterRule(_localctx, 2, RULE_transformation_expr);
+		try {
+			setState(22);
+			switch (_input.LA(1)) {
+			case LPAREN:
+				_localctx = new TransformationExprContext(_localctx);
+				enterOuterAlt(_localctx, 1);
+				{
+				setState(17);
+				match(LPAREN);
+				setState(18);
+				transformation_expr();
+				setState(19);
+				match(RPAREN);
+				}
+				break;
+			case LBRACKET:
+			case INT_LITERAL:
+			case DOUBLE_LITERAL:
+			case IDENTIFIER:
+			case STRING_LITERAL:
+				_localctx = new TransformationEntityContext(_localctx);
+				enterOuterAlt(_localctx, 2);
+				{
+				setState(21);
+				transformation_entity();
+				}
+				break;
+			default:
+				throw new NoViableAltException(this);
+			}
+		}
+		catch (RecognitionException re) {
+			_localctx.exception = re;
+			_errHandler.reportError(this, re);
+			_errHandler.recover(this, re);
+		}
+		finally {
+			exitRule();
+		}
+		return _localctx;
+	}
+
+	public static class Transformation_entityContext extends ParserRuleContext {
+		public Identifier_operandContext identifier_operand() {
+			return getRuleContext(Identifier_operandContext.class,0);
+		}
+		public Transformation_entityContext(ParserRuleContext parent, int invokingState) {
+			super(parent, invokingState);
+		}
+		@Override public int getRuleIndex() { return RULE_transformation_entity; }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).enterTransformation_entity(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).exitTransformation_entity(this);
+		}
+	}
+
+	public final Transformation_entityContext transformation_entity() throws RecognitionException {
+		Transformation_entityContext _localctx = new Transformation_entityContext(_ctx, getState());
+		enterRule(_localctx, 4, RULE_transformation_entity);
+		try {
+			enterOuterAlt(_localctx, 1);
+			{
+			setState(24);
+			identifier_operand();
+			}
+		}
+		catch (RecognitionException re) {
+			_localctx.exception = re;
+			_errHandler.reportError(this, re);
+			_errHandler.recover(this, re);
+		}
+		finally {
+			exitRule();
+		}
+		return _localctx;
+	}
+
+	public static class Func_argsContext extends ParserRuleContext {
+		public Op_listContext op_list() {
+			return getRuleContext(Op_listContext.class,0);
+		}
+		public Func_argsContext(ParserRuleContext parent, int invokingState) {
+			super(parent, invokingState);
+		}
+		@Override public int getRuleIndex() { return RULE_func_args; }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).enterFunc_args(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).exitFunc_args(this);
+		}
+	}
+
+	public final Func_argsContext func_args() throws RecognitionException {
+		Func_argsContext _localctx = new Func_argsContext(_ctx, getState());
+		enterRule(_localctx, 6, RULE_func_args);
+		try {
+			enterOuterAlt(_localctx, 1);
+			{
+			setState(26);
+			op_list(0);
+			}
+		}
+		catch (RecognitionException re) {
+			_localctx.exception = re;
+			_errHandler.reportError(this, re);
+			_errHandler.recover(this, re);
+		}
+		finally {
+			exitRule();
+		}
+		return _localctx;
+	}
+
+	public static class Op_listContext extends ParserRuleContext {
+		public Identifier_operandContext identifier_operand() {
+			return getRuleContext(Identifier_operandContext.class,0);
+		}
+		public Op_listContext op_list() {
+			return getRuleContext(Op_listContext.class,0);
+		}
+		public TerminalNode COMMA() { return getToken(TransformationParser.COMMA, 0); }
+		public Op_listContext(ParserRuleContext parent, int invokingState) {
+			super(parent, invokingState);
+		}
+		@Override public int getRuleIndex() { return RULE_op_list; }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).enterOp_list(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).exitOp_list(this);
+		}
+	}
+
+	public final Op_listContext op_list() throws RecognitionException {
+		return op_list(0);
+	}
+
+	private Op_listContext op_list(int _p) throws RecognitionException {
+		ParserRuleContext _parentctx = _ctx;
+		int _parentState = getState();
+		Op_listContext _localctx = new Op_listContext(_ctx, _parentState);
+		Op_listContext _prevctx = _localctx;
+		int _startState = 8;
+		enterRecursionRule(_localctx, 8, RULE_op_list, _p);
+		try {
+			int _alt;
+			enterOuterAlt(_localctx, 1);
+			{
+			{
+			setState(29);
+			identifier_operand();
+			}
+			_ctx.stop = _input.LT(-1);
+			setState(36);
+			_errHandler.sync(this);
+			_alt = getInterpreter().adaptivePredict(_input,1,_ctx);
+			while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
+				if ( _alt==1 ) {
+					if ( _parseListeners!=null ) triggerExitRuleEvent();
+					_prevctx = _localctx;
+					{
+					{
+					_localctx = new Op_listContext(_parentctx, _parentState);
+					pushNewRecursionContext(_localctx, _startState, RULE_op_list);
+					setState(31);
+					if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)");
+					setState(32);
+					match(COMMA);
+					setState(33);
+					identifier_operand();
+					}
+					} 
+				}
+				setState(38);
+				_errHandler.sync(this);
+				_alt = getInterpreter().adaptivePredict(_input,1,_ctx);
+			}
+			}
+		}
+		catch (RecognitionException re) {
+			_localctx.exception = re;
+			_errHandler.reportError(this, re);
+			_errHandler.recover(this, re);
+		}
+		finally {
+			unrollRecursionContexts(_parentctx);
+		}
+		return _localctx;
+	}
+
+	public static class List_entityContext extends ParserRuleContext {
+		public TerminalNode LBRACKET() { return getToken(TransformationParser.LBRACKET, 0); }
+		public Op_listContext op_list() {
+			return getRuleContext(Op_listContext.class,0);
+		}
+		public TerminalNode RBRACKET() { return getToken(TransformationParser.RBRACKET, 0); }
+		public List_entityContext(ParserRuleContext parent, int invokingState) {
+			super(parent, invokingState);
+		}
+		@Override public int getRuleIndex() { return RULE_list_entity; }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).enterList_entity(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).exitList_entity(this);
+		}
+	}
+
+	public final List_entityContext list_entity() throws RecognitionException {
+		List_entityContext _localctx = new List_entityContext(_ctx, getState());
+		enterRule(_localctx, 10, RULE_list_entity);
+		try {
+			enterOuterAlt(_localctx, 1);
+			{
+			setState(39);
+			match(LBRACKET);
+			setState(40);
+			op_list(0);
+			setState(41);
+			match(RBRACKET);
+			}
+		}
+		catch (RecognitionException re) {
+			_localctx.exception = re;
+			_errHandler.reportError(this, re);
+			_errHandler.recover(this, re);
+		}
+		finally {
+			exitRule();
+		}
+		return _localctx;
+	}
+
+	public static class Identifier_operandContext extends ParserRuleContext {
+		public Identifier_operandContext(ParserRuleContext parent, int invokingState) {
+			super(parent, invokingState);
+		}
+		@Override public int getRuleIndex() { return RULE_identifier_operand; }
+	 
+		public Identifier_operandContext() { }
+		public void copyFrom(Identifier_operandContext ctx) {
+			super.copyFrom(ctx);
+		}
+	}
+	public static class VariableContext extends Identifier_operandContext {
+		public TerminalNode IDENTIFIER() { return getToken(TransformationParser.IDENTIFIER, 0); }
+		public VariableContext(Identifier_operandContext ctx) { copyFrom(ctx); }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).enterVariable(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).exitVariable(this);
+		}
+	}
+	public static class StringLiteralContext extends Identifier_operandContext {
+		public TerminalNode STRING_LITERAL() { return getToken(TransformationParser.STRING_LITERAL, 0); }
+		public StringLiteralContext(Identifier_operandContext ctx) { copyFrom(ctx); }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).enterStringLiteral(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).exitStringLiteral(this);
+		}
+	}
+	public static class TransformationFuncContext extends Identifier_operandContext {
+		public TerminalNode IDENTIFIER() { return getToken(TransformationParser.IDENTIFIER, 0); }
+		public TerminalNode LPAREN() { return getToken(TransformationParser.LPAREN, 0); }
+		public Func_argsContext func_args() {
+			return getRuleContext(Func_argsContext.class,0);
+		}
+		public TerminalNode RPAREN() { return getToken(TransformationParser.RPAREN, 0); }
+		public TransformationFuncContext(Identifier_operandContext ctx) { copyFrom(ctx); }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).enterTransformationFunc(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).exitTransformationFunc(this);
+		}
+	}
+	public static class ListContext extends Identifier_operandContext {
+		public List_entityContext list_entity() {
+			return getRuleContext(List_entityContext.class,0);
+		}
+		public ListContext(Identifier_operandContext ctx) { copyFrom(ctx); }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).enterList(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).exitList(this);
+		}
+	}
+	public static class DoubleLiteralContext extends Identifier_operandContext {
+		public TerminalNode DOUBLE_LITERAL() { return getToken(TransformationParser.DOUBLE_LITERAL, 0); }
+		public DoubleLiteralContext(Identifier_operandContext ctx) { copyFrom(ctx); }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).enterDoubleLiteral(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).exitDoubleLiteral(this);
+		}
+	}
+	public static class IntegerLiteralContext extends Identifier_operandContext {
+		public TerminalNode INT_LITERAL() { return getToken(TransformationParser.INT_LITERAL, 0); }
+		public IntegerLiteralContext(Identifier_operandContext ctx) { copyFrom(ctx); }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).enterIntegerLiteral(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof TransformationListener ) ((TransformationListener)listener).exitIntegerLiteral(this);
+		}
+	}
+
+	public final Identifier_operandContext identifier_operand() throws RecognitionException {
+		Identifier_operandContext _localctx = new Identifier_operandContext(_ctx, getState());
+		enterRule(_localctx, 12, RULE_identifier_operand);
+		try {
+			setState(53);
+			switch ( getInterpreter().adaptivePredict(_input,2,_ctx) ) {
+			case 1:
+				_localctx = new StringLiteralContext(_localctx);
+				enterOuterAlt(_localctx, 1);
+				{
+				setState(43);
+				match(STRING_LITERAL);
+				}
+				break;
+			case 2:
+				_localctx = new IntegerLiteralContext(_localctx);
+				enterOuterAlt(_localctx, 2);
+				{
+				setState(44);
+				match(INT_LITERAL);
+				}
+				break;
+			case 3:
+				_localctx = new DoubleLiteralContext(_localctx);
+				enterOuterAlt(_localctx, 3);
+				{
+				setState(45);
+				match(DOUBLE_LITERAL);
+				}
+				break;
+			case 4:
+				_localctx = new VariableContext(_localctx);
+				enterOuterAlt(_localctx, 4);
+				{
+				setState(46);
+				match(IDENTIFIER);
+				}
+				break;
+			case 5:
+				_localctx = new TransformationFuncContext(_localctx);
+				enterOuterAlt(_localctx, 5);
+				{
+				setState(47);
+				match(IDENTIFIER);
+				setState(48);
+				match(LPAREN);
+				setState(49);
+				func_args();
+				setState(50);
+				match(RPAREN);
+				}
+				break;
+			case 6:
+				_localctx = new ListContext(_localctx);
+				enterOuterAlt(_localctx, 6);
+				{
+				setState(52);
+				list_entity();
+				}
+				break;
+			}
+		}
+		catch (RecognitionException re) {
+			_localctx.exception = re;
+			_errHandler.reportError(this, re);
+			_errHandler.recover(this, re);
+		}
+		finally {
+			exitRule();
+		}
+		return _localctx;
+	}
+
+	public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) {
+		switch (ruleIndex) {
+		case 4:
+			return op_list_sempred((Op_listContext)_localctx, predIndex);
+		}
+		return true;
+	}
+	private boolean op_list_sempred(Op_listContext _localctx, int predIndex) {
+		switch (predIndex) {
+		case 0:
+			return precpred(_ctx, 1);
+		}
+		return true;
+	}
+
+	public static final String _serializedATN =
+		"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3\r:\4\2\t\2\4\3\t"+
+		"\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\3\2\3\2\3\2\3\3\3\3\3\3\3\3"+
+		"\3\3\5\3\31\n\3\3\4\3\4\3\5\3\5\3\6\3\6\3\6\3\6\3\6\3\6\7\6%\n\6\f\6\16"+
+		"\6(\13\6\3\7\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\5\b8"+
+		"\n\b\3\b\2\3\n\t\2\4\6\b\n\f\16\2\29\2\20\3\2\2\2\4\30\3\2\2\2\6\32\3"+
+		"\2\2\2\b\34\3\2\2\2\n\36\3\2\2\2\f)\3\2\2\2\16\67\3\2\2\2\20\21\5\4\3"+
+		"\2\21\22\7\2\2\3\22\3\3\2\2\2\23\24\7\6\2\2\24\25\5\4\3\2\25\26\7\7\2"+
+		"\2\26\31\3\2\2\2\27\31\5\6\4\2\30\23\3\2\2\2\30\27\3\2\2\2\31\5\3\2\2"+
+		"\2\32\33\5\16\b\2\33\7\3\2\2\2\34\35\5\n\6\2\35\t\3\2\2\2\36\37\b\6\1"+
+		"\2\37 \5\16\b\2 &\3\2\2\2!\"\f\3\2\2\"#\7\3\2\2#%\5\16\b\2$!\3\2\2\2%"+
+		"(\3\2\2\2&$\3\2\2\2&\'\3\2\2\2\'\13\3\2\2\2(&\3\2\2\2)*\7\4\2\2*+\5\n"+
+		"\6\2+,\7\5\2\2,\r\3\2\2\2-8\7\13\2\2.8\7\b\2\2/8\7\t\2\2\608\7\n\2\2\61"+
+		"\62\7\n\2\2\62\63\7\6\2\2\63\64\5\b\5\2\64\65\7\7\2\2\658\3\2\2\2\668"+
+		"\5\f\7\2\67-\3\2\2\2\67.\3\2\2\2\67/\3\2\2\2\67\60\3\2\2\2\67\61\3\2\2"+
+		"\2\67\66\3\2\2\28\17\3\2\2\2\5\30&\67";
+	public static final ATN _ATN =
+		new ATNDeserializer().deserialize(_serializedATN.toCharArray());
+	static {
+		_decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
+		for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
+			_decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/test/java/org/apache/metron/common/AggregatorsTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/test/java/org/apache/metron/common/AggregatorsTest.java b/metron-platform/metron-common/src/test/java/org/apache/metron/common/AggregatorsTest.java
new file mode 100644
index 0000000..ab3eb1d
--- /dev/null
+++ b/metron-platform/metron-common/src/test/java/org/apache/metron/common/AggregatorsTest.java
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.apache.metron.common.aggregator.Aggregators;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.HashMap;
+
+public class AggregatorsTest {
+  @Test
+  public void testMax() {
+    Assert.assertEquals(Double.NEGATIVE_INFINITY, Aggregators.MAX.aggregate(ImmutableList.of(1, 5, -1, 7), new HashMap<>()), 1e-7);
+    Assert.assertEquals(Double.NEGATIVE_INFINITY, Aggregators.MAX.aggregate(ImmutableList.of(1, 5, -1, -2), new HashMap<>()), 1e-7);
+    Assert.assertEquals(7d, Aggregators.MAX.aggregate(ImmutableList.of(1, 5, -1, 7, 0), ImmutableMap.of(Aggregators.NEGATIVE_VALUES_TRUMP_CONF, "false")), 1e-7);
+  }
+
+  @Test
+  public void testMin() {
+    Assert.assertEquals(Double.NEGATIVE_INFINITY, Aggregators.MIN.aggregate(ImmutableList.of(1, 5, -1, 7, 0), new HashMap<>()), 1e-7);
+    Assert.assertEquals(Double.NEGATIVE_INFINITY, Aggregators.MIN.aggregate(ImmutableList.of(1, 5, -1, -2, 0), new HashMap<>()), 1e-7);
+    Assert.assertEquals(-1d, Aggregators.MIN.aggregate(ImmutableList.of(1, 5, -1, 7, 0), ImmutableMap.of(Aggregators.NEGATIVE_VALUES_TRUMP_CONF, "false")), 1e-7);
+  }
+
+  @Test
+  public void testMean() {
+    Assert.assertEquals(Double.NEGATIVE_INFINITY, Aggregators.MEAN.aggregate(ImmutableList.of(1, 5, -1, 7, 0), new HashMap<>()), 1e-7);
+    Assert.assertEquals(12.0/5.0, Aggregators.MEAN.aggregate(ImmutableList.of(1, 5, -1, 7, 0), ImmutableMap.of(Aggregators.NEGATIVE_VALUES_TRUMP_CONF, "false")), 1e-7);
+  }
+  @Test
+  public void testPositiveMean() {
+    Assert.assertEquals(Double.NEGATIVE_INFINITY, Aggregators.POSITIVE_MEAN.aggregate(ImmutableList.of(1, 5, -1, 7, 0), new HashMap<>()), 1e-7);
+    Assert.assertEquals(13.0/3.0, Aggregators.POSITIVE_MEAN.aggregate(ImmutableList.of(1, 5, -1, 7, 0), ImmutableMap.of(Aggregators.NEGATIVE_VALUES_TRUMP_CONF, "false")), 1e-7);
+  }
+  @Test
+  public void testSum() {
+    Assert.assertEquals(Double.NEGATIVE_INFINITY, Aggregators.SUM.aggregate(ImmutableList.of(1, 5, -1, 7), new HashMap<>()), 1e-7);
+    Assert.assertEquals(1 + 5 + -1 + 7, Aggregators.SUM.aggregate(ImmutableList.of(1, 5, -1, 7), ImmutableMap.of(Aggregators.NEGATIVE_VALUES_TRUMP_CONF, "false")), 1e-7);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/test/java/org/apache/metron/common/field/transformation/MTLTransformationTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/test/java/org/apache/metron/common/field/transformation/MTLTransformationTest.java b/metron-platform/metron-common/src/test/java/org/apache/metron/common/field/transformation/MTLTransformationTest.java
new file mode 100644
index 0000000..53373dd
--- /dev/null
+++ b/metron-platform/metron-common/src/test/java/org/apache/metron/common/field/transformation/MTLTransformationTest.java
@@ -0,0 +1,167 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common.field.transformation;
+
+import com.google.common.collect.Iterables;
+import org.adrianwalker.multilinestring.Multiline;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.metron.common.configuration.FieldTransformer;
+import org.apache.metron.common.configuration.SensorParserConfig;
+import org.json.simple.JSONObject;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.HashMap;
+
+public class MTLTransformationTest {
+  /**
+   {
+    "fieldTransformations" : [
+          {
+           "transformation" : "MTL"
+          ,"output" : "utc_timestamp"
+          ,"config" : {
+            "utc_timestamp" : "TO_EPOCH_TIMESTAMP(timestamp, 'yyyy-MM-dd HH:mm:ss', 'UTC')"
+                      }
+          }
+                      ]
+   }
+   */
+  @Multiline
+  public static String mtlConfig;
+  /**
+   * Test the happy path.  This ensures that a simple transformation, converting a timestamp in a yyyy-MM-dd HH:mm:ss
+   * format can be converted to the expected UTC MS since Epoch.
+   */
+  @Test
+  public void testMTL() throws Exception {
+
+    SensorParserConfig c = SensorParserConfig.fromBytes(Bytes.toBytes(mtlConfig));
+    FieldTransformer handler = Iterables.getFirst(c.getFieldTransformations(), null);
+    JSONObject input = new JSONObject(new HashMap<String, Object>() {{
+      put("timestamp", "2016-01-05 17:02:30");
+    }});
+    handler.transformAndUpdate(input, new HashMap<>());
+    long expected = 1452013350000L;
+    Assert.assertEquals(expected, input.get("utc_timestamp"));
+    Assert.assertTrue(input.containsKey("timestamp"));
+  }
+  /**
+   * Ensures that if we try to transform with a field which does not exist, it does not
+   * 1. throw an exception
+   * 2. do any transformation.
+   */
+  @Test
+  public void testMTL_negative() throws Exception {
+
+    SensorParserConfig c = SensorParserConfig.fromBytes(Bytes.toBytes(mtlConfig));
+    FieldTransformer handler = Iterables.getFirst(c.getFieldTransformations(), null);
+    //no input fields => no transformation
+    JSONObject input = new JSONObject(new HashMap<String, Object>() {{
+    }});
+    handler.transformAndUpdate(input, new HashMap<>());
+    Assert.assertFalse(input.containsKey("utc_timestamp"));
+    Assert.assertTrue(input.isEmpty());
+  }
+
+  /**
+   {
+    "fieldTransformations" : [
+          {
+           "transformation" : "MTL"
+          ,"output" : [ "utc_timestamp", "url_host", "url_protocol" ]
+          ,"config" : {
+            "utc_timestamp" : "TO_EPOCH_TIMESTAMP(timestamp, 'yyyy-MM-dd HH:mm:ss', MAP_GET(dc, dc2tz, 'UTC') )"
+           ,"url_host" : "TO_LOWER(URL_TO_HOST(url))"
+           ,"url_protocol" : "URL_TO_PROTOCOL(url)"
+                      }
+          }
+                      ]
+   ,"parserConfig" : {
+      "dc2tz" : {
+                "nyc" : "EST"
+               ,"la" : "PST"
+               ,"london" : "UTC"
+                }
+    }
+   }
+   */
+  @Multiline
+  public static String mtlConfig_multi;
+
+  /**
+   * A more complicated test where we are transforming multiple fields:
+   * 1. Convert a timestamp field in yyyy-MM-dd HH:mm:ss format to unix epoch while
+   *    looking up the timezone based on a second field, dc, in a map being kept in the parser config.
+   *    If the data center isn't in the map, then the default is UTC
+   * 2. Extract the host from a URL field and convert to lowercase
+   * 3. Extract the protocol of the URL field
+   **/
+  @Test
+  public void testMTL_multi() throws Exception {
+
+    SensorParserConfig c = SensorParserConfig.fromBytes(Bytes.toBytes(mtlConfig_multi));
+    FieldTransformer handler = Iterables.getFirst(c.getFieldTransformations(), null);
+    {
+      //We need a timestamp field, a URL field and a data center field
+      JSONObject input = new JSONObject(new HashMap<String, Object>() {{
+        put("timestamp", "2016-01-05 17:02:30");
+        put("url", "https://caseystella.com/blog");
+        //looking up the data center in portland, which doesn't exist in the map, so we default to UTC
+        put("dc", "portland");
+      }});
+      handler.transformAndUpdate(input, c.getParserConfig());
+      long expected = 1452013350000L;
+      Assert.assertEquals(expected, input.get("utc_timestamp"));
+      Assert.assertEquals("caseystella.com", input.get("url_host"));
+      Assert.assertEquals("https", input.get("url_protocol"));
+      Assert.assertTrue(input.containsKey("timestamp"));
+      Assert.assertTrue(input.containsKey("url"));
+    }
+    {
+      //now we see what happens when we change the data center to london, which is in the map
+      JSONObject input = new JSONObject(new HashMap<String, Object>() {{
+        put("timestamp", "2016-01-05 17:02:30");
+        put("url", "https://caseystella.com/blog");
+        put("dc", "london");
+      }});
+      handler.transformAndUpdate(input, c.getParserConfig());
+      long expected = 1452013350000L;
+      Assert.assertEquals(expected, input.get("utc_timestamp"));
+      Assert.assertEquals("caseystella.com", input.get("url_host"));
+      Assert.assertEquals("https", input.get("url_protocol"));
+      Assert.assertTrue(input.containsKey("timestamp"));
+      Assert.assertTrue(input.containsKey("url"));
+    }
+    //now we ensure that because we don't have a data center field at all, it's defaulted to UTC.
+    {
+      JSONObject input = new JSONObject(new HashMap<String, Object>() {{
+        put("timestamp", "2016-01-05 17:02:30");
+        put("url", "https://caseystella.com/blog");
+      }});
+      handler.transformAndUpdate(input, c.getParserConfig());
+      long expected = 1452013350000L;
+      Assert.assertEquals(expected, input.get("utc_timestamp"));
+      Assert.assertEquals("caseystella.com", input.get("url_host"));
+      Assert.assertEquals("https", input.get("url_protocol"));
+      Assert.assertTrue(input.containsKey("timestamp"));
+      Assert.assertTrue(input.containsKey("url"));
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/test/java/org/apache/metron/common/field/validation/QueryValidationTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/test/java/org/apache/metron/common/field/validation/QueryValidationTest.java b/metron-platform/metron-common/src/test/java/org/apache/metron/common/field/validation/QueryValidationTest.java
index e658fc6..79162dd 100644
--- a/metron-platform/metron-common/src/test/java/org/apache/metron/common/field/validation/QueryValidationTest.java
+++ b/metron-platform/metron-common/src/test/java/org/apache/metron/common/field/validation/QueryValidationTest.java
@@ -74,12 +74,39 @@ public class QueryValidationTest extends BaseValidationTest{
    */
   @Multiline
   public static String invalidQueryConfig2;
+  /**
+   {
+    "fieldValidations" : [
+          {
+           "validation" : "MQL"
+          ,"config" : {
+                "condition" : "MAP_EXISTS(dc, dc2tz)"
+                ,"dc2tz" : {
+                          "la" : "PST"
+                           }
+                      }
+          }
+                         ]
+   }
+   */
+  @Multiline
+  public static String validQueryConfig_map;
+
   @Test
   public void testPositive() throws IOException {
     Assert.assertTrue(execute(validQueryConfig, ImmutableMap.of("field1", "foo")));
   }
 
   @Test
+  public void testPositive_map() throws IOException {
+    Assert.assertTrue(execute(validQueryConfig_map, ImmutableMap.of("dc", "la")));
+  }
+  @Test
+  public void testNegative_map() throws IOException {
+    Assert.assertFalse(execute(validQueryConfig_map, ImmutableMap.of("dc", "nyc")));
+    Assert.assertFalse(execute(validQueryConfig_map, ImmutableMap.of("foo", "nyc")));
+  }
+  @Test
   public void testNegative() throws IOException {
     Assert.assertFalse(execute(validQueryConfig, ImmutableMap.of("field2", "foo")));
   }

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/test/java/org/apache/metron/common/field/validation/primitive/DateValidationTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/test/java/org/apache/metron/common/field/validation/primitive/DateValidationTest.java b/metron-platform/metron-common/src/test/java/org/apache/metron/common/field/validation/primitive/DateValidationTest.java
index 60808a3..4df8cdb 100644
--- a/metron-platform/metron-common/src/test/java/org/apache/metron/common/field/validation/primitive/DateValidationTest.java
+++ b/metron-platform/metron-common/src/test/java/org/apache/metron/common/field/validation/primitive/DateValidationTest.java
@@ -71,10 +71,10 @@ public class DateValidationTest extends BaseValidationTest{
   }
   @Test
   public void negativeTest_single() throws IOException {
+    Assert.assertFalse(run(validWithSingleField_MQL, ImmutableMap.of("field1", 2.3f)));
     Assert.assertFalse(execute(validWithSingleField, ImmutableMap.of("field1", "2014/05/01")));
     Assert.assertFalse(run(validWithSingleField_MQL, ImmutableMap.of("field1", "2014/05/01")));
     Assert.assertFalse(execute(validWithSingleField, ImmutableMap.of("field1", 2.3f)));
-    Assert.assertFalse(run(validWithSingleField_MQL, ImmutableMap.of("field1", 2.3f)));
   }
   @Test
   public void positiveTest_multiple() throws IOException {

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/test/java/org/apache/metron/common/query/QueryParserTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/test/java/org/apache/metron/common/query/QueryParserTest.java b/metron-platform/metron-common/src/test/java/org/apache/metron/common/query/QueryParserTest.java
index 1e5fbbf..94236dd 100644
--- a/metron-platform/metron-common/src/test/java/org/apache/metron/common/query/QueryParserTest.java
+++ b/metron-platform/metron-common/src/test/java/org/apache/metron/common/query/QueryParserTest.java
@@ -18,6 +18,11 @@
 
 package org.apache.metron.common.query;
 
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.apache.metron.common.dsl.MapVariableResolver;
+import org.apache.metron.common.dsl.ParseException;
+import org.apache.metron.common.dsl.VariableResolver;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -135,6 +140,59 @@ public class QueryParserTest {
   }
 
   @Test
+  public void testStringFunctions_advanced() throws Exception {
+    final Map<String, Object> variableMap = new HashMap<String, Object>() {{
+      put("foo", "casey");
+      put("bar", "bar.casey.grok");
+      put("ip", "192.168.0.1");
+      put("empty", "");
+      put("spaced", "metron is great");
+      put("myList", ImmutableList.of("casey", "apple", "orange"));
+    }};
+    Assert.assertTrue(run("foo in SPLIT(bar, '.')", v -> variableMap.get(v)));
+    Assert.assertFalse(run("foo in SPLIT(ip, '.')", v -> variableMap.get(v)));
+    Assert.assertTrue(run("foo in myList", v -> variableMap.get(v)));
+    Assert.assertFalse(run("foo not in myList", v -> variableMap.get(v)));
+  }
+
+  @Test
+  public void testMapFunctions_advanced() throws Exception {
+    final Map<String, Object> variableMap = new HashMap<String, Object>() {{
+      put("foo", "casey");
+      put("bar", "bar.casey.grok");
+      put("ip", "192.168.0.1");
+      put("empty", "");
+      put("spaced", "metron is great");
+      put("myMap", ImmutableMap.of("casey", "apple"));
+    }};
+    Assert.assertTrue(run("MAP_EXISTS(foo, myMap)", v -> variableMap.get(v)));
+  }
+
+  @Test
+  public void testNumericComparisonFunctions() throws Exception {
+    final Map<String, Object> variableMap = new HashMap<String, Object>() {{
+      put("foo", "casey");
+      put("bar", "bar.casey.grok");
+      put("ip", "192.168.0.1");
+      put("num", 7);
+      put("num2", 8.5);
+      put("num3", 7);
+      put("num4", "8.5");
+      put("empty", "");
+      put("spaced", "metron is great");
+    }};
+    Assert.assertTrue(run("num == 7", v -> variableMap.get(v)));
+    Assert.assertTrue(run("num < num2", v -> variableMap.get(v)));
+    Assert.assertTrue(run("num < TO_DOUBLE(num2)", v -> variableMap.get(v)));
+    Assert.assertTrue(run("num < TO_DOUBLE(num4)", v -> variableMap.get(v)));
+    Assert.assertTrue(run("num < 100", v -> variableMap.get(v)));
+    Assert.assertTrue(run("num == num3", v -> variableMap.get(v)));
+    Assert.assertFalse(run("num == num2", v -> variableMap.get(v)));
+    Assert.assertTrue(run("num == num2 || true", v -> variableMap.get(v)));
+    Assert.assertFalse(run("num > num2", v -> variableMap.get(v)));
+    Assert.assertTrue(run("num == 7 && num > 2", v -> variableMap.get(v)));
+  }
+  @Test
   public void testLogicalFunctions() throws Exception {
     final Map<String, String> variableMap = new HashMap<String, String>() {{
       put("foo", "casey");

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/test/java/org/apache/metron/common/transformation/TransformationTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/test/java/org/apache/metron/common/transformation/TransformationTest.java b/metron-platform/metron-common/src/test/java/org/apache/metron/common/transformation/TransformationTest.java
new file mode 100644
index 0000000..7884098
--- /dev/null
+++ b/metron-platform/metron-common/src/test/java/org/apache/metron/common/transformation/TransformationTest.java
@@ -0,0 +1,151 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common.transformation;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.metron.common.utils.timestamp.TimestampConverters;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class TransformationTest {
+
+  @Test
+  public void testHappyPath() {
+    String query = "TO_UPPER(TRIM(foo))";
+    Assert.assertEquals("CASEY", run(query, ImmutableMap.of("foo", "casey ")));
+  }
+
+  @Test
+  public void testJoin() {
+    String query = "JOIN( [ TO_UPPER(TRIM(foo)), 'bar' ], ',')";
+    Assert.assertEquals("CASEY,bar", run(query, ImmutableMap.of("foo", "casey ")));
+  }
+
+  @Test
+  public void testSplit() {
+    String query = "JOIN( SPLIT(foo, ':'), ',')";
+    Assert.assertEquals("casey,bar", run(query, ImmutableMap.of("foo", "casey:bar")));
+  }
+
+  @Test
+  public void testMapGet() {
+    String query = "MAP_GET(dc, dc2tz, 'UTC')";
+    Assert.assertEquals("UTC"
+                       , run(query, ImmutableMap.of("dc", "nyc"
+                                                   ,"dc2tz", ImmutableMap.of("la", "PST")
+                                                   )
+                            )
+                       );
+    Assert.assertEquals("EST"
+                       , run(query, ImmutableMap.of("dc", "nyc"
+                                                   ,"dc2tz", ImmutableMap.of("nyc", "EST")
+                                                   )
+                            )
+                       );
+  }
+  @Test
+  public void testTLDExtraction() {
+    String query = "DOMAIN_TO_TLD(foo)";
+    Assert.assertEquals("co.uk", run(query, ImmutableMap.of("foo", "www.google.co.uk")));
+  }
+
+  @Test
+  public void testTLDRemoval() {
+    String query = "DOMAIN_REMOVE_TLD(foo)";
+    Assert.assertEquals("www.google", run(query, ImmutableMap.of("foo", "www.google.co.uk")));
+  }
+
+  @Test
+  public void testSubdomainRemoval() {
+    String query = "DOMAIN_REMOVE_SUBDOMAINS(foo)";
+    Assert.assertEquals("google.co.uk", run(query, ImmutableMap.of("foo", "www.google.co.uk")));
+    Assert.assertEquals("google.com", run(query, ImmutableMap.of("foo", "www.google.com")));
+  }
+  @Test
+  public void testURLToHost() {
+    String query = "URL_TO_HOST(foo)";
+    Assert.assertEquals("www.google.co.uk", run(query, ImmutableMap.of("foo", "http://www.google.co.uk/my/path")));
+  }
+
+  @Test
+  public void testURLToPort() {
+    String query = "URL_TO_PORT(foo)";
+    Assert.assertEquals(80, run(query, ImmutableMap.of("foo", "http://www.google.co.uk/my/path")));
+  }
+
+  @Test
+  public void testURLToProtocol() {
+    String query = "URL_TO_PROTOCOL(foo)";
+    Assert.assertEquals("http", run(query, ImmutableMap.of("foo", "http://www.google.co.uk/my/path")));
+  }
+
+  @Test
+  public void testURLToPath() {
+    String query = "URL_TO_PATH(foo)";
+    Assert.assertEquals("/my/path", run(query, ImmutableMap.of("foo", "http://www.google.co.uk/my/path")));
+  }
+
+  @Test
+  public void testDateConversion() {
+    long expected =1452013350000L;
+    {
+      String query = "TO_EPOCH_TIMESTAMP(foo, 'yyyy-MM-dd HH:mm:ss', 'UTC')";
+      Assert.assertEquals(expected, run(query, ImmutableMap.of("foo", "2016-01-05 17:02:30")));
+    }
+    {
+      String query = "TO_EPOCH_TIMESTAMP(foo, 'yyyy-MM-dd HH:mm:ss')";
+      Long ts = (Long) run(query, ImmutableMap.of("foo", "2016-01-05 17:02:30"));
+      //is it within 24 hours of the UTC?
+      Assert.assertTrue(Math.abs(ts - expected) < 8.64e+7);
+    }
+  }
+
+  @Test
+  public void testToString() {
+    Assert.assertEquals("5", run("TO_STRING(foo)", ImmutableMap.of("foo", 5)));
+  }
+
+  @Test
+  public void testToInteger() {
+    Assert.assertEquals(5, run("TO_INTEGER(foo)", ImmutableMap.of("foo", "5")));
+    Assert.assertEquals(5, run("TO_INTEGER(foo)", ImmutableMap.of("foo", 5)));
+  }
+
+  @Test
+  public void testToDouble() {
+    Assert.assertEquals(new Double(5.1), run("TO_DOUBLE(foo)", ImmutableMap.of("foo", 5.1d)));
+    Assert.assertEquals(new Double(5.1), run("TO_DOUBLE(foo)", ImmutableMap.of("foo", "5.1")));
+  }
+  @Test
+  public void testGet() {
+    Map<String, Object> variables = ImmutableMap.of("foo", "www.google.co.uk");
+    Assert.assertEquals("www", run("GET_FIRST(SPLIT(DOMAIN_REMOVE_TLD(foo), '.'))", variables));
+    Assert.assertEquals("www", run("GET(SPLIT(DOMAIN_REMOVE_TLD(foo), '.'), 0)", variables));
+    Assert.assertEquals("google", run("GET_LAST(SPLIT(DOMAIN_REMOVE_TLD(foo), '.'))", variables));
+    Assert.assertEquals("google", run("GET(SPLIT(DOMAIN_REMOVE_TLD(foo), '.'), 1)", variables));
+  }
+  private static Object run(String rule, Map<String, Object> variables) {
+    TransformationProcessor processor = new TransformationProcessor();
+    Assert.assertTrue(rule + " not valid.", processor.validate(rule));
+    return processor.parse(rule, x -> variables.get(x));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-enrichment/src/main/java/org/apache/metron/enrichment/bolt/ThreatIntelJoinBolt.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-enrichment/src/main/java/org/apache/metron/enrichment/bolt/ThreatIntelJoinBolt.java b/metron-platform/metron-enrichment/src/main/java/org/apache/metron/enrichment/bolt/ThreatIntelJoinBolt.java
index ec1ce7a..55e9d92 100644
--- a/metron-platform/metron-enrichment/src/main/java/org/apache/metron/enrichment/bolt/ThreatIntelJoinBolt.java
+++ b/metron-platform/metron-enrichment/src/main/java/org/apache/metron/enrichment/bolt/ThreatIntelJoinBolt.java
@@ -86,7 +86,7 @@ public class ThreatIntelJoinBolt extends EnrichmentJoinBolt {
           LOG.debug(sourceType + ": Empty rules!");
         }
 
-        ThreatTriageProcessor threatTriageProcessor = new ThreatTriageProcessor(triageConfig);
+        ThreatTriageProcessor threatTriageProcessor = new ThreatTriageProcessor(config);
         Double triageLevel = threatTriageProcessor.apply(ret);
         if(LOG.isDebugEnabled()) {
           String rules = Joiner.on('\n').join(triageConfig.getRiskLevelRules().entrySet());

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-enrichment/src/main/java/org/apache/metron/threatintel/triage/ThreatTriageProcessor.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-enrichment/src/main/java/org/apache/metron/threatintel/triage/ThreatTriageProcessor.java b/metron-platform/metron-enrichment/src/main/java/org/apache/metron/threatintel/triage/ThreatTriageProcessor.java
index bb4d387..e12622c 100644
--- a/metron-platform/metron-enrichment/src/main/java/org/apache/metron/threatintel/triage/ThreatTriageProcessor.java
+++ b/metron-platform/metron-enrichment/src/main/java/org/apache/metron/threatintel/triage/ThreatTriageProcessor.java
@@ -19,10 +19,12 @@
 package org.apache.metron.threatintel.triage;
 
 import com.google.common.base.Function;
+import org.apache.metron.common.configuration.enrichment.SensorEnrichmentConfig;
+import org.apache.metron.common.configuration.enrichment.threatintel.ThreatIntelConfig;
 import org.apache.metron.common.configuration.enrichment.threatintel.ThreatTriageConfig;
-import org.apache.metron.common.query.MapVariableResolver;
+import org.apache.metron.common.dsl.MapVariableResolver;
 import org.apache.metron.common.query.PredicateProcessor;
-import org.apache.metron.common.query.VariableResolver;
+import org.apache.metron.common.dsl.VariableResolver;
 
 import javax.annotation.Nullable;
 import java.util.ArrayList;
@@ -30,9 +32,13 @@ import java.util.List;
 import java.util.Map;
 
 public class ThreatTriageProcessor implements Function<Map, Double> {
-  private ThreatTriageConfig config;
-  public ThreatTriageProcessor(ThreatTriageConfig config) {
-    this.config = config;
+  private SensorEnrichmentConfig sensorConfig;
+  private ThreatIntelConfig threatIntelConfig;
+  private ThreatTriageConfig threatTriageConfig;
+  public ThreatTriageProcessor(SensorEnrichmentConfig config) {
+    this.threatIntelConfig = config.getThreatIntel();
+    this.sensorConfig = config;
+    this.threatTriageConfig = config.getThreatIntel().getTriageConfig();
   }
 
   @Nullable
@@ -40,12 +46,12 @@ public class ThreatTriageProcessor implements Function<Map, Double> {
   public Double apply(@Nullable Map input) {
     List<Number> scores = new ArrayList<>();
     PredicateProcessor predicateProcessor = new PredicateProcessor();
-    VariableResolver resolver = new MapVariableResolver(input);
-    for(Map.Entry<String, Number> kv : config.getRiskLevelRules().entrySet()) {
+    VariableResolver resolver = new MapVariableResolver(input, sensorConfig.getConfiguration(), threatIntelConfig.getConfig());
+    for(Map.Entry<String, Number> kv : threatTriageConfig.getRiskLevelRules().entrySet()) {
       if(predicateProcessor.parse(kv.getKey(), resolver)) {
         scores.add(kv.getValue());
       }
     }
-    return config.getAggregator().aggregate(scores, config.getAggregationConfig());
+    return threatTriageConfig.getAggregator().aggregate(scores, threatTriageConfig.getAggregationConfig());
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-enrichment/src/test/java/org/apache/metron/threatintel/triage/ThreatTriageTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-enrichment/src/test/java/org/apache/metron/threatintel/triage/ThreatTriageTest.java b/metron-platform/metron-enrichment/src/test/java/org/apache/metron/threatintel/triage/ThreatTriageTest.java
index 90a4c9b..8ae74b3 100644
--- a/metron-platform/metron-enrichment/src/test/java/org/apache/metron/threatintel/triage/ThreatTriageTest.java
+++ b/metron-platform/metron-enrichment/src/test/java/org/apache/metron/threatintel/triage/ThreatTriageTest.java
@@ -19,6 +19,7 @@
 package org.apache.metron.threatintel.triage;
 
 import org.adrianwalker.multilinestring.Multiline;
+import org.apache.metron.common.configuration.enrichment.SensorEnrichmentConfig;
 import org.apache.metron.common.configuration.enrichment.threatintel.ThreatTriageConfig;
 import org.apache.metron.common.utils.JSONUtils;
 import org.junit.Assert;
@@ -30,19 +31,28 @@ import java.util.HashMap;
 public class ThreatTriageTest {
   /**
    {
-    "riskLevelRules" : {
-        "user.type in [ 'admin', 'power' ] and asset.type == 'web'" : 10
-       ,"asset.type == 'web'" : 5
-       ,"user.type == 'normal'  and asset.type == 'web'" : 0
+    "threatIntel" : {
+      "triageConfig" :
+      {
+        "riskLevelRules" : {
+            "user.type in [ 'admin', 'power' ] and asset.type == 'web'" : 10
+           ,"asset.type == 'web'" : 5
+          ,"user.type == 'normal'  and asset.type == 'web'" : 0
+          ,"user.type in whitelist" : -1
                           }
-   ,"aggregator" : "MAX"
+        ,"aggregator" : "MAX"
+      },
+      "config" : {
+        "whitelist" : [ "abnormal" ]
+                 }
+    }
    }
    */
   @Multiline
   public static String smokeTestProcessorConfig;
 
   private static ThreatTriageProcessor getProcessor(String config) throws IOException {
-    ThreatTriageConfig c = JSONUtils.INSTANCE.load(config, ThreatTriageConfig.class);
+    SensorEnrichmentConfig c = JSONUtils.INSTANCE.load(config, SensorEnrichmentConfig.class);
     return new ThreatTriageProcessor(c);
   }
 
@@ -51,7 +61,7 @@ public class ThreatTriageTest {
     ThreatTriageProcessor threatTriageProcessor = getProcessor(smokeTestProcessorConfig);
     Assert.assertEquals("Expected a score of 0"
                        , 0d
-                       ,new ThreatTriageProcessor(new ThreatTriageConfig()).apply(new HashMap<Object, Object>() {{
+                       ,new ThreatTriageProcessor(new SensorEnrichmentConfig()).apply(new HashMap<Object, Object>() {{
                           put("user.type", "admin");
                           put("asset.type", "web");
                                         }}
@@ -85,16 +95,30 @@ public class ThreatTriageTest {
                                         )
                        , 1e-10
                        );
+    Assert.assertEquals("Expected a score of -Inf"
+                       , Double.NEGATIVE_INFINITY
+                       , threatTriageProcessor.apply(new HashMap<Object, Object>() {{
+                          put("user.type", "abnormal");
+                          put("asset.type", "bar");
+                                        }}
+                                        )
+                       , 1e-10
+                       );
   }
 
   /**
    {
-    "riskLevelRules" : {
-        "user.type in [ 'admin', 'power' ] and asset.type == 'web'" : 10
-       ,"asset.type == 'web'" : 5
-       ,"user.type == 'normal'  and asset.type == 'web'" : 0
+    "threatIntel" : {
+      "triageConfig" :
+      {
+        "riskLevelRules" : {
+            "user.type in [ 'admin', 'power' ] and asset.type == 'web'" : 10
+           ,"asset.type == 'web'" : 5
+           ,"user.type == 'normal'  and asset.type == 'web'" : 0
                           }
-   ,"aggregator" : "POSITIVE_MEAN"
+        ,"aggregator" : "POSITIVE_MEAN"
+      }
+                   }
    }
    */
   @Multiline

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-integration-test/src/main/sample/data/squid/parsed/SquidExampleParsed
----------------------------------------------------------------------
diff --git a/metron-platform/metron-integration-test/src/main/sample/data/squid/parsed/SquidExampleParsed b/metron-platform/metron-integration-test/src/main/sample/data/squid/parsed/SquidExampleParsed
index 9643c25..9a8b981 100644
--- a/metron-platform/metron-integration-test/src/main/sample/data/squid/parsed/SquidExampleParsed
+++ b/metron-platform/metron-integration-test/src/main/sample/data/squid/parsed/SquidExampleParsed
@@ -1,2 +1,2 @@
-{"elapsed":161,"code":200,"ip_dst_addr":"199.27.79.73","original_string":"1461576382.642    161 127.0.0.1 TCP_MISS\/200 103701 GET http:\/\/www.cnn.com\/ - DIRECT\/199.27.79.73 text\/html","method":"GET","bytes":103701,"action":"TCP_MISS","ip_src_addr":"127.0.0.1","url":"cnn.com","timestamp":1461576382642,"source.type":"squid"}
-{"elapsed":159,"code":200,"ip_dst_addr":"66.210.41.9","original_string":"1461576442.228    159 127.0.0.1 TCP_MISS\/200 137183 GET http:\/\/www.nba.com\/ - DIRECT\/66.210.41.9 text\/html","method":"GET","bytes":137183,"action":"TCP_MISS","ip_src_addr":"127.0.0.1","url":"nba.com","timestamp":1461576442228,"source.type":"squid"}
\ No newline at end of file
+{"elapsed":161,"code":200,"ip_dst_addr":"199.27.79.73","original_string":"1461576382.642    161 127.0.0.1 TCP_MISS\/200 103701 GET http:\/\/www.cnn.com\/ - DIRECT\/199.27.79.73 text\/html","method":"GET","bytes":103701,"action":"TCP_MISS","ip_src_addr":"127.0.0.1","url":"http://www.cnn.com/","full_hostname":"www.cnn.com", "domain_without_subdomains": "cnn.com", "timestamp":1461576382642,"source.type":"squid"}
+{"elapsed":159,"code":200,"ip_dst_addr":"66.210.41.9","original_string":"1461576442.228    159 127.0.0.1 TCP_MISS\/200 137183 GET http:\/\/www.nba.com\/ - DIRECT\/66.210.41.9 text\/html","method":"GET","bytes":137183,"action":"TCP_MISS","ip_src_addr":"127.0.0.1","url":"http://www.nba.com/", "full_hostname":"www.nba.com", "domain_without_subdomains" : "nba.com", "timestamp":1461576442228,"source.type":"squid"}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-parsers/README.md
----------------------------------------------------------------------
diff --git a/metron-platform/metron-parsers/README.md b/metron-platform/metron-parsers/README.md
index b78550b..76adfcc 100644
--- a/metron-platform/metron-parsers/README.md
+++ b/metron-platform/metron-parsers/README.md
@@ -84,7 +84,7 @@ unconditionally:
     "fieldTransformations" : [
           {
             "input" : "field1"
-          , "mapping" : "REMOVE"
+          , "transformation" : "REMOVE"
           }
                       ]
 }
@@ -98,7 +98,7 @@ whenever `field2` exists and whose corresponding equal to 'foo':
   "fieldTransformations" : [
           {
             "input" : "field1"
-          , "mapping" : "REMOVE"
+          , "transformation" : "REMOVE"
           , "config" : {
               "condition" : "exists(field2) and field2 == 'foo'"
                        }
@@ -126,6 +126,42 @@ to a textual representation of the protocol:
 This transformation would transform `{ "protocol" : 6, "source.type" : "bro", ... }` 
 into `{ "protocol" : "TCP", "source.type" : "bro", ...}`
 
+* `MTL` : This transformation executes a set of transformations expressed as [Metron Transformation Language](../metron-common) statements.
+
+Consider the following sensor parser config to add three new fields to a
+message:
+* `utc_timestamp` : The unix epoch timestamp based on the `timestamp` field, a `dc` field which is the data center the message comes from and a `dc2tz` map mapping data centers to timezones
+* `url_host` : The host associated with the url in the `url` field
+* `url_protocol` : The protocol associated with the url in the `url` field
+
+```
+{
+...
+    "fieldTransformations" : [
+          {
+           "transformation" : "MTL"
+          ,"output" : [ "utc_timestamp", "url_host", "url_protocol" ]
+          ,"config" : {
+            "utc_timestamp" : "TO_EPOCH_TIMESTAMP(timestamp, 'yyyy-MM-dd
+HH:mm:ss', MAP_GET(dc, dc2tz, 'UTC') )"
+           ,"url_host" : "URL_TO_HOST(url)"
+           ,"url_protocol" : "URL_TO_PROTOCOL(url)"
+                      }
+          }
+                      ]
+   ,"parserConfig" : {
+      "dc2tz" : {
+                "nyc" : "EST"
+               ,"la" : "PST"
+               ,"london" : "UTC"
+                }
+    }
+}
+```
+
+Note that the `dc2tz` map is in the parser config, so it is accessible
+in the functions.
+
 ###An Example Configuration for a Sensor
 Consider the following example configuration for the `yaf` sensor:
 

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-parsers/src/main/config/zookeeper/parsers/squid.json
----------------------------------------------------------------------
diff --git a/metron-platform/metron-parsers/src/main/config/zookeeper/parsers/squid.json b/metron-platform/metron-parsers/src/main/config/zookeeper/parsers/squid.json
index 6c4a69b..3f6fde5 100644
--- a/metron-platform/metron-parsers/src/main/config/zookeeper/parsers/squid.json
+++ b/metron-platform/metron-parsers/src/main/config/zookeeper/parsers/squid.json
@@ -5,5 +5,15 @@
     "grokPath": "/patterns/squid",
     "patternLabel": "SQUID_DELIMITED",
     "timestampField": "timestamp"
-  }
+  },
+  "fieldTransformations" : [
+    {
+      "transformation" : "MTL"
+    ,"output" : [ "full_hostname", "domain_without_subdomains" ]
+    ,"config" : {
+      "full_hostname" : "URL_TO_HOST(url)"
+      ,"domain_without_subdomains" : "DOMAIN_REMOVE_SUBDOMAINS(full_hostname)"
+                }
+    }
+                           ]
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-parsers/src/main/java/org/apache/metron/parsers/filters/QueryFilter.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-parsers/src/main/java/org/apache/metron/parsers/filters/QueryFilter.java b/metron-platform/metron-parsers/src/main/java/org/apache/metron/parsers/filters/QueryFilter.java
index ee64fb4..5ee5fcc 100644
--- a/metron-platform/metron-parsers/src/main/java/org/apache/metron/parsers/filters/QueryFilter.java
+++ b/metron-platform/metron-parsers/src/main/java/org/apache/metron/parsers/filters/QueryFilter.java
@@ -18,15 +18,12 @@
 
 package org.apache.metron.parsers.filters;
 
-import com.google.common.collect.ImmutableList;
-import org.apache.metron.common.query.MapVariableResolver;
+import org.apache.metron.common.dsl.MapVariableResolver;
 import org.apache.metron.common.query.PredicateProcessor;
-import org.apache.metron.common.query.VariableResolver;
+import org.apache.metron.common.dsl.VariableResolver;
 import org.apache.metron.parsers.interfaces.MessageFilter;
 import org.json.simple.JSONObject;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Map;
 
 public class QueryFilter implements MessageFilter<JSONObject> {

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-parsers/src/main/resources/patterns/squid
----------------------------------------------------------------------
diff --git a/metron-platform/metron-parsers/src/main/resources/patterns/squid b/metron-platform/metron-parsers/src/main/resources/patterns/squid
index ba5bab8..d7312cc 100644
--- a/metron-platform/metron-parsers/src/main/resources/patterns/squid
+++ b/metron-platform/metron-parsers/src/main/resources/patterns/squid
@@ -1,2 +1 @@
-WDOM [^(?:http:\/\/|www\.|https:\/\/)]([^\/]+)
-SQUID_DELIMITED %{NUMBER:timestamp} %{SPACE:UNWANTED}  %{INT:elapsed} %{IPV4:ip_src_addr} %{WORD:action}/%{NUMBER:code} %{NUMBER:bytes} %{WORD:method} http:\/\/\www.%{WDOM:url}\/ - %{WORD:UNWANTED}\/%{IPV4:ip_dst_addr} %{WORD:UNWANTED}\/%{WORD:UNWANTED}
\ No newline at end of file
+SQUID_DELIMITED %{NUMBER:timestamp} %{SPACE:UNWANTED}  %{INT:elapsed} %{IPV4:ip_src_addr} %{WORD:action}/%{NUMBER:code} %{NUMBER:bytes} %{WORD:method} %{NOTSPACE:url} - %{WORD:UNWANTED}\/%{IPV4:ip_dst_addr} %{WORD:UNWANTED}\/%{WORD:UNWANTED}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/SquidParserTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/SquidParserTest.java b/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/SquidParserTest.java
index d97025e..7f0abaf 100644
--- a/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/SquidParserTest.java
+++ b/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/SquidParserTest.java
@@ -39,7 +39,7 @@ public class SquidParserTest extends GrokParserTest {
    *   "action":"TCP_MISS",
    *   "ip_src_addr":"127.0.0.1",
    *   "ip_dst_addr":"199.27.79.73",
-   *   "url":"cnn.com",
+   *   "url":"http://www.cnn.com/",
    *   "timestamp":1461576382642
    * }
    */

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/PcapFieldResolver.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/PcapFieldResolver.java b/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/PcapFieldResolver.java
index 50537e1..0facfa8 100644
--- a/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/PcapFieldResolver.java
+++ b/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/PcapFieldResolver.java
@@ -19,7 +19,7 @@
 package org.apache.metron.pcap.filter;
 
 import org.apache.metron.common.Constants;
-import org.apache.metron.common.query.VariableResolver;
+import org.apache.metron.common.dsl.VariableResolver;
 
 import java.util.EnumMap;
 



[4/4] incubator-metron git commit: METRON-204: Field Transformation Domain Specific Language. This closes apache/incubator-metron#142

Posted by ce...@apache.org.
METRON-204: Field Transformation Domain Specific Language.  This closes apache/incubator-metron#142


Project: http://git-wip-us.apache.org/repos/asf/incubator-metron/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-metron/commit/bdbf33a9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-metron/tree/bdbf33a9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-metron/diff/bdbf33a9

Branch: refs/heads/master
Commit: bdbf33a9d29d437d4b75be6314849c8f60e0f3e8
Parents: 739e2eb
Author: cstella <ce...@gmail.com>
Authored: Thu Jun 16 12:02:40 2016 -0400
Committer: cstella <ce...@gmail.com>
Committed: Thu Jun 16 12:02:40 2016 -0400

----------------------------------------------------------------------
 metron-platform/metron-common/README.md         |  71 +-
 .../metron/common/query/generated/Predicate.g4  |  22 +-
 .../transformation/generated/Transformation.g4  |  93 +++
 .../src/main/java/Predicate.tokens              |  54 +-
 .../src/main/java/PredicateLexer.tokens         |  54 +-
 .../src/main/java/Transformation.tokens         |  16 +
 .../src/main/java/TransformationLexer.tokens    |  16 +
 .../metron/common/aggregator/Aggregators.java   |  58 +-
 .../apache/metron/common/dsl/ErrorListener.java |  51 ++
 .../metron/common/dsl/FunctionMarker.java       |  21 +
 .../metron/common/dsl/MapVariableResolver.java  |  43 ++
 .../metron/common/dsl/ParseException.java       |  28 +
 .../org/apache/metron/common/dsl/Token.java     |  58 ++
 .../common/dsl/TransformationFunctions.java     |  61 ++
 .../metron/common/dsl/VariableResolver.java     |  23 +
 .../common/dsl/functions/DateFunctions.java     | 129 ++++
 .../common/dsl/functions/MapFunctions.java      |  46 ++
 .../common/dsl/functions/NetworkFunctions.java  | 144 +++++
 .../common/dsl/functions/StringFunctions.java   |  78 +++
 .../transformation/FieldTransformations.java    |   1 +
 .../field/transformation/MTLTransformation.java |  51 ++
 .../transformation/RemoveTransformation.java    |   7 +-
 .../field/validation/QueryValidation.java       |   4 +-
 .../field/validation/SimpleValidation.java      |  12 +-
 .../validation/network/DomainValidation.java    |   4 +-
 .../validation/network/EmailValidation.java     |   4 +-
 .../field/validation/network/IPValidation.java  |  21 +-
 .../field/validation/network/URLValidation.java |   4 +-
 .../validation/primitive/DateValidation.java    |  12 +-
 .../validation/primitive/IntegerValidation.java |   4 +-
 .../primitive/NotEmptyValidation.java           |   4 +-
 .../metron/common/query/ErrorListener.java      |  50 --
 .../metron/common/query/FunctionMarker.java     |  21 -
 .../metron/common/query/LogicalFunctions.java   |  40 +-
 .../common/query/MapVariableResolver.java       |  33 -
 .../metron/common/query/ParseException.java     |  28 -
 .../metron/common/query/PredicateProcessor.java |   3 +
 .../metron/common/query/PredicateToken.java     |  58 --
 .../metron/common/query/QueryCompiler.java      | 208 +++---
 .../metron/common/query/StringFunctions.java    |  42 --
 .../metron/common/query/VariableResolver.java   |  23 -
 .../query/generated/PredicateBaseListener.java  |  52 +-
 .../common/query/generated/PredicateLexer.java  | 141 ++--
 .../query/generated/PredicateListener.java      |  56 +-
 .../common/query/generated/PredicateParser.java | 383 +++++++----
 .../transformation/TransformationCompiler.java  | 160 +++++
 .../transformation/TransformationProcessor.java |  70 ++
 .../generated/PredicateLexer.java               | 146 +++++
 .../generated/TransformationBaseListener.java   | 216 +++++++
 .../generated/TransformationLexer.java          | 148 +++++
 .../generated/TransformationListener.java       | 177 +++++
 .../generated/TransformationParser.java         | 640 +++++++++++++++++++
 .../apache/metron/common/AggregatorsTest.java   |  59 ++
 .../transformation/MTLTransformationTest.java   | 167 +++++
 .../field/validation/QueryValidationTest.java   |  27 +
 .../primitive/DateValidationTest.java           |   2 +-
 .../metron/common/query/QueryParserTest.java    |  58 ++
 .../transformation/TransformationTest.java      | 151 +++++
 .../enrichment/bolt/ThreatIntelJoinBolt.java    |   2 +-
 .../triage/ThreatTriageProcessor.java           |  22 +-
 .../threatintel/triage/ThreatTriageTest.java    |  48 +-
 .../sample/data/squid/parsed/SquidExampleParsed |   4 +-
 metron-platform/metron-parsers/README.md        |  40 +-
 .../main/config/zookeeper/parsers/squid.json    |  12 +-
 .../metron/parsers/filters/QueryFilter.java     |   7 +-
 .../src/main/resources/patterns/squid           |   3 +-
 .../apache/metron/parsers/SquidParserTest.java  |   2 +-
 .../metron/pcap/filter/PcapFieldResolver.java   |   2 +-
 .../pcap/filter/fixed/FixedPcapFilter.java      |  12 +-
 .../pcap/filter/query/QueryPcapFilter.java      |   2 +-
 metron-platform/style/suppressions.xml          |   4 +
 71 files changed, 3825 insertions(+), 688 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/README.md
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/README.md b/metron-platform/metron-common/README.md
index 1799287..e70be5e 100644
--- a/metron-platform/metron-common/README.md
+++ b/metron-platform/metron-common/README.md
@@ -4,7 +4,8 @@ For a variety of components (currently only threat intelligence triage) we have
 
 The query language supports the following:
 * Referencing fields in the enriched JSON
-* Simple boolean operations: and, not, or
+* Simple boolean operations: `and`, `not`, `or`
+* Simple comparison operations `<`, `>`, `<=`, `>=`
 * Determining whether a field exists (via `exists`)
 * The ability to have parenthesis to make order of operations explicit
 * A fixed set of functions which take strings and return boolean.  Currently:
@@ -13,17 +14,33 @@ The query language supports the following:
     * `STARTS_WITH(str, prefix)`
     * `ENDS_WITH(str, suffix)`
     * `REGEXP_MATCH(str, pattern)`
-* A fixed set of string to string transformation functions:
-    * `TO_LOWER`
-    * `TO_UPPER`
-    * `TRIM`
     * `IS_IP` : Validates that the input fields are an IP address.  By default, if no second arg is set, it assumes `IPV4`, but you can specify the type by passing in either `IPV6` or `IPV4` to the second argument.
    * `IS_DOMAIN` 
    * `IS_EMAIL`
    * `IS_URL`
    * `IS_DATE`
    * `IS_INTEGER`
-
+* A fixed set of transformation functions:
+   * `TO_LOWER(string)` : Transforms the first argument to a lowercase string
+   * `TO_UPPER(string)` : Transforms the first argument to an uppercase string
+   * `TO_STRING(string)` : Transforms the first argument to a string
+   * `TO_INTEGER(x)` : Transforms the first argument to an integer 
+   * `TO_DOUBLE(x)` : Transforms the first argument to a double
+   * `TRIM(string)` : Trims whitespace from both sides of a string.
+   * `JOIN(list, delim)` : Joins the components of the list with the specified delimiter
+   * `SPLIT(string, delim)` : Splits the string by the delimiter.  Returns a list.
+   * `GET_FIRST(list)` : Returns the first element of the list
+   * `GET_LAST(list)` : Returns the last element of the list
+   * `GET(list, i)` : Returns the i'th element of the list (i is 0-based).
+   * `MAP_GET(key, map, default)` : Returns the value associated with the key in the map.  If the key does not exist, the default will be returned.  If the default is unspecified, then null will be returned.
+   * `DOMAIN_TO_TLD(domain)` : Returns the TLD of the domain.
+   * `DOMAIN_REMOVE_TLD(domain)` : Remove the TLD of the domain.
+   * `REMOVE_TLD(domain)` : Removes the TLD from the domain.
+   * `URL_TO_HOST(url)` : Returns the host from a URL
+   * `URL_TO_PROTOCOL(url)` : Returns the protocol from a URL
+   * `URL_TO_PORT(url)` : Returns the port from a URL
+   * `URL_TO_PATH(url)` : Returns the path from a URL
+   * `TO_EPOCH_TIMESTAMP(dateTime, format, timezone)` : Returns the epoch timestamp of the `dateTime` given the `format`.  If the format does not have a timestamp and you wish to assume a given timestamp, you may specify the `timezone` optionally.
 
 Example query:
 
@@ -34,6 +51,48 @@ This evaluates to true precisely when one of the following is true:
 * The value of the `ip` field is `10.0.0.1` or `10.0.0.2`
 * The field `is_local` exists
 
+#Transformation Language
+
+For a variety of components, there is the need to transform messages and
+compose those transformations in a pluggable way.  For this purpose,
+there is a simple DSL to allow functions to be defined for common
+transformations and to have those functions be composed.
+
+The functions currently supported are:
+   * `TO_LOWER(string)` : Transforms the first argument to a lowercase string
+   * `TO_UPPER(string)` : Transforms the first argument to an uppercase string
+   * `TO_STRING(string)` : Transforms the first argument to a string
+   * `TO_INTEGER(x)` : Transforms the first argument to an integer 
+   * `TO_DOUBLE(x)` : Transforms the first argument to a double
+   * `TRIM(string)` : Trims whitespace from both sides of a string.
+   * `JOIN(list, delim)` : Joins the components of the list with the specified delimiter
+   * `SPLIT(string, delim)` : Splits the string by the delimiter.  Returns a list.
+   * `GET_FIRST(list)` : Returns the first element of the list
+   * `GET_LAST(list)` : Returns the last element of the list
+   * `GET(list, i)` : Returns the i'th element of the list (i is 0-based).
+   * `MAP_GET(key, map, default)` : Returns the value associated with the key in the map.  If the key does not exist, the default will be returned.  If the default is unspecified, then null will be returned.
+   * `DOMAIN_TO_TLD(domain)` : Returns the TLD of the domain.
+   * `DOMAIN_REMOVE_TLD(domain)` : Remove the TLD of the domain.
+   * `REMOVE_TLD(domain)` : Removes the TLD from the domain.
+   * `URL_TO_HOST(url)` : Returns the host from a URL
+   * `URL_TO_PROTOCOL(url)` : Returns the protocol from a URL
+   * `URL_TO_PORT(url)` : Returns the port from a URL
+   * `URL_TO_PATH(url)` : Returns the path from a URL
+   * `TO_EPOCH_TIMESTAMP(dateTime, format, timezone)` : Returns the epoch timestamp of the `dateTime` given the `format`.  If the format does not have a timestamp and you wish to assume a given timestamp, you may specify the `timezone` optionally.
+
+Example Transformation:
+
+`TO_EPOCH_TIMESTAMP(timestamp, 'yyyy-MM-dd HH:mm:ss', MAP_GET(dc, dc2tz, 'UTC'))`
+
+For a message with a `timestamp` and `dc` field, we want to set the
+transform the timestamp to an epoch timestamp given a timezone which we
+will lookup in a separate map, called `dc2tz`.
+
+This will convert the timestamp field to an epoch timestamp based on the 
+* Format `yyyy-MM-dd HH:mm:ss`
+* The value in `dc2tz` associated with the value associated with field
+  `dc`, defaulting to `UTC`
+
 #Enrichment Configuration
 
 The configuration for the `enrichment` topology, the topology primarily

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/antlr4/org/apache/metron/common/query/generated/Predicate.g4
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/antlr4/org/apache/metron/common/query/generated/Predicate.g4 b/metron-platform/metron-common/src/main/antlr4/org/apache/metron/common/query/generated/Predicate.g4
index 73c60cd..4e334d2 100644
--- a/metron-platform/metron-common/src/main/antlr4/org/apache/metron/common/query/generated/Predicate.g4
+++ b/metron-platform/metron-common/src/main/antlr4/org/apache/metron/common/query/generated/Predicate.g4
@@ -60,6 +60,10 @@ FALSE : 'false'
 
 EQ : '==' ;
 NEQ : '!=' ;
+LT : '<';
+LTE : '<=';
+GT : '>';
+GTE : '>=';
 COMMA : ',';
 
 LBRACKET : '[';
@@ -72,6 +76,9 @@ IN : 'in'
 NIN : 'not in'
    ;
 EXISTS : 'exists';
+INT_LITERAL     : '0'..'9'+ ;
+DOUBLE_LITERAL  : '0'..'9'+'.''0'..'9'+ ;
+
 IDENTIFIER : [a-zA-Z_][a-zA-Z_\.0-9]* ;
 fragment SCHAR:  ~['"\\\r\n];
 STRING_LITERAL : '"' SCHAR* '"'
@@ -101,8 +108,8 @@ logical_expr
  ;
 
 comparison_expr : comparison_operand comp_operator comparison_operand # ComparisonExpressionWithOperator
-                | identifier_operand IN list_entity #InExpression
-                | identifier_operand NIN list_entity #NInExpression
+                | identifier_operand IN identifier_operand #InExpression
+                | identifier_operand NIN identifier_operand #NInExpression
                 | LPAREN comparison_expr RPAREN # ComparisonExpressionParens
                 ;
 
@@ -118,14 +125,21 @@ func_args : op_list
 op_list : identifier_operand
         | op_list COMMA identifier_operand
         ;
+
+t_func : IDENTIFIER LPAREN func_args RPAREN #TransformationFunc
+       ;
+
 identifier_operand : STRING_LITERAL # StringLiteral
                    | IDENTIFIER     # LogicalVariable
-                   | IDENTIFIER LPAREN func_args RPAREN #StringFunc
+                   | t_func #id_tfunc
+                   | INT_LITERAL #IntegerLiteral
+                   | DOUBLE_LITERAL #DoubleLiteral
+                   | list_entity #List
                    ;
 
 comparison_operand : identifier_operand #IdentifierOperand
                    | logical_entity # LogicalConstComparison
                    ;
 
-comp_operator : (EQ | NEQ) # ComparisonOp
+comp_operator : (EQ | NEQ | LT | LTE | GT | GTE) # ComparisonOp
               ;

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/antlr4/org/apache/metron/common/transformation/generated/Transformation.g4
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/antlr4/org/apache/metron/common/transformation/generated/Transformation.g4 b/metron-platform/metron-common/src/main/antlr4/org/apache/metron/common/transformation/generated/Transformation.g4
new file mode 100644
index 0000000..95fa542
--- /dev/null
+++ b/metron-platform/metron-common/src/main/antlr4/org/apache/metron/common/transformation/generated/Transformation.g4
@@ -0,0 +1,93 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+grammar Transformation;
+
+@header {
+//CHECKSTYLE:OFF
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+}
+
+/* Lexical rules */
+
+COMMA : ',';
+
+LBRACKET : '[';
+RBRACKET : ']';
+LPAREN : '(' ;
+RPAREN : ')' ;
+
+INT_LITERAL     : '0'..'9'+ ;
+DOUBLE_LITERAL  : '0'..'9'+'.''0'..'9'+ ;
+IDENTIFIER : [a-zA-Z_][a-zA-Z_\.0-9]* ;
+fragment SCHAR:  ~['"\\\r\n];
+STRING_LITERAL : '"' SCHAR* '"'
+               | '\'' SCHAR* '\'' ;
+
+
+// COMMENT and WS are stripped from the output token stream by sending
+// to a different channel 'skip'
+
+COMMENT : '//' .+? ('\n'|EOF) -> skip ;
+
+WS : [ \r\t\u000C\n]+ -> skip ;
+
+
+/* Parser rules */
+
+transformation : transformation_expr EOF;
+
+transformation_expr
+  : LPAREN transformation_expr RPAREN #TransformationExpr
+  | transformation_entity #TransformationEntity
+  ;
+
+transformation_entity
+  : identifier_operand 
+  ;
+
+func_args : op_list
+          ;
+op_list : identifier_operand
+        | op_list COMMA identifier_operand
+        ;
+list_entity : LBRACKET op_list RBRACKET;
+
+identifier_operand : STRING_LITERAL # StringLiteral
+                   | INT_LITERAL #IntegerLiteral
+                   | DOUBLE_LITERAL #DoubleLiteral
+                   | IDENTIFIER     # Variable
+                   | IDENTIFIER LPAREN func_args RPAREN #TransformationFunc
+                   | list_entity #List
+                   ;

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/Predicate.tokens
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/Predicate.tokens b/metron-platform/metron-common/src/main/java/Predicate.tokens
index e0726f9..7adce51 100644
--- a/metron-platform/metron-common/src/main/java/Predicate.tokens
+++ b/metron-platform/metron-common/src/main/java/Predicate.tokens
@@ -5,27 +5,37 @@ TRUE=4
 FALSE=5
 EQ=6
 NEQ=7
-COMMA=8
-LBRACKET=9
-RBRACKET=10
-LPAREN=11
-RPAREN=12
-IN=13
-NIN=14
-EXISTS=15
-IDENTIFIER=16
-STRING_LITERAL=17
-SEMI=18
-COMMENT=19
-WS=20
+LT=8
+LTE=9
+GT=10
+GTE=11
+COMMA=12
+LBRACKET=13
+RBRACKET=14
+LPAREN=15
+RPAREN=16
+IN=17
+NIN=18
+EXISTS=19
+INT_LITERAL=20
+DOUBLE_LITERAL=21
+IDENTIFIER=22
+STRING_LITERAL=23
+SEMI=24
+COMMENT=25
+WS=26
 '=='=6
 '!='=7
-','=8
-'['=9
-']'=10
-'('=11
-')'=12
-'in'=13
-'not in'=14
-'exists'=15
-';'=18
+'<'=8
+'<='=9
+'>'=10
+'>='=11
+','=12
+'['=13
+']'=14
+'('=15
+')'=16
+'in'=17
+'not in'=18
+'exists'=19
+';'=24

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/PredicateLexer.tokens
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/PredicateLexer.tokens b/metron-platform/metron-common/src/main/java/PredicateLexer.tokens
index e0726f9..7adce51 100644
--- a/metron-platform/metron-common/src/main/java/PredicateLexer.tokens
+++ b/metron-platform/metron-common/src/main/java/PredicateLexer.tokens
@@ -5,27 +5,37 @@ TRUE=4
 FALSE=5
 EQ=6
 NEQ=7
-COMMA=8
-LBRACKET=9
-RBRACKET=10
-LPAREN=11
-RPAREN=12
-IN=13
-NIN=14
-EXISTS=15
-IDENTIFIER=16
-STRING_LITERAL=17
-SEMI=18
-COMMENT=19
-WS=20
+LT=8
+LTE=9
+GT=10
+GTE=11
+COMMA=12
+LBRACKET=13
+RBRACKET=14
+LPAREN=15
+RPAREN=16
+IN=17
+NIN=18
+EXISTS=19
+INT_LITERAL=20
+DOUBLE_LITERAL=21
+IDENTIFIER=22
+STRING_LITERAL=23
+SEMI=24
+COMMENT=25
+WS=26
 '=='=6
 '!='=7
-','=8
-'['=9
-']'=10
-'('=11
-')'=12
-'in'=13
-'not in'=14
-'exists'=15
-';'=18
+'<'=8
+'<='=9
+'>'=10
+'>='=11
+','=12
+'['=13
+']'=14
+'('=15
+')'=16
+'in'=17
+'not in'=18
+'exists'=19
+';'=24

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/Transformation.tokens
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/Transformation.tokens b/metron-platform/metron-common/src/main/java/Transformation.tokens
new file mode 100644
index 0000000..82051aa
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/Transformation.tokens
@@ -0,0 +1,16 @@
+COMMA=1
+LBRACKET=2
+RBRACKET=3
+LPAREN=4
+RPAREN=5
+INT_LITERAL=6
+DOUBLE_LITERAL=7
+IDENTIFIER=8
+STRING_LITERAL=9
+COMMENT=10
+WS=11
+','=1
+'['=2
+']'=3
+'('=4
+')'=5

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/TransformationLexer.tokens
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/TransformationLexer.tokens b/metron-platform/metron-common/src/main/java/TransformationLexer.tokens
new file mode 100644
index 0000000..82051aa
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/TransformationLexer.tokens
@@ -0,0 +1,16 @@
+COMMA=1
+LBRACKET=2
+RBRACKET=3
+LPAREN=4
+RPAREN=5
+INT_LITERAL=6
+DOUBLE_LITERAL=7
+IDENTIFIER=8
+STRING_LITERAL=9
+COMMENT=10
+WS=11
+','=1
+'['=2
+']'=3
+'('=4
+')'=5

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/aggregator/Aggregators.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/aggregator/Aggregators.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/aggregator/Aggregators.java
index 35b7ada..57e3ae2 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/aggregator/Aggregators.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/aggregator/Aggregators.java
@@ -18,18 +18,21 @@
 
 package org.apache.metron.common.aggregator;
 
+import org.apache.metron.common.utils.ConversionUtils;
+
 import java.util.List;
 import java.util.Map;
 import java.util.function.BinaryOperator;
 import java.util.function.Predicate;
 
 public enum Aggregators implements Aggregator {
-   MAX( (numbers, config) -> accumulate(0d, (x,y) -> Math.max(x.doubleValue(),y.doubleValue()), numbers))
-  ,MIN( (numbers, config) -> accumulate(0d, (x,y) -> Math.min(x.doubleValue(),y.doubleValue()), numbers))
-  ,SUM( (numbers, config) -> accumulate(0d, (x,y) -> x.doubleValue() + y.doubleValue(), numbers))
+   MAX( (numbers, config) -> accumulate(0d, (x,y) -> Math.max(x.doubleValue(),y.doubleValue()), numbers, config))
+  ,MIN( (numbers, config) -> accumulate(0d, (x,y) -> Math.min(x.doubleValue(),y.doubleValue()), numbers, config))
+  ,SUM( (numbers, config) -> accumulate(0d, (x,y) -> x.doubleValue() + y.doubleValue(), numbers, config))
   ,MEAN( (numbers, config) -> scale(SUM.aggregate(numbers, config), numbers, n -> true))
-  ,POSITIVE_MEAN( (numbers, config) -> scale(SUM.aggregate(numbers, config), numbers, n -> n.doubleValue() > 0))
+  ,POSITIVE_MEAN( (numbers, config) -> positiveMean(numbers, config))
   ;
+  public static String NEGATIVE_VALUES_TRUMP_CONF = "negativeValuesTrump";
   Aggregator aggregator;
   Aggregators(Aggregator agg) {
     aggregator = agg;
@@ -38,12 +41,55 @@ public enum Aggregators implements Aggregator {
     return aggregator;
   }
 
-  private static double accumulate(double initial, BinaryOperator<Number> op, List<Number> list) {
+  private static double positiveMean(List<Number> list, Map<String, Object> config) {
+    Double ret = 0d;
+    int num = 0;
+    boolean negValuesTrump = doNegativeValuesTrump(config);
+    for(Number n : list) {
+      if(n.doubleValue() < 0) {
+        if(negValuesTrump) {
+          return Double.NEGATIVE_INFINITY;
+        }
+      }
+      else if(n.doubleValue() > 0) {
+        ret += n.doubleValue();
+        num++;
+      }
+    }
+    return num > 0?ret/num:0d;
+
+  }
+
+  private static boolean doNegativeValuesTrump(Map<String, Object> config) {
+    boolean negativeValuesTrump = true;
+    Object negValuesObj = config.get(NEGATIVE_VALUES_TRUMP_CONF);
+    if(negValuesObj != null)
+    {
+      Boolean b = ConversionUtils.convert(negValuesObj, Boolean.class);
+      if(b != null) {
+        negativeValuesTrump = b;
+      }
+    }
+    return negativeValuesTrump;
+  }
+  private static double accumulate(double initial, BinaryOperator<Number> op, List<Number> list, Map<String, Object> config) {
     if(list.isEmpty()) {
       return 0d;
     }
+    boolean negativeValuesTrump = doNegativeValuesTrump(config);
+
+    BinaryOperator<Number> binOp = op;
+    if(negativeValuesTrump) {
+      binOp =(x,y) -> {
+        if (y.doubleValue() < 0 || x.doubleValue() < 0) {
+          return Double.NEGATIVE_INFINITY;
+        } else {
+          return op.apply(x, y);
+        }
+      };
+    }
     return list.stream()
-               .reduce(initial, op)
+               .reduce(initial, binOp)
                .doubleValue();
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/ErrorListener.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/ErrorListener.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/ErrorListener.java
new file mode 100644
index 0000000..e01d56d
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/ErrorListener.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common.dsl;
+
+import org.antlr.v4.runtime.ANTLRErrorListener;
+import org.antlr.v4.runtime.Parser;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.antlr.v4.runtime.atn.ATNConfigSet;
+import org.antlr.v4.runtime.dfa.DFA;
+import org.apache.metron.common.dsl.ParseException;
+
+import java.util.BitSet;
+
+public class ErrorListener implements ANTLRErrorListener {
+  @Override
+  public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
+    throw new ParseException("Syntax error @ " + line + ":" + charPositionInLine+ " " + msg, e);
+  }
+
+
+  @Override
+  public void reportAmbiguity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, boolean exact, BitSet ambigAlts, ATNConfigSet configs) {
+  }
+
+
+  @Override
+  public void reportAttemptingFullContext(Parser recognizer, DFA dfa, int startIndex, int stopIndex, BitSet conflictingAlts, ATNConfigSet configs) {
+  }
+
+
+  @Override
+  public void reportContextSensitivity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, int prediction, ATNConfigSet configs) {
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/FunctionMarker.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/FunctionMarker.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/FunctionMarker.java
new file mode 100644
index 0000000..17ff488
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/FunctionMarker.java
@@ -0,0 +1,21 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common.dsl;
+
+public class FunctionMarker { }

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/MapVariableResolver.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/MapVariableResolver.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/MapVariableResolver.java
new file mode 100644
index 0000000..b03c66f
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/MapVariableResolver.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common.dsl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class MapVariableResolver implements VariableResolver {
+  List<Map> variableMappings = new ArrayList<>();
+  public MapVariableResolver(Map variableMappingOne, Map... variableMapping) {
+    variableMappings.add(variableMappingOne);
+    for(Map m : variableMapping) {
+      this.variableMappings.add(m);
+    }
+  }
+  @Override
+  public Object resolve(String variable) {
+    for(Map variableMapping : variableMappings) {
+      Object o = variableMapping.get(variable);
+      if(o != null) {
+        return o;
+      }
+    }
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/ParseException.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/ParseException.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/ParseException.java
new file mode 100644
index 0000000..20c65c6
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/ParseException.java
@@ -0,0 +1,28 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common.dsl;
+
+public class ParseException extends RuntimeException {
+  public ParseException(String reason) {
+    super(reason);
+  }
+  public ParseException(String reason, Throwable t) {
+    super(reason, t);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/Token.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/Token.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/Token.java
new file mode 100644
index 0000000..f2c56a5
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/Token.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common.dsl;
+
+public class Token<T> {
+  T value;
+  Class<T> underlyingType;
+  public Token(T value, Class<T> clazz) {
+    this.value = value;
+    this.underlyingType = clazz;
+  }
+  public T getValue() {
+    return value;
+  }
+  public Class<T> getUnderlyingType() {
+    return underlyingType;
+  }
+
+  @Override
+  public String toString() {
+    return value.toString();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    Token<?> token = (Token<?>) o;
+
+    if (getValue() != null ? !getValue().equals(token.getValue()) : token.getValue() != null) return false;
+    return getUnderlyingType() != null ? getUnderlyingType().equals(token.getUnderlyingType()) : token.getUnderlyingType() == null;
+
+  }
+
+  @Override
+  public int hashCode() {
+    int result = getValue() != null ? getValue().hashCode() : 0;
+    result = 31 * result + (getUnderlyingType() != null ? getUnderlyingType().hashCode() : 0);
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/TransformationFunctions.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/TransformationFunctions.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/TransformationFunctions.java
new file mode 100644
index 0000000..3cc51ce
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/TransformationFunctions.java
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common.dsl;
+
+import org.apache.metron.common.dsl.functions.DateFunctions;
+import org.apache.metron.common.dsl.functions.MapFunctions;
+import org.apache.metron.common.dsl.functions.NetworkFunctions;
+import org.apache.metron.common.dsl.functions.StringFunctions;
+import org.apache.metron.common.utils.ConversionUtils;
+
+import java.util.List;
+import java.util.function.Function;
+
+public enum TransformationFunctions implements Function<List<Object>, Object> {
+  TO_LOWER(strings -> strings.get(0)==null?null:strings.get(0).toString().toLowerCase())
+  ,TO_UPPER(strings -> strings.get(0) == null?null:strings.get(0).toString().toUpperCase())
+  ,TO_STRING(strings -> strings.get(0) == null?null:strings.get(0).toString())
+  ,TO_INTEGER(strings -> strings.get(0) == null?null: ConversionUtils.convert(strings.get(0), Integer.class))
+  ,TO_DOUBLE(strings -> strings.get(0) == null?null: ConversionUtils.convert(strings.get(0), Double.class))
+  ,TRIM(strings -> strings.get(0) == null?null:strings.get(0).toString().trim())
+  ,JOIN(new StringFunctions.JoinFunction())
+  ,SPLIT(new StringFunctions.SplitFunction())
+  ,GET_FIRST(new StringFunctions.GetFirst())
+  ,GET_LAST(new StringFunctions.GetLast())
+  ,GET(new StringFunctions.Get())
+  ,MAP_GET(new MapFunctions.MapGet())
+  ,DOMAIN_TO_TLD(new NetworkFunctions.ExtractTLD())
+  ,DOMAIN_REMOVE_TLD(new NetworkFunctions.RemoveTLD())
+  ,DOMAIN_REMOVE_SUBDOMAINS(new NetworkFunctions.RemoveSubdomains())
+  ,URL_TO_HOST(new NetworkFunctions.URLToHost())
+  ,URL_TO_PORT(new NetworkFunctions.URLToPort())
+  ,URL_TO_PATH(new NetworkFunctions.URLToPath())
+  ,URL_TO_PROTOCOL(new NetworkFunctions.URLToProtocol())
+  ,TO_EPOCH_TIMESTAMP(new DateFunctions.ToTimestamp())
+  ;
+  Function<List<Object>, Object> func;
+  TransformationFunctions(Function<List<Object>, Object> func) {
+    this.func = func;
+  }
+
+  @Override
+  public Object apply(List<Object> input) {
+    return func.apply(input);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/VariableResolver.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/VariableResolver.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/VariableResolver.java
new file mode 100644
index 0000000..5c5b23f
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/VariableResolver.java
@@ -0,0 +1,23 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common.dsl;
+
+public interface VariableResolver {
+  Object resolve(String variable);
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/functions/DateFunctions.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/functions/DateFunctions.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/functions/DateFunctions.java
new file mode 100644
index 0000000..f4a2b97
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/functions/DateFunctions.java
@@ -0,0 +1,129 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common.dsl.functions;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.List;
+import java.util.Optional;
+import java.util.TimeZone;
+import java.util.concurrent.ExecutionException;
+import java.util.function.Function;
+
+public class DateFunctions {
+
+  private static class TimezonedFormat {
+    private String format;
+    private Optional<String> timezone;
+    public TimezonedFormat(String format, String timezone) {
+      this.format = format;
+      this.timezone = Optional.of(timezone);
+    }
+
+    public TimezonedFormat(String format) {
+      this.format = format;
+      this.timezone = Optional.empty();
+    }
+    public SimpleDateFormat toDateFormat() {
+      return createFormat(format, timezone);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      TimezonedFormat that = (TimezonedFormat) o;
+
+      if (format != null ? !format.equals(that.format) : that.format != null) return false;
+      return timezone != null ? timezone.equals(that.timezone) : that.timezone == null;
+
+    }
+
+    @Override
+    public int hashCode() {
+      int result = format != null ? format.hashCode() : 0;
+      result = 31 * result + (timezone != null ? timezone.hashCode() : 0);
+      return result;
+    }
+  }
+
+  private static LoadingCache<TimezonedFormat, ThreadLocal<SimpleDateFormat>> formatCache
+          = CacheBuilder.newBuilder().build(new CacheLoader<TimezonedFormat, ThreadLocal<SimpleDateFormat>>() {
+            @Override
+            public ThreadLocal<SimpleDateFormat> load(final TimezonedFormat format) throws Exception {
+              return new ThreadLocal<SimpleDateFormat>() {
+                @Override
+                public SimpleDateFormat initialValue() {
+                  return format.toDateFormat();
+                }
+              };
+            }
+          }
+                        );
+
+  public static SimpleDateFormat createFormat(String format, Optional<String> timezone) {
+    SimpleDateFormat sdf = new SimpleDateFormat(format);
+    if(timezone.isPresent()) {
+      sdf.setTimeZone(TimeZone.getTimeZone(timezone.get()));
+    }
+    return sdf;
+  }
+  public static long getEpochTime(String date, String format, Optional<String> timezone) throws ExecutionException, ParseException {
+    TimezonedFormat fmt = null;
+    if(timezone.isPresent()) {
+      fmt = new TimezonedFormat(format, timezone.get());
+    }
+    else {
+      fmt = new TimezonedFormat(format);
+    }
+    SimpleDateFormat sdf = formatCache.get(fmt).get();
+    return sdf.parse(date).getTime();
+  }
+
+
+  public static class ToTimestamp implements Function<List<Object>, Object> {
+    @Override
+    public Object apply(List<Object> objects) {
+      Object dateObj = objects.get(0);
+      Object formatObj = objects.get(1);
+      Object tzObj = null;
+      if(objects.size() >= 3) {
+        tzObj = objects.get(2);
+      }
+      if(dateObj != null && formatObj != null) {
+        try {
+          return getEpochTime(dateObj.toString()
+                             , formatObj.toString()
+                             , tzObj == null?Optional.empty():Optional.of(tzObj.toString())
+                             );
+        } catch (ExecutionException e) {
+          return null;
+        } catch (ParseException e) {
+          return null;
+        }
+      }
+      return null;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/functions/MapFunctions.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/functions/MapFunctions.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/functions/MapFunctions.java
new file mode 100644
index 0000000..5d43416
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/functions/MapFunctions.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common.dsl.functions;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+public class MapFunctions {
+  public static class MapGet implements Function<List<Object>, Object> {
+    @Override
+    public Object apply(List<Object> objects) {
+      Object keyObj = objects.get(0);
+      Object mapObj = objects.get(1);
+      Object defaultObj = null;
+      if(objects.size() >= 3) {
+        defaultObj = objects.get(2);
+      }
+      if(keyObj == null || mapObj == null) {
+        return defaultObj;
+      }
+      Map<Object, Object> map = (Map)mapObj;
+      Object ret = map.get(keyObj);
+      if(ret == null && defaultObj != null) {
+        return defaultObj;
+      }
+      return ret;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/functions/NetworkFunctions.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/functions/NetworkFunctions.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/functions/NetworkFunctions.java
new file mode 100644
index 0000000..e8cda44
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/functions/NetworkFunctions.java
@@ -0,0 +1,144 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common.dsl.functions;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.Iterables;
+import com.google.common.net.InternetDomainName;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+import java.util.function.Function;
+
+public class NetworkFunctions {
+  public static class RemoveSubdomains implements Function<List<Object>, Object> {
+
+    @Override
+    public Object apply(List<Object> objects) {
+      Object dnObj = objects.get(0);
+      InternetDomainName idn = toDomainName(dnObj);
+      if(idn != null) {
+        String dn = dnObj.toString();
+        String tld = idn.publicSuffix().toString();
+        String suffix = Iterables.getFirst(Splitter.on(tld).split(dn), null);
+        if(suffix != null)
+        {
+          String hostnameWithoutTLD = suffix.substring(0, suffix.length() - 1);
+          String hostnameWithoutSubsAndTLD = Iterables.getLast(Splitter.on(".").split(hostnameWithoutTLD), null);
+          if(hostnameWithoutSubsAndTLD == null) {
+            return null;
+          }
+          return hostnameWithoutSubsAndTLD + "." + tld;
+        }
+        else {
+          return null;
+        }
+      }
+      return null;
+    }
+  }
+  public static class RemoveTLD implements Function<List<Object>, Object> {
+    @Override
+    public Object apply(List<Object> objects) {
+      Object dnObj = objects.get(0);
+      InternetDomainName idn = toDomainName(dnObj);
+      if(idn != null) {
+        String dn = dnObj.toString();
+        String tld = idn.publicSuffix().toString();
+        String suffix = Iterables.getFirst(Splitter.on(tld).split(dn), null);
+        if(suffix != null)
+        {
+          return suffix.substring(0, suffix.length() - 1);
+        }
+        else {
+          return null;
+        }
+      }
+      return null;
+    }
+  }
+
+  public static class ExtractTLD implements Function<List<Object>, Object> {
+    @Override
+    public Object apply(List<Object> objects) {
+      Object dnObj = objects.get(0);
+      InternetDomainName idn = toDomainName(dnObj);
+      if(idn != null) {
+        return idn.publicSuffix().toString();
+      }
+      return null;
+    }
+  }
+
+  public static class URLToPort implements Function<List<Object>, Object> {
+    @Override
+    public Object apply(List<Object> objects) {
+      URL url =  toUrl(objects.get(0));
+      if(url == null) {
+        return null;
+      }
+      int port = url.getPort();
+      return port >= 0?port:url.getDefaultPort();
+    }
+  }
+
+  public static class URLToPath implements Function<List<Object>, Object> {
+    @Override
+    public Object apply(List<Object> objects) {
+      URL url =  toUrl(objects.get(0));
+      return url == null?null:url.getPath();
+    }
+  }
+  public static class URLToHost implements Function<List<Object>, Object> {
+
+    @Override
+    public Object apply(List<Object> objects) {
+      URL url =  toUrl(objects.get(0));
+      return url == null?null:url.getHost();
+    }
+  }
+
+  public static class URLToProtocol implements Function<List<Object>, Object> {
+
+    @Override
+    public Object apply(List<Object> objects) {
+      URL url =  toUrl(objects.get(0));
+      return url == null?null:url.getProtocol();
+    }
+  }
+  private static InternetDomainName toDomainName(Object dnObj) {
+    if(dnObj != null) {
+      String dn = dnObj.toString();
+      return InternetDomainName.from(dn);
+    }
+    return null;
+  }
+
+  private static URL toUrl(Object urlObj) {
+    if(urlObj == null) {
+      return null;
+    }
+    try {
+      return new URL(urlObj.toString());
+    } catch (MalformedURLException e) {
+      return null;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/functions/StringFunctions.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/functions/StringFunctions.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/functions/StringFunctions.java
new file mode 100644
index 0000000..2793f02
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/dsl/functions/StringFunctions.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common.dsl.functions;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Iterables;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+public class StringFunctions {
+  public static class JoinFunction implements Function<List<Object>, Object> {
+    @Override
+    public Object apply(List<Object> args) {
+      List<Object> arg1 = (List<Object>) args.get(0);
+      String delim = (String) args.get(1);
+      return Joiner.on(delim).join(Iterables.filter(arg1, x -> x != null));
+    }
+  }
+  public static class SplitFunction implements Function<List<Object>, Object> {
+    @Override
+    public Object apply(List<Object> args) {
+      List ret = new ArrayList();
+      Object o1 = args.get(0);
+      if(o1 != null) {
+        String arg1 = o1.toString();
+        String delim = (String) args.get(1);
+        Iterables.addAll(ret, Splitter.on(delim).split(arg1));
+      }
+      return ret;
+    }
+  }
+
+  public static class GetLast implements Function<List<Object>, Object> {
+    @Override
+    public Object apply(List<Object> args) {
+      List<Object> arg1 = (List<Object>) args.get(0);
+      return Iterables.getLast(arg1, null);
+    }
+  }
+  public static class GetFirst implements Function<List<Object>, Object> {
+    @Override
+    public Object apply(List<Object> args) {
+      List<Object> arg1 = (List<Object>) args.get(0);
+      return Iterables.getFirst(arg1, null);
+    }
+  }
+
+  public static class Get implements Function<List<Object>, Object> {
+    @Override
+    public Object apply(List<Object> args) {
+      List<Object> arg1 = (List<Object>) args.get(0);
+      int offset = (Integer) args.get(1);
+      if(offset < arg1.size()) {
+        return Iterables.get(arg1, offset);
+      }
+      return null;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/FieldTransformations.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/FieldTransformations.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/FieldTransformations.java
index f4fa488..e16987c 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/FieldTransformations.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/FieldTransformations.java
@@ -23,6 +23,7 @@ import org.apache.metron.common.utils.ReflectionUtils;
 public enum FieldTransformations {
   IP_PROTOCOL(new IPProtocolTransformation())
   ,REMOVE(new RemoveTransformation())
+  ,MTL(new MTLTransformation())
   ;
   FieldTransformation mapping;
   FieldTransformations(FieldTransformation mapping) {

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/MTLTransformation.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/MTLTransformation.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/MTLTransformation.java
new file mode 100644
index 0000000..e0dd40e
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/MTLTransformation.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common.field.transformation;
+
+import org.apache.metron.common.dsl.MapVariableResolver;
+import org.apache.metron.common.dsl.VariableResolver;
+import org.apache.metron.common.transformation.TransformationProcessor;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class MTLTransformation implements FieldTransformation {
+  @Override
+  public Map<String, Object> map( Map<String, Object> input
+                                , List<String> outputField
+                                , Map<String, Object> fieldMappingConfig
+                                , Map<String, Object> sensorConfig
+                                )
+  {
+    Map<String, Object> ret = new HashMap<>();
+    VariableResolver resolver = new MapVariableResolver(ret, input,fieldMappingConfig, sensorConfig);
+    TransformationProcessor processor = new TransformationProcessor();
+    for(String oField : outputField) {
+      Object transformObj = fieldMappingConfig.get(oField);
+      if(transformObj != null) {
+        Object o = processor.parse(transformObj.toString(), resolver);
+        if (o != null) {
+          ret.put(oField, o);
+        }
+      }
+    }
+    return ret;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/RemoveTransformation.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/RemoveTransformation.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/RemoveTransformation.java
index c370cd3..c90e2b3 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/RemoveTransformation.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/RemoveTransformation.java
@@ -18,11 +18,10 @@
 
 package org.apache.metron.common.field.transformation;
 
-import com.google.common.collect.ImmutableMap;
-import org.apache.metron.common.query.MapVariableResolver;
-import org.apache.metron.common.query.ParseException;
+import org.apache.metron.common.dsl.MapVariableResolver;
+import org.apache.metron.common.dsl.ParseException;
 import org.apache.metron.common.query.PredicateProcessor;
-import org.apache.metron.common.query.VariableResolver;
+import org.apache.metron.common.dsl.VariableResolver;
 
 import java.util.HashMap;
 import java.util.List;

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/QueryValidation.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/QueryValidation.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/QueryValidation.java
index 6c0ab86..0760220 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/QueryValidation.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/QueryValidation.java
@@ -18,7 +18,7 @@
 
 package org.apache.metron.common.field.validation;
 
-import org.apache.metron.common.query.MapVariableResolver;
+import org.apache.metron.common.dsl.MapVariableResolver;
 import org.apache.metron.common.query.PredicateProcessor;
 
 import java.util.Map;
@@ -52,7 +52,7 @@ public class QueryValidation implements FieldValidation {
     }
     else {
       PredicateProcessor processor = new PredicateProcessor();
-      return processor.parse(condition, new MapVariableResolver(input));
+      return processor.parse(condition, new MapVariableResolver(input, validationConfig, globalConfig));
     }
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/SimpleValidation.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/SimpleValidation.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/SimpleValidation.java
index c409253..acaa790 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/SimpleValidation.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/SimpleValidation.java
@@ -25,14 +25,14 @@ import java.util.Map;
 import java.util.function.Function;
 import java.util.function.Predicate;
 
-public abstract class SimpleValidation implements FieldValidation, Predicate<List<String>> {
+public abstract class SimpleValidation implements FieldValidation, Predicate<List<Object>> {
   @Override
   public boolean isValid( Map<String, Object> input
                         , Map<String, Object> validationConfig
                         , Map<String, Object> globalConfig
                         )
   {
-    Predicate<String> predicate = getPredicate();
+    Predicate<Object> predicate = getPredicate();
     if(isNonExistentOk()) {
       for (Object o : input.values()) {
         if (o != null && !predicate.test(o.toString())) {
@@ -51,9 +51,9 @@ public abstract class SimpleValidation implements FieldValidation, Predicate<Lis
   }
 
   @Override
-  public boolean test(List<String> input) {
-    Predicate<String> predicate = getPredicate();
-    for(String o : input) {
+  public boolean test(List<Object> input) {
+    Predicate<Object> predicate = getPredicate();
+    for(Object o : input) {
       if(o == null || !predicate.test(o)){
         return false;
       }
@@ -66,7 +66,7 @@ public abstract class SimpleValidation implements FieldValidation, Predicate<Lis
 
   }
 
-  public abstract Predicate<String> getPredicate();
+  public abstract Predicate<Object> getPredicate();
   protected boolean isNonExistentOk() {
     return true;
   }

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/DomainValidation.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/DomainValidation.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/DomainValidation.java
index 5a9c121..8b1fc36 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/DomainValidation.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/DomainValidation.java
@@ -28,7 +28,7 @@ import java.util.function.Predicate;
 public class DomainValidation extends SimpleValidation {
 
   @Override
-  public Predicate<String> getPredicate() {
-    return domain -> DomainValidator.getInstance().isValid(domain);
+  public Predicate<Object> getPredicate() {
+    return domain -> DomainValidator.getInstance().isValid(domain == null?null:domain.toString());
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/EmailValidation.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/EmailValidation.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/EmailValidation.java
index f2a09bd..44d835c 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/EmailValidation.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/EmailValidation.java
@@ -26,7 +26,7 @@ import java.util.function.Predicate;
 
 public class EmailValidation extends SimpleValidation{
   @Override
-  public Predicate<String> getPredicate() {
-    return email -> EmailValidator.getInstance().isValid(email);
+  public Predicate<Object> getPredicate() {
+    return email -> EmailValidator.getInstance().isValid(email == null?null:email.toString());
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/IPValidation.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/IPValidation.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/IPValidation.java
index 42b0aaf..0aa9075 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/IPValidation.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/IPValidation.java
@@ -25,7 +25,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.function.Predicate;
 
-public class IPValidation implements FieldValidation, Predicate<List<String>> {
+public class IPValidation implements FieldValidation, Predicate<List<Object>> {
 
 
   private enum IPType {
@@ -77,24 +77,27 @@ public class IPValidation implements FieldValidation, Predicate<List<String>> {
    * otherwise {@code false}
    */
   @Override
-  public boolean test(List<String> strings) {
+  public boolean test(List<Object> strings) {
     IPType type = IPType.DEFAULT;
     if(strings.isEmpty()) {
       return false;
     }
-    String ip = strings.get(0);
+    Object ip =  strings.get(0);
     if(ip == null) {
       return false;
     }
     if(strings.size() >= 2) {
-      try {
-        type = IPType.get(strings.get(1));
-      }
-      catch(Exception e) {
-        type = IPType.DEFAULT;
+      Object ipType = strings.get(1);
+      if(ipType != null )
+      {
+        try {
+          type = IPType.get(ipType.toString());
+        } catch (Exception e) {
+          type = IPType.DEFAULT;
+        }
       }
     }
-    return type.isValid(ip);
+    return type.isValid(ip.toString());
   }
   @Override
   public boolean isValid( Map<String, Object> input

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/URLValidation.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/URLValidation.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/URLValidation.java
index 4a044b0..5ef053b 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/URLValidation.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/network/URLValidation.java
@@ -25,7 +25,7 @@ import java.util.function.Predicate;
 
 public class URLValidation extends SimpleValidation {
   @Override
-  public Predicate<String> getPredicate() {
-    return url -> UrlValidator.getInstance().isValid(url);
+  public Predicate<Object> getPredicate() {
+    return url -> UrlValidator.getInstance().isValid(url == null?null:url.toString());
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/primitive/DateValidation.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/primitive/DateValidation.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/primitive/DateValidation.java
index 3a28462..85121e2 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/primitive/DateValidation.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/primitive/DateValidation.java
@@ -27,7 +27,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.function.Predicate;
 
-public class DateValidation implements FieldValidation, Predicate<List<String>> {
+public class DateValidation implements FieldValidation, Predicate<List<Object>> {
 
   /**
    * Evaluates this predicate on the given argument.
@@ -37,19 +37,19 @@ public class DateValidation implements FieldValidation, Predicate<List<String>>
    * otherwise {@code false}
    */
   @Override
-  public boolean test(List<String> strings) {
+  public boolean test(List<Object> strings) {
     if(strings.isEmpty()) {
       return false;
     }
     if(strings.size() >= 2) {
-      String date = strings.get(0);
-      String format = strings.get(1);
+      Object date = strings.get(0);
+      Object format = strings.get(1);
       if(date == null || format == null) {
         return false;
       }
       try {
-        SimpleDateFormat sdf = new SimpleDateFormat(format);
-        sdf.parse(date);
+        SimpleDateFormat sdf = new SimpleDateFormat(format.toString());
+        sdf.parse(date.toString());
         return true;
       }
       catch(ParseException pe) {

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/primitive/IntegerValidation.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/primitive/IntegerValidation.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/primitive/IntegerValidation.java
index 320d56d..d803e37 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/primitive/IntegerValidation.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/primitive/IntegerValidation.java
@@ -26,7 +26,7 @@ import java.util.function.Predicate;
 
 public class IntegerValidation extends SimpleValidation{
   @Override
-  public Predicate<String> getPredicate() {
-    return x -> LongValidator.getInstance().isValid(x);
+  public Predicate<Object> getPredicate() {
+    return x -> LongValidator.getInstance().isValid(x == null?null:x.toString());
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/primitive/NotEmptyValidation.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/primitive/NotEmptyValidation.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/primitive/NotEmptyValidation.java
index 98d2269..28ac002 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/primitive/NotEmptyValidation.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/validation/primitive/NotEmptyValidation.java
@@ -24,8 +24,8 @@ import java.util.function.Predicate;
 
 public class NotEmptyValidation extends SimpleValidation {
   @Override
-  public Predicate<String> getPredicate() {
-    return s -> !(s == null || s.trim().isEmpty());
+  public Predicate<Object> getPredicate() {
+    return s -> !(s == null || s.toString().trim().isEmpty());
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/ErrorListener.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/ErrorListener.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/ErrorListener.java
deleted file mode 100644
index 883dee2..0000000
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/ErrorListener.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.metron.common.query;
-
-import org.antlr.v4.runtime.ANTLRErrorListener;
-import org.antlr.v4.runtime.Parser;
-import org.antlr.v4.runtime.RecognitionException;
-import org.antlr.v4.runtime.Recognizer;
-import org.antlr.v4.runtime.atn.ATNConfigSet;
-import org.antlr.v4.runtime.dfa.DFA;
-
-import java.util.BitSet;
-
-public class ErrorListener implements ANTLRErrorListener {
-  @Override
-  public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
-    throw new ParseException("Syntax error @ " + line + ":" + charPositionInLine+ " " + msg, e);
-  }
-
-
-  @Override
-  public void reportAmbiguity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, boolean exact, BitSet ambigAlts, ATNConfigSet configs) {
-  }
-
-
-  @Override
-  public void reportAttemptingFullContext(Parser recognizer, DFA dfa, int startIndex, int stopIndex, BitSet conflictingAlts, ATNConfigSet configs) {
-  }
-
-
-  @Override
-  public void reportContextSensitivity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, int prediction, ATNConfigSet configs) {
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/FunctionMarker.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/FunctionMarker.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/FunctionMarker.java
deleted file mode 100644
index aefbbbf..0000000
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/FunctionMarker.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.metron.common.query;
-
-public class FunctionMarker { }

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/LogicalFunctions.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/LogicalFunctions.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/LogicalFunctions.java
index bb35f04..63c696f 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/LogicalFunctions.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/LogicalFunctions.java
@@ -28,14 +28,16 @@ import org.apache.metron.common.field.validation.primitive.IntegerValidation;
 
 import javax.annotation.Nullable;
 import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
 import java.util.function.Predicate;
 
-public enum LogicalFunctions implements Predicate<List<String>> {
+public enum LogicalFunctions implements Predicate<List<Object>> {
   IS_EMPTY ( list -> {
     if(list.size() == 0) {
       throw new IllegalStateException("IS_EMPTY expects one string arg");
     }
-    String val = list.get(0);
+    String val = (String) list.get(0);
     return val == null || val.isEmpty() ? true:false;
   })
   ,IN_SUBNET( list -> {
@@ -44,13 +46,13 @@ public enum LogicalFunctions implements Predicate<List<String>> {
                                      + " where cidr is the subnet mask in cidr form"
                                      );
     }
-    String ip = list.get(0);
+    String ip = (String) list.get(0);
     if(ip == null) {
       return false;
     }
     boolean inSubnet = false;
     for(int i = 1;i < list.size() && !inSubnet;++i) {
-      String cidr = list.get(1);
+      String cidr = (String) list.get(1);
       if(cidr == null) {
         continue;
       }
@@ -63,8 +65,8 @@ public enum LogicalFunctions implements Predicate<List<String>> {
     if(list.size() < 2) {
       throw new IllegalStateException("STARTS_WITH expects two args: [string, prefix] where prefix is the string fragment that the string should start with");
     }
-    String prefix = list.get(1);
-    String str = list.get(0);
+    String prefix = (String) list.get(1);
+    String str = (String) list.get(0);
     if(str == null || prefix == null) {
       return false;
     }
@@ -74,8 +76,8 @@ public enum LogicalFunctions implements Predicate<List<String>> {
     if(list.size() < 2) {
       throw new IllegalStateException("ENDS_WITH expects two args: [string, suffix] where suffix is the string fragment that the string should end with");
     }
-    String prefix = list.get(1);
-    String str = list.get(0);
+    String prefix = (String) list.get(1);
+    String str = (String) list.get(0);
     if(str == null || prefix == null) {
       return false;
     }
@@ -85,8 +87,8 @@ public enum LogicalFunctions implements Predicate<List<String>> {
      if(list.size() < 2) {
       throw new IllegalStateException("REGEXP_MATCH expects two args: [string, pattern] where pattern is a regexp pattern");
     }
-    String pattern = list.get(1);
-    String str = list.get(0);
+    String pattern = (String) list.get(1);
+    String str = (String) list.get(0);
     if(str == null || pattern == null) {
       return false;
     }
@@ -98,14 +100,26 @@ public enum LogicalFunctions implements Predicate<List<String>> {
   , IS_URL(new URLValidation())
   , IS_DATE(new DateValidation())
   , IS_INTEGER(new IntegerValidation())
+  , MAP_EXISTS(list -> {
+      if(list.size() < 2) {
+        return false;
+      }
+      Object key = list.get(0);
+      Object mapObj = list.get(1);
+      if(key != null && mapObj != null && mapObj instanceof Map) {
+        return ((Map)mapObj).containsKey(key);
+      }
+      return false;
+    }
+  )
   ;
-  Predicate<List<String>> func;
-  LogicalFunctions(Predicate<List<String>> func) {
+  Predicate<List<Object>> func;
+  LogicalFunctions(Predicate<List<Object>> func) {
     this.func = func;
   }
   @Nullable
   @Override
-  public boolean test(@Nullable List<String> input) {
+  public boolean test(@Nullable List<Object> input) {
     return func.test(input);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/MapVariableResolver.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/MapVariableResolver.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/MapVariableResolver.java
deleted file mode 100644
index ad1f810..0000000
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/MapVariableResolver.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.metron.common.query;
-
-import java.util.Map;
-
-public class MapVariableResolver implements VariableResolver {
-  Map variableMapping;
-  public MapVariableResolver(Map variableMapping) {
-    this.variableMapping = variableMapping;
-  }
-  @Override
-  public String resolve(String variable) {
-    Object o = variableMapping.get(variable);
-    return o == null?null:o.toString();
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/ParseException.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/ParseException.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/ParseException.java
deleted file mode 100644
index 7d658f0..0000000
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/ParseException.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.metron.common.query;
-
-public class ParseException extends RuntimeException {
-  public ParseException(String reason) {
-    super(reason);
-  }
-  public ParseException(String reason, Throwable t) {
-    super(reason, t);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/PredicateProcessor.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/PredicateProcessor.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/PredicateProcessor.java
index 95b943a..304768e 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/PredicateProcessor.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/PredicateProcessor.java
@@ -25,6 +25,9 @@ import com.google.common.cache.LoadingCache;
 import org.antlr.v4.runtime.ANTLRInputStream;
 import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.TokenStream;
+import org.apache.metron.common.dsl.ErrorListener;
+import org.apache.metron.common.dsl.ParseException;
+import org.apache.metron.common.dsl.VariableResolver;
 import org.apache.metron.common.query.generated.PredicateLexer;
 import org.apache.metron.common.query.generated.PredicateParser;
 


[3/4] incubator-metron git commit: METRON-204: Field Transformation Domain Specific Language. This closes apache/incubator-metron#142

Posted by ce...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/PredicateToken.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/PredicateToken.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/PredicateToken.java
deleted file mode 100644
index 54ac17d..0000000
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/PredicateToken.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.metron.common.query;
-
-public class PredicateToken<T> {
-  T value;
-  Class<T> underlyingType;
-  public PredicateToken(T value, Class<T> clazz) {
-    this.value = value;
-    this.underlyingType = clazz;
-  }
-  public T getValue() {
-    return value;
-  }
-  public Class<T> getUnderlyingType() {
-    return underlyingType;
-  }
-
-  @Override
-  public String toString() {
-    return value.toString();
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
-
-    PredicateToken<?> predicateToken = (PredicateToken<?>) o;
-
-    if (getValue() != null ? !getValue().equals(predicateToken.getValue()) : predicateToken.getValue() != null) return false;
-    return getUnderlyingType() != null ? getUnderlyingType().equals(predicateToken.getUnderlyingType()) : predicateToken.getUnderlyingType() == null;
-
-  }
-
-  @Override
-  public int hashCode() {
-    int result = getValue() != null ? getValue().hashCode() : 0;
-    result = 31 * result + (getUnderlyingType() != null ? getUnderlyingType().hashCode() : 0);
-    return result;
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/QueryCompiler.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/QueryCompiler.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/QueryCompiler.java
index 3d85d9e..3e074dc 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/QueryCompiler.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/QueryCompiler.java
@@ -18,17 +18,19 @@
 
 package org.apache.metron.common.query;
 
-import com.google.common.base.Function;
 import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+import org.apache.metron.common.dsl.*;
 import org.apache.metron.common.query.generated.PredicateBaseListener;
 import org.apache.metron.common.query.generated.PredicateParser;
 
 import java.util.*;
+import java.util.function.Function;
 import java.util.function.Predicate;
 
 class QueryCompiler extends PredicateBaseListener {
   private VariableResolver resolver = null;
-  private Stack<PredicateToken> tokenStack = new Stack<>();
+  private Stack<Token> tokenStack = new Stack<>();
 
   public QueryCompiler(VariableResolver resolver) {
     this.resolver = resolver;
@@ -45,20 +47,20 @@ class QueryCompiler extends PredicateBaseListener {
 
   @Override
   public void exitLogicalExpressionAnd(PredicateParser.LogicalExpressionAndContext ctx) {
-    PredicateToken<?> left = popStack();
-    PredicateToken<?> right = popStack();
-    tokenStack.push(new PredicateToken<>(booleanOp(left, right, (l, r) -> l && r, "&&"), Boolean.class));
+    Token<?> left = popStack();
+    Token<?> right = popStack();
+    tokenStack.push(new Token<>(booleanOp(left, right, (l, r) -> l && r, "&&"), Boolean.class));
   }
 
   @Override
   public void exitLogicalExpressionOr(PredicateParser.LogicalExpressionOrContext ctx) {
-    PredicateToken<?> left = popStack();
-    PredicateToken<?> right = popStack();
+    Token<?> left = popStack();
+    Token<?> right = popStack();
 
-    tokenStack.push(new PredicateToken<>(booleanOp(left, right, (l, r) -> l || r, "||"), Boolean.class));
+    tokenStack.push(new Token<>(booleanOp(left, right, (l, r) -> l || r, "||"), Boolean.class));
   }
 
-  private boolean booleanOp(PredicateToken<?> left, PredicateToken<?> right, BooleanOp op, String opName)
+  private boolean booleanOp(Token<?> left, Token<?> right, BooleanOp op, String opName)
   {
     if(left.getUnderlyingType().equals(right.getUnderlyingType()) && left.getUnderlyingType().equals(Boolean.class)) {
       Boolean l = (Boolean) left.getValue();
@@ -87,24 +89,63 @@ class QueryCompiler extends PredicateBaseListener {
       default:
         throw new ParseException("Unable to process " + ctx.getText() + " as a boolean constant");
     }
-    tokenStack.push(new PredicateToken<>(b, Boolean.class));
+    tokenStack.push(new Token<>(b, Boolean.class));
+  }
+
+
+  @Override
+  public void exitDoubleLiteral(PredicateParser.DoubleLiteralContext ctx) {
+    tokenStack.push(new Token<>(Double.parseDouble(ctx.getText()), Double.class));
+  }
+
+
+  @Override
+  public void exitIntegerLiteral(PredicateParser.IntegerLiteralContext ctx) {
+    tokenStack.push(new Token<>(Integer.parseInt(ctx.getText()), Integer.class));
+  }
+
+  private <T extends Comparable<T>> boolean compare(T l, T r, String op) {
+    if(op.equals("==")) {
+        return l.compareTo(r) == 0;
+      }
+      else if(op.equals("!=")) {
+        return l.compareTo(r) != 0;
+      }
+      else if(op.equals("<")) {
+        return l.compareTo(r) < 0;
+      }
+      else if(op.equals(">")) {
+        return l.compareTo(r) > 0;
+      }
+      else if(op.equals(">=")) {
+        return l.compareTo(r) >= 0;
+      }
+      else {
+        return l.compareTo(r) <= 0;
+      }
   }
 
   @Override
   public void exitComparisonExpressionWithOperator(PredicateParser.ComparisonExpressionWithOperatorContext ctx) {
-    boolean isEqualsOp = ctx.getChild(1).getText().equals("==");
-    PredicateToken<?> left = popStack();
-    PredicateToken<?> right = popStack();
-    if(left.getUnderlyingType().equals(right.getUnderlyingType())) {
-      boolean isEquals = left.equals(right);
-      tokenStack.push(new PredicateToken<>(isEqualsOp?isEquals:!isEquals, Boolean.class));
+    String op = ctx.getChild(1).getText();
+    Token<?> right = popStack();
+    Token<?> left = popStack();
+    if(left.getValue() instanceof Number
+    && right.getValue() instanceof Number
+      ) {
+      Double l = ((Number)left.getValue()).doubleValue();
+      Double r = ((Number)right.getValue()).doubleValue();
+      tokenStack.push(new Token<>(compare(l, r, op), Boolean.class));
+
     }
     else {
-      throw new ParseException("Unable to compare " + left.getValue() + " " + ctx.getText() + " " + right.getValue());
+      String l = left.getValue() == null?"":left.getValue().toString();
+      String r = right.getValue() == null?"":right.getValue().toString();
+      tokenStack.push(new Token<>(compare(l, r, op), Boolean.class));
     }
   }
 
-  public PredicateToken<?> popStack() {
+  public Token<?> popStack() {
     if(tokenStack.empty()) {
       throw new ParseException("Unable to pop an empty stack");
     }
@@ -113,107 +154,101 @@ class QueryCompiler extends PredicateBaseListener {
 
   @Override
   public void exitLogicalVariable(PredicateParser.LogicalVariableContext ctx) {
-    tokenStack.push(new PredicateToken<>(resolver.resolve(ctx.getText()), String.class));
+    tokenStack.push(new Token<>(resolver.resolve(ctx.getText()), Object.class));
   }
 
 
   @Override
   public void exitStringLiteral(PredicateParser.StringLiteralContext ctx) {
     String val = ctx.getText();
-    tokenStack.push(new PredicateToken<>(val.substring(1, val.length() - 1), String.class));
+    tokenStack.push(new Token<>(val.substring(1, val.length() - 1), String.class));
   }
 
 
+
   @Override
   public void enterList_entity(PredicateParser.List_entityContext ctx) {
-    tokenStack.push(new PredicateToken<>(new FunctionMarker(), FunctionMarker.class));
+    tokenStack.push(new Token<>(new FunctionMarker(), FunctionMarker.class));
   }
 
 
   @Override
   public void exitList_entity(PredicateParser.List_entityContext ctx) {
-    Set<String> inSet = new HashSet<>();
+    LinkedList<String> args = new LinkedList<>();
     while(true) {
-      PredicateToken<?> token = popStack();
+      Token<?> token = popStack();
       if(token.getUnderlyingType().equals(FunctionMarker.class)) {
         break;
       }
       else {
-        inSet.add((String)token.getValue());
+        args.addFirst((String)token.getValue());
       }
     }
-    tokenStack.push(new PredicateToken<>(inSet, Set.class));
+    tokenStack.push(new Token<>(args, List.class));
   }
 
 
   @Override
   public void enterFunc_args(PredicateParser.Func_argsContext ctx) {
-    tokenStack.push(new PredicateToken<>(new FunctionMarker(), FunctionMarker.class));
+    tokenStack.push(new Token<>(new FunctionMarker(), FunctionMarker.class));
   }
 
 
   @Override
   public void exitFunc_args(PredicateParser.Func_argsContext ctx) {
-    LinkedList<String> args = new LinkedList<>();
+    LinkedList<Object> args = new LinkedList<>();
     while(true) {
-      PredicateToken<?> token = popStack();
+      Token<?> token = popStack();
       if(token.getUnderlyingType().equals(FunctionMarker.class)) {
         break;
       }
       else {
-        args.addFirst((String)token.getValue());
+        args.addFirst(token.getValue());
       }
     }
-    tokenStack.push(new PredicateToken<>(args, List.class));
+    tokenStack.push(new Token<>(args, List.class));
   }
 
-  @Override
-  public void exitInExpression(PredicateParser.InExpressionContext ctx) {
-    PredicateToken<?> left = popStack();
-    PredicateToken<?> right = popStack();
-    String key = null;
-    Set<String> set = null;
-    if(left.getUnderlyingType().equals(Set.class)) {
-      set = (Set<String>) left.getValue();
-    }
-    else {
-      throw new ParseException("Unable to process in clause because " + left.getValue() + " is not a set");
+  private boolean handleIn(Token<?> left, Token<?> right) {
+    Object key = null;
+    Set<Object> set = null;
+    if(left.getValue() instanceof Collection) {
+      set = new HashSet<>((List<Object>) left.getValue());
     }
-    if(right.getUnderlyingType().equals(String.class)) {
-      key = (String) right.getValue();
+    else if(left.getValue() != null) {
+      set = ImmutableSet.of(left.getValue());
     }
     else {
-      throw new ParseException("Unable to process in clause because " + right.getValue() + " is not a string");
+      set = new HashSet<>();
+    }
+
+
+    key = right.getValue();
+    if(key == null || set.isEmpty()) {
+      return false;
     }
-    tokenStack.push(new PredicateToken<>(set.contains(key), Boolean.class));
+    return set.contains(key);
   }
 
   @Override
-  public void exitNInExpression(PredicateParser.NInExpressionContext ctx) {
-    PredicateToken<?> left = popStack();
-    PredicateToken<?> right = popStack();
-    String key = null;
-    Set<String> set = null;
-    if(left.getUnderlyingType().equals(Set.class)) {
-      set = (Set<String>) left.getValue();
-    }
-    else {
-      throw new ParseException("Unable to process in clause because " + left.getValue() + " is not a set");
-    }
-    if(right.getUnderlyingType().equals(String.class)) {
-      key = (String) right.getValue();
-    }
-    else {
-      throw new ParseException("Unable to process in clause because " + right.getValue() + " is not a string");
-    }
-    tokenStack.push(new PredicateToken<>(!set.contains(key), Boolean.class));
+  public void exitInExpression(PredicateParser.InExpressionContext ctx) {
+    Token<?> left = popStack();
+    Token<?> right = popStack();
+    tokenStack.push(new Token<>(handleIn(left, right), Boolean.class));
   }
 
 
   @Override
+  public void exitNInExpression(PredicateParser.NInExpressionContext ctx) {
+    Token<?> left = popStack();
+    Token<?> right = popStack();
+    tokenStack.push(new Token<>(!handleIn(left, right), Boolean.class));
+  }
+
+  @Override
   public void exitLogicalFunc(PredicateParser.LogicalFuncContext ctx) {
     String funcName = ctx.getChild(0).getText();
-    Predicate<List<String>> func;
+    Predicate<List<Object>> func;
     try {
       func = LogicalFunctions.valueOf(funcName);
     }
@@ -222,60 +257,69 @@ class QueryCompiler extends PredicateBaseListener {
               + Joiner.on(',').join(LogicalFunctions.values())
       );
     }
-    PredicateToken<?> left = popStack();
-    List<String> argList = null;
-    if(left.getUnderlyingType().equals(List.class)) {
-      argList = (List<String>) left.getValue();
+    Token<?> left = popStack();
+    List<Object> argList = null;
+    if(left.getValue() instanceof List) {
+      argList = (List<Object>) left.getValue();
     }
     else {
       throw new ParseException("Unable to process in clause because " + left.getValue() + " is not a set");
     }
     Boolean result = func.test(argList);
-    tokenStack.push(new PredicateToken<>(result, Boolean.class));
+    tokenStack.push(new Token<>(result, Boolean.class));
   }
 
+  /**
+   * {@inheritDoc}
+   * <p/>
+   * <p>The default implementation does nothing.</p>
+   *
+   * @param ctx
+   */
   @Override
-  public void exitStringFunc(PredicateParser.StringFuncContext ctx) {
+  public void exitTransformationFunc(PredicateParser.TransformationFuncContext ctx) {
     String funcName = ctx.getChild(0).getText();
-    Function<List<String>, String> func;
+    Function<List<Object>, Object> func;
     try {
-      func = StringFunctions.valueOf(funcName);
+      func = TransformationFunctions.valueOf(funcName);
     }
     catch(IllegalArgumentException iae) {
       throw new ParseException("Unable to find string function " + funcName + ".  Valid functions are "
-              + Joiner.on(',').join(StringFunctions.values())
+              + Joiner.on(',').join(TransformationFunctions.values())
       );
     }
-    PredicateToken<?> left = popStack();
-    List<String> argList = null;
+    Token<?> left = popStack();
+    List<Object> argList = null;
     if(left.getUnderlyingType().equals(List.class)) {
-      argList = (List<String>) left.getValue();
+      argList = (List<Object>) left.getValue();
     }
     else {
       throw new ParseException("Unable to process in clause because " + left.getValue() + " is not a set");
     }
-    String result = func.apply(argList);
-    tokenStack.push(new PredicateToken<>(result, String.class));
+    Object result = func.apply(argList);
+    tokenStack.push(new Token<>(result, Object.class));
   }
 
+
+
   @Override
   public void exitExistsFunc(PredicateParser.ExistsFuncContext ctx) {
     String variable = ctx.getChild(2).getText();
     boolean exists = resolver.resolve(variable) != null;
-    tokenStack.push(new PredicateToken<>(exists, Boolean.class));
+    tokenStack.push(new Token<>(exists, Boolean.class));
   }
 
   @Override
   public void exitNotFunc(PredicateParser.NotFuncContext ctx) {
-    PredicateToken<Boolean> arg = (PredicateToken<Boolean>) popStack();
-    tokenStack.push(new PredicateToken<>(!arg.getValue(), Boolean.class));
+    Token<Boolean> arg = (Token<Boolean>) popStack();
+    tokenStack.push(new Token<>(!arg.getValue(), Boolean.class));
   }
 
   public boolean getResult() throws ParseException {
     if(tokenStack.empty()) {
       throw new ParseException("Invalid predicate: Empty stack.");
     }
-    PredicateToken<?> token = popStack();
+    Token<?> token = popStack();
     if(token.getUnderlyingType().equals(Boolean.class) && tokenStack.empty()) {
       return (Boolean)token.getValue();
     }

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/StringFunctions.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/StringFunctions.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/StringFunctions.java
deleted file mode 100644
index 911063e..0000000
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/StringFunctions.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.metron.common.query;
-
-
-import com.google.common.base.Function;
-
-import javax.annotation.Nullable;
-import java.util.List;
-
-public enum StringFunctions implements Function<List<String>, String> {
-  TO_LOWER(strings -> strings.get(0)==null?null:strings.get(0).toLowerCase())
-  ,TO_UPPER(strings -> strings.get(0) == null?null:strings.get(0).toUpperCase())
-  ,TRIM(strings -> strings.get(0) == null?null:strings.get(0).trim())
-  ;
-  Function<List<String>, String> func;
-  StringFunctions(Function<List<String>, String> func) {
-    this.func = func;
-  }
-
-  @Nullable
-  @Override
-  public String apply(@Nullable List<String> input) {
-    return func.apply(input);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/VariableResolver.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/VariableResolver.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/VariableResolver.java
deleted file mode 100644
index d0a6625..0000000
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/VariableResolver.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.metron.common.query;
-
-public interface VariableResolver {
-  String resolve(String variable);
-}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateBaseListener.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateBaseListener.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateBaseListener.java
index ca7ac84..5c41d0c 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateBaseListener.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateBaseListener.java
@@ -241,6 +241,18 @@ public class PredicateBaseListener implements PredicateListener {
 	 *
 	 * <p>The default implementation does nothing.</p>
 	 */
+	@Override public void enterTransformationFunc(PredicateParser.TransformationFuncContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitTransformationFunc(PredicateParser.TransformationFuncContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
 	@Override public void enterStringLiteral(PredicateParser.StringLiteralContext ctx) { }
 	/**
 	 * {@inheritDoc}
@@ -265,13 +277,49 @@ public class PredicateBaseListener implements PredicateListener {
 	 *
 	 * <p>The default implementation does nothing.</p>
 	 */
-	@Override public void enterStringFunc(PredicateParser.StringFuncContext ctx) { }
+	@Override public void enterId_tfunc(PredicateParser.Id_tfuncContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitId_tfunc(PredicateParser.Id_tfuncContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterIntegerLiteral(PredicateParser.IntegerLiteralContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitIntegerLiteral(PredicateParser.IntegerLiteralContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterDoubleLiteral(PredicateParser.DoubleLiteralContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void exitDoubleLiteral(PredicateParser.DoubleLiteralContext ctx) { }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation does nothing.</p>
+	 */
+	@Override public void enterList(PredicateParser.ListContext ctx) { }
 	/**
 	 * {@inheritDoc}
 	 *
 	 * <p>The default implementation does nothing.</p>
 	 */
-	@Override public void exitStringFunc(PredicateParser.StringFuncContext ctx) { }
+	@Override public void exitList(PredicateParser.ListContext ctx) { }
 	/**
 	 * {@inheritDoc}
 	 *

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateLexer.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateLexer.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateLexer.java
index ebc0b00..2bcf114 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateLexer.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateLexer.java
@@ -37,26 +37,30 @@ public class PredicateLexer extends Lexer {
 	protected static final PredictionContextCache _sharedContextCache =
 		new PredictionContextCache();
 	public static final int
-		AND=1, OR=2, NOT=3, TRUE=4, FALSE=5, EQ=6, NEQ=7, COMMA=8, LBRACKET=9, 
-		RBRACKET=10, LPAREN=11, RPAREN=12, IN=13, NIN=14, EXISTS=15, IDENTIFIER=16, 
-		STRING_LITERAL=17, SEMI=18, COMMENT=19, WS=20;
+		AND=1, OR=2, NOT=3, TRUE=4, FALSE=5, EQ=6, NEQ=7, LT=8, LTE=9, GT=10, 
+		GTE=11, COMMA=12, LBRACKET=13, RBRACKET=14, LPAREN=15, RPAREN=16, IN=17, 
+		NIN=18, EXISTS=19, INT_LITERAL=20, DOUBLE_LITERAL=21, IDENTIFIER=22, STRING_LITERAL=23, 
+		SEMI=24, COMMENT=25, WS=26;
 	public static String[] modeNames = {
 		"DEFAULT_MODE"
 	};
 
 	public static final String[] ruleNames = {
-		"AND", "OR", "NOT", "TRUE", "FALSE", "EQ", "NEQ", "COMMA", "LBRACKET", 
-		"RBRACKET", "LPAREN", "RPAREN", "IN", "NIN", "EXISTS", "IDENTIFIER", "SCHAR", 
-		"STRING_LITERAL", "SEMI", "COMMENT", "WS"
+		"AND", "OR", "NOT", "TRUE", "FALSE", "EQ", "NEQ", "LT", "LTE", "GT", "GTE", 
+		"COMMA", "LBRACKET", "RBRACKET", "LPAREN", "RPAREN", "IN", "NIN", "EXISTS", 
+		"INT_LITERAL", "DOUBLE_LITERAL", "IDENTIFIER", "SCHAR", "STRING_LITERAL", 
+		"SEMI", "COMMENT", "WS"
 	};
 
 	private static final String[] _LITERAL_NAMES = {
-		null, null, null, null, null, null, "'=='", "'!='", "','", "'['", "']'", 
-		"'('", "')'", "'in'", "'not in'", "'exists'", null, null, "';'"
+		null, null, null, null, null, null, "'=='", "'!='", "'<'", "'<='", "'>'", 
+		"'>='", "','", "'['", "']'", "'('", "')'", "'in'", "'not in'", "'exists'", 
+		null, null, null, null, "';'"
 	};
 	private static final String[] _SYMBOLIC_NAMES = {
-		null, "AND", "OR", "NOT", "TRUE", "FALSE", "EQ", "NEQ", "COMMA", "LBRACKET", 
-		"RBRACKET", "LPAREN", "RPAREN", "IN", "NIN", "EXISTS", "IDENTIFIER", "STRING_LITERAL", 
+		null, "AND", "OR", "NOT", "TRUE", "FALSE", "EQ", "NEQ", "LT", "LTE", "GT", 
+		"GTE", "COMMA", "LBRACKET", "RBRACKET", "LPAREN", "RPAREN", "IN", "NIN", 
+		"EXISTS", "INT_LITERAL", "DOUBLE_LITERAL", "IDENTIFIER", "STRING_LITERAL", 
 		"SEMI", "COMMENT", "WS"
 	};
 	public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
@@ -114,59 +118,74 @@ public class PredicateLexer extends Lexer {
 	public ATN getATN() { return _ATN; }
 
 	public static final String _serializedATN =
-		"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2\26\u00af\b\1\4\2"+
+		"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2\34\u00d5\b\1\4\2"+
 		"\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4"+
 		"\13\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22"+
-		"\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\3\2\3\2\3\2\3\2\3\2\3\2"+
-		"\3\2\3\2\5\2\66\n\2\3\3\3\3\3\3\3\3\3\3\3\3\5\3>\n\3\3\4\3\4\3\4\3\4\3"+
-		"\4\3\4\5\4F\n\4\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\5\5P\n\5\3\6\3\6\3\6\3"+
-		"\6\3\6\3\6\3\6\3\6\3\6\3\6\5\6\\\n\6\3\7\3\7\3\7\3\b\3\b\3\b\3\t\3\t\3"+
-		"\n\3\n\3\13\3\13\3\f\3\f\3\r\3\r\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3"+
-		"\17\3\17\3\17\3\20\3\20\3\20\3\20\3\20\3\20\3\20\3\21\3\21\7\21\u0081"+
-		"\n\21\f\21\16\21\u0084\13\21\3\22\3\22\3\23\3\23\7\23\u008a\n\23\f\23"+
-		"\16\23\u008d\13\23\3\23\3\23\3\23\7\23\u0092\n\23\f\23\16\23\u0095\13"+
-		"\23\3\23\5\23\u0098\n\23\3\24\3\24\3\25\3\25\3\25\3\25\6\25\u00a0\n\25"+
-		"\r\25\16\25\u00a1\3\25\5\25\u00a5\n\25\3\25\3\25\3\26\6\26\u00aa\n\26"+
-		"\r\26\16\26\u00ab\3\26\3\26\3\u00a1\2\27\3\3\5\4\7\5\t\6\13\7\r\b\17\t"+
-		"\21\n\23\13\25\f\27\r\31\16\33\17\35\20\37\21!\22#\2%\23\'\24)\25+\26"+
-		"\3\2\7\5\2C\\aac|\b\2\60\60\62;C\\^^aac|\7\2\f\f\17\17$$))^^\3\3\f\f\5"+
-		"\2\13\f\16\17\"\"\u00ba\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2"+
-		"\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25"+
-		"\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2"+
-		"\2\2\2!\3\2\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\3\65\3\2"+
-		"\2\2\5=\3\2\2\2\7E\3\2\2\2\tO\3\2\2\2\13[\3\2\2\2\r]\3\2\2\2\17`\3\2\2"+
-		"\2\21c\3\2\2\2\23e\3\2\2\2\25g\3\2\2\2\27i\3\2\2\2\31k\3\2\2\2\33m\3\2"+
-		"\2\2\35p\3\2\2\2\37w\3\2\2\2!~\3\2\2\2#\u0085\3\2\2\2%\u0097\3\2\2\2\'"+
-		"\u0099\3\2\2\2)\u009b\3\2\2\2+\u00a9\3\2\2\2-.\7c\2\2./\7p\2\2/\66\7f"+
-		"\2\2\60\61\7(\2\2\61\66\7(\2\2\62\63\7C\2\2\63\64\7P\2\2\64\66\7F\2\2"+
-		"\65-\3\2\2\2\65\60\3\2\2\2\65\62\3\2\2\2\66\4\3\2\2\2\678\7q\2\28>\7t"+
-		"\2\29:\7~\2\2:>\7~\2\2;<\7Q\2\2<>\7T\2\2=\67\3\2\2\2=9\3\2\2\2=;\3\2\2"+
-		"\2>\6\3\2\2\2?@\7p\2\2@A\7q\2\2AF\7v\2\2BC\7P\2\2CD\7Q\2\2DF\7V\2\2E?"+
-		"\3\2\2\2EB\3\2\2\2F\b\3\2\2\2GH\7v\2\2HI\7t\2\2IJ\7w\2\2JP\7g\2\2KL\7"+
-		"V\2\2LM\7T\2\2MN\7W\2\2NP\7G\2\2OG\3\2\2\2OK\3\2\2\2P\n\3\2\2\2QR\7h\2"+
-		"\2RS\7c\2\2ST\7n\2\2TU\7u\2\2U\\\7g\2\2VW\7H\2\2WX\7C\2\2XY\7N\2\2YZ\7"+
-		"U\2\2Z\\\7G\2\2[Q\3\2\2\2[V\3\2\2\2\\\f\3\2\2\2]^\7?\2\2^_\7?\2\2_\16"+
-		"\3\2\2\2`a\7#\2\2ab\7?\2\2b\20\3\2\2\2cd\7.\2\2d\22\3\2\2\2ef\7]\2\2f"+
-		"\24\3\2\2\2gh\7_\2\2h\26\3\2\2\2ij\7*\2\2j\30\3\2\2\2kl\7+\2\2l\32\3\2"+
-		"\2\2mn\7k\2\2no\7p\2\2o\34\3\2\2\2pq\7p\2\2qr\7q\2\2rs\7v\2\2st\7\"\2"+
-		"\2tu\7k\2\2uv\7p\2\2v\36\3\2\2\2wx\7g\2\2xy\7z\2\2yz\7k\2\2z{\7u\2\2{"+
-		"|\7v\2\2|}\7u\2\2} \3\2\2\2~\u0082\t\2\2\2\177\u0081\t\3\2\2\u0080\177"+
-		"\3\2\2\2\u0081\u0084\3\2\2\2\u0082\u0080\3\2\2\2\u0082\u0083\3\2\2\2\u0083"+
-		"\"\3\2\2\2\u0084\u0082\3\2\2\2\u0085\u0086\n\4\2\2\u0086$\3\2\2\2\u0087"+
-		"\u008b\7$\2\2\u0088\u008a\5#\22\2\u0089\u0088\3\2\2\2\u008a\u008d\3\2"+
-		"\2\2\u008b\u0089\3\2\2\2\u008b\u008c\3\2\2\2\u008c\u008e\3\2\2\2\u008d"+
-		"\u008b\3\2\2\2\u008e\u0098\7$\2\2\u008f\u0093\7)\2\2\u0090\u0092\5#\22"+
-		"\2\u0091\u0090\3\2\2\2\u0092\u0095\3\2\2\2\u0093\u0091\3\2\2\2\u0093\u0094"+
-		"\3\2\2\2\u0094\u0096\3\2\2\2\u0095\u0093\3\2\2\2\u0096\u0098\7)\2\2\u0097"+
-		"\u0087\3\2\2\2\u0097\u008f\3\2\2\2\u0098&\3\2\2\2\u0099\u009a\7=\2\2\u009a"+
-		"(\3\2\2\2\u009b\u009c\7\61\2\2\u009c\u009d\7\61\2\2\u009d\u009f\3\2\2"+
-		"\2\u009e\u00a0\13\2\2\2\u009f\u009e\3\2\2\2\u00a0\u00a1\3\2\2\2\u00a1"+
-		"\u00a2\3\2\2\2\u00a1\u009f\3\2\2\2\u00a2\u00a4\3\2\2\2\u00a3\u00a5\t\5"+
-		"\2\2\u00a4\u00a3\3\2\2\2\u00a5\u00a6\3\2\2\2\u00a6\u00a7\b\25\2\2\u00a7"+
-		"*\3\2\2\2\u00a8\u00aa\t\6\2\2\u00a9\u00a8\3\2\2\2\u00aa\u00ab\3\2\2\2"+
-		"\u00ab\u00a9\3\2\2\2\u00ab\u00ac\3\2\2\2\u00ac\u00ad\3\2\2\2\u00ad\u00ae"+
-		"\b\26\2\2\u00ae,\3\2\2\2\17\2\65=EO[\u0082\u008b\u0093\u0097\u00a1\u00a4"+
-		"\u00ab\3\b\2\2";
+		"\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31"+
+		"\t\31\4\32\t\32\4\33\t\33\4\34\t\34\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\2\5"+
+		"\2B\n\2\3\3\3\3\3\3\3\3\3\3\3\3\5\3J\n\3\3\4\3\4\3\4\3\4\3\4\3\4\5\4R"+
+		"\n\4\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\5\5\\\n\5\3\6\3\6\3\6\3\6\3\6\3\6"+
+		"\3\6\3\6\3\6\3\6\5\6h\n\6\3\7\3\7\3\7\3\b\3\b\3\b\3\t\3\t\3\n\3\n\3\n"+
+		"\3\13\3\13\3\f\3\f\3\f\3\r\3\r\3\16\3\16\3\17\3\17\3\20\3\20\3\21\3\21"+
+		"\3\22\3\22\3\22\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24"+
+		"\3\24\3\24\3\24\3\25\6\25\u0096\n\25\r\25\16\25\u0097\3\26\6\26\u009b"+
+		"\n\26\r\26\16\26\u009c\3\26\3\26\6\26\u00a1\n\26\r\26\16\26\u00a2\3\27"+
+		"\3\27\7\27\u00a7\n\27\f\27\16\27\u00aa\13\27\3\30\3\30\3\31\3\31\7\31"+
+		"\u00b0\n\31\f\31\16\31\u00b3\13\31\3\31\3\31\3\31\7\31\u00b8\n\31\f\31"+
+		"\16\31\u00bb\13\31\3\31\5\31\u00be\n\31\3\32\3\32\3\33\3\33\3\33\3\33"+
+		"\6\33\u00c6\n\33\r\33\16\33\u00c7\3\33\5\33\u00cb\n\33\3\33\3\33\3\34"+
+		"\6\34\u00d0\n\34\r\34\16\34\u00d1\3\34\3\34\3\u00c7\2\35\3\3\5\4\7\5\t"+
+		"\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17\35\20\37\21!\22#\23"+
+		"%\24\'\25)\26+\27-\30/\2\61\31\63\32\65\33\67\34\3\2\7\5\2C\\aac|\b\2"+
+		"\60\60\62;C\\^^aac|\7\2\f\f\17\17$$))^^\3\3\f\f\5\2\13\f\16\17\"\"\u00e3"+
+		"\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2"+
+		"\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2"+
+		"\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2"+
+		"\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2\61\3\2"+
+		"\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\3A\3\2\2\2\5I\3\2\2\2\7Q\3"+
+		"\2\2\2\t[\3\2\2\2\13g\3\2\2\2\ri\3\2\2\2\17l\3\2\2\2\21o\3\2\2\2\23q\3"+
+		"\2\2\2\25t\3\2\2\2\27v\3\2\2\2\31y\3\2\2\2\33{\3\2\2\2\35}\3\2\2\2\37"+
+		"\177\3\2\2\2!\u0081\3\2\2\2#\u0083\3\2\2\2%\u0086\3\2\2\2\'\u008d\3\2"+
+		"\2\2)\u0095\3\2\2\2+\u009a\3\2\2\2-\u00a4\3\2\2\2/\u00ab\3\2\2\2\61\u00bd"+
+		"\3\2\2\2\63\u00bf\3\2\2\2\65\u00c1\3\2\2\2\67\u00cf\3\2\2\29:\7c\2\2:"+
+		";\7p\2\2;B\7f\2\2<=\7(\2\2=B\7(\2\2>?\7C\2\2?@\7P\2\2@B\7F\2\2A9\3\2\2"+
+		"\2A<\3\2\2\2A>\3\2\2\2B\4\3\2\2\2CD\7q\2\2DJ\7t\2\2EF\7~\2\2FJ\7~\2\2"+
+		"GH\7Q\2\2HJ\7T\2\2IC\3\2\2\2IE\3\2\2\2IG\3\2\2\2J\6\3\2\2\2KL\7p\2\2L"+
+		"M\7q\2\2MR\7v\2\2NO\7P\2\2OP\7Q\2\2PR\7V\2\2QK\3\2\2\2QN\3\2\2\2R\b\3"+
+		"\2\2\2ST\7v\2\2TU\7t\2\2UV\7w\2\2V\\\7g\2\2WX\7V\2\2XY\7T\2\2YZ\7W\2\2"+
+		"Z\\\7G\2\2[S\3\2\2\2[W\3\2\2\2\\\n\3\2\2\2]^\7h\2\2^_\7c\2\2_`\7n\2\2"+
+		"`a\7u\2\2ah\7g\2\2bc\7H\2\2cd\7C\2\2de\7N\2\2ef\7U\2\2fh\7G\2\2g]\3\2"+
+		"\2\2gb\3\2\2\2h\f\3\2\2\2ij\7?\2\2jk\7?\2\2k\16\3\2\2\2lm\7#\2\2mn\7?"+
+		"\2\2n\20\3\2\2\2op\7>\2\2p\22\3\2\2\2qr\7>\2\2rs\7?\2\2s\24\3\2\2\2tu"+
+		"\7@\2\2u\26\3\2\2\2vw\7@\2\2wx\7?\2\2x\30\3\2\2\2yz\7.\2\2z\32\3\2\2\2"+
+		"{|\7]\2\2|\34\3\2\2\2}~\7_\2\2~\36\3\2\2\2\177\u0080\7*\2\2\u0080 \3\2"+
+		"\2\2\u0081\u0082\7+\2\2\u0082\"\3\2\2\2\u0083\u0084\7k\2\2\u0084\u0085"+
+		"\7p\2\2\u0085$\3\2\2\2\u0086\u0087\7p\2\2\u0087\u0088\7q\2\2\u0088\u0089"+
+		"\7v\2\2\u0089\u008a\7\"\2\2\u008a\u008b\7k\2\2\u008b\u008c\7p\2\2\u008c"+
+		"&\3\2\2\2\u008d\u008e\7g\2\2\u008e\u008f\7z\2\2\u008f\u0090\7k\2\2\u0090"+
+		"\u0091\7u\2\2\u0091\u0092\7v\2\2\u0092\u0093\7u\2\2\u0093(\3\2\2\2\u0094"+
+		"\u0096\4\62;\2\u0095\u0094\3\2\2\2\u0096\u0097\3\2\2\2\u0097\u0095\3\2"+
+		"\2\2\u0097\u0098\3\2\2\2\u0098*\3\2\2\2\u0099\u009b\4\62;\2\u009a\u0099"+
+		"\3\2\2\2\u009b\u009c\3\2\2\2\u009c\u009a\3\2\2\2\u009c\u009d\3\2\2\2\u009d"+
+		"\u009e\3\2\2\2\u009e\u00a0\7\60\2\2\u009f\u00a1\4\62;\2\u00a0\u009f\3"+
+		"\2\2\2\u00a1\u00a2\3\2\2\2\u00a2\u00a0\3\2\2\2\u00a2\u00a3\3\2\2\2\u00a3"+
+		",\3\2\2\2\u00a4\u00a8\t\2\2\2\u00a5\u00a7\t\3\2\2\u00a6\u00a5\3\2\2\2"+
+		"\u00a7\u00aa\3\2\2\2\u00a8\u00a6\3\2\2\2\u00a8\u00a9\3\2\2\2\u00a9.\3"+
+		"\2\2\2\u00aa\u00a8\3\2\2\2\u00ab\u00ac\n\4\2\2\u00ac\60\3\2\2\2\u00ad"+
+		"\u00b1\7$\2\2\u00ae\u00b0\5/\30\2\u00af\u00ae\3\2\2\2\u00b0\u00b3\3\2"+
+		"\2\2\u00b1\u00af\3\2\2\2\u00b1\u00b2\3\2\2\2\u00b2\u00b4\3\2\2\2\u00b3"+
+		"\u00b1\3\2\2\2\u00b4\u00be\7$\2\2\u00b5\u00b9\7)\2\2\u00b6\u00b8\5/\30"+
+		"\2\u00b7\u00b6\3\2\2\2\u00b8\u00bb\3\2\2\2\u00b9\u00b7\3\2\2\2\u00b9\u00ba"+
+		"\3\2\2\2\u00ba\u00bc\3\2\2\2\u00bb\u00b9\3\2\2\2\u00bc\u00be\7)\2\2\u00bd"+
+		"\u00ad\3\2\2\2\u00bd\u00b5\3\2\2\2\u00be\62\3\2\2\2\u00bf\u00c0\7=\2\2"+
+		"\u00c0\64\3\2\2\2\u00c1\u00c2\7\61\2\2\u00c2\u00c3\7\61\2\2\u00c3\u00c5"+
+		"\3\2\2\2\u00c4\u00c6\13\2\2\2\u00c5\u00c4\3\2\2\2\u00c6\u00c7\3\2\2\2"+
+		"\u00c7\u00c8\3\2\2\2\u00c7\u00c5\3\2\2\2\u00c8\u00ca\3\2\2\2\u00c9\u00cb"+
+		"\t\5\2\2\u00ca\u00c9\3\2\2\2\u00cb\u00cc\3\2\2\2\u00cc\u00cd\b\33\2\2"+
+		"\u00cd\66\3\2\2\2\u00ce\u00d0\t\6\2\2\u00cf\u00ce\3\2\2\2\u00d0\u00d1"+
+		"\3\2\2\2\u00d1\u00cf\3\2\2\2\u00d1\u00d2\3\2\2\2\u00d2\u00d3\3\2\2\2\u00d3"+
+		"\u00d4\b\34\2\2\u00d48\3\2\2\2\22\2AIQ[g\u0097\u009c\u00a2\u00a8\u00b1"+
+		"\u00b9\u00bd\u00c7\u00ca\u00d1\3\b\2\2";
 	public static final ATN _ATN =
 		new ATNDeserializer().deserialize(_serializedATN.toCharArray());
 	static {

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateListener.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateListener.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateListener.java
index 6a8b669..c39c678 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateListener.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateListener.java
@@ -225,6 +225,18 @@ public interface PredicateListener extends ParseTreeListener {
 	 */
 	void exitOp_list(PredicateParser.Op_listContext ctx);
 	/**
+	 * Enter a parse tree produced by the {@code TransformationFunc}
+	 * labeled alternative in {@link PredicateParser#t_func}.
+	 * @param ctx the parse tree
+	 */
+	void enterTransformationFunc(PredicateParser.TransformationFuncContext ctx);
+	/**
+	 * Exit a parse tree produced by the {@code TransformationFunc}
+	 * labeled alternative in {@link PredicateParser#t_func}.
+	 * @param ctx the parse tree
+	 */
+	void exitTransformationFunc(PredicateParser.TransformationFuncContext ctx);
+	/**
 	 * Enter a parse tree produced by the {@code StringLiteral}
 	 * labeled alternative in {@link PredicateParser#identifier_operand}.
 	 * @param ctx the parse tree
@@ -249,17 +261,53 @@ public interface PredicateListener extends ParseTreeListener {
 	 */
 	void exitLogicalVariable(PredicateParser.LogicalVariableContext ctx);
 	/**
-	 * Enter a parse tree produced by the {@code StringFunc}
+	 * Enter a parse tree produced by the {@code id_tfunc}
+	 * labeled alternative in {@link PredicateParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void enterId_tfunc(PredicateParser.Id_tfuncContext ctx);
+	/**
+	 * Exit a parse tree produced by the {@code id_tfunc}
+	 * labeled alternative in {@link PredicateParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void exitId_tfunc(PredicateParser.Id_tfuncContext ctx);
+	/**
+	 * Enter a parse tree produced by the {@code IntegerLiteral}
+	 * labeled alternative in {@link PredicateParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void enterIntegerLiteral(PredicateParser.IntegerLiteralContext ctx);
+	/**
+	 * Exit a parse tree produced by the {@code IntegerLiteral}
+	 * labeled alternative in {@link PredicateParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void exitIntegerLiteral(PredicateParser.IntegerLiteralContext ctx);
+	/**
+	 * Enter a parse tree produced by the {@code DoubleLiteral}
+	 * labeled alternative in {@link PredicateParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void enterDoubleLiteral(PredicateParser.DoubleLiteralContext ctx);
+	/**
+	 * Exit a parse tree produced by the {@code DoubleLiteral}
+	 * labeled alternative in {@link PredicateParser#identifier_operand}.
+	 * @param ctx the parse tree
+	 */
+	void exitDoubleLiteral(PredicateParser.DoubleLiteralContext ctx);
+	/**
+	 * Enter a parse tree produced by the {@code List}
 	 * labeled alternative in {@link PredicateParser#identifier_operand}.
 	 * @param ctx the parse tree
 	 */
-	void enterStringFunc(PredicateParser.StringFuncContext ctx);
+	void enterList(PredicateParser.ListContext ctx);
 	/**
-	 * Exit a parse tree produced by the {@code StringFunc}
+	 * Exit a parse tree produced by the {@code List}
 	 * labeled alternative in {@link PredicateParser#identifier_operand}.
 	 * @param ctx the parse tree
 	 */
-	void exitStringFunc(PredicateParser.StringFuncContext ctx);
+	void exitList(PredicateParser.ListContext ctx);
 	/**
 	 * Enter a parse tree produced by the {@code IdentifierOperand}
 	 * labeled alternative in {@link PredicateParser#comparison_operand}.

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateParser.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateParser.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateParser.java
index 3586f01..1bc67a6 100644
--- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateParser.java
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/query/generated/PredicateParser.java
@@ -37,25 +37,30 @@ public class PredicateParser extends Parser {
 	protected static final PredictionContextCache _sharedContextCache =
 		new PredictionContextCache();
 	public static final int
-		AND=1, OR=2, NOT=3, TRUE=4, FALSE=5, EQ=6, NEQ=7, COMMA=8, LBRACKET=9, 
-		RBRACKET=10, LPAREN=11, RPAREN=12, IN=13, NIN=14, EXISTS=15, IDENTIFIER=16, 
-		STRING_LITERAL=17, SEMI=18, COMMENT=19, WS=20;
+		AND=1, OR=2, NOT=3, TRUE=4, FALSE=5, EQ=6, NEQ=7, LT=8, LTE=9, GT=10, 
+		GTE=11, COMMA=12, LBRACKET=13, RBRACKET=14, LPAREN=15, RPAREN=16, IN=17, 
+		NIN=18, EXISTS=19, INT_LITERAL=20, DOUBLE_LITERAL=21, IDENTIFIER=22, STRING_LITERAL=23, 
+		SEMI=24, COMMENT=25, WS=26;
 	public static final int
 		RULE_single_rule = 0, RULE_logical_expr = 1, RULE_comparison_expr = 2, 
 		RULE_logical_entity = 3, RULE_list_entity = 4, RULE_func_args = 5, RULE_op_list = 6, 
-		RULE_identifier_operand = 7, RULE_comparison_operand = 8, RULE_comp_operator = 9;
+		RULE_t_func = 7, RULE_identifier_operand = 8, RULE_comparison_operand = 9, 
+		RULE_comp_operator = 10;
 	public static final String[] ruleNames = {
 		"single_rule", "logical_expr", "comparison_expr", "logical_entity", "list_entity", 
-		"func_args", "op_list", "identifier_operand", "comparison_operand", "comp_operator"
+		"func_args", "op_list", "t_func", "identifier_operand", "comparison_operand", 
+		"comp_operator"
 	};
 
 	private static final String[] _LITERAL_NAMES = {
-		null, null, null, null, null, null, "'=='", "'!='", "','", "'['", "']'", 
-		"'('", "')'", "'in'", "'not in'", "'exists'", null, null, "';'"
+		null, null, null, null, null, null, "'=='", "'!='", "'<'", "'<='", "'>'", 
+		"'>='", "','", "'['", "']'", "'('", "')'", "'in'", "'not in'", "'exists'", 
+		null, null, null, null, "';'"
 	};
 	private static final String[] _SYMBOLIC_NAMES = {
-		null, "AND", "OR", "NOT", "TRUE", "FALSE", "EQ", "NEQ", "COMMA", "LBRACKET", 
-		"RBRACKET", "LPAREN", "RPAREN", "IN", "NIN", "EXISTS", "IDENTIFIER", "STRING_LITERAL", 
+		null, "AND", "OR", "NOT", "TRUE", "FALSE", "EQ", "NEQ", "LT", "LTE", "GT", 
+		"GTE", "COMMA", "LBRACKET", "RBRACKET", "LPAREN", "RPAREN", "IN", "NIN", 
+		"EXISTS", "INT_LITERAL", "DOUBLE_LITERAL", "IDENTIFIER", "STRING_LITERAL", 
 		"SEMI", "COMMENT", "WS"
 	};
 	public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
@@ -132,9 +137,9 @@ public class PredicateParser extends Parser {
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(20);
+			setState(22);
 			logical_expr(0);
-			setState(21);
+			setState(23);
 			match(EOF);
 			}
 		}
@@ -273,7 +278,7 @@ public class PredicateParser extends Parser {
 			int _alt;
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(35);
+			setState(37);
 			switch ( getInterpreter().adaptivePredict(_input,0,_ctx) ) {
 			case 1:
 				{
@@ -281,7 +286,7 @@ public class PredicateParser extends Parser {
 				_ctx = _localctx;
 				_prevctx = _localctx;
 
-				setState(24);
+				setState(26);
 				comparison_expr();
 				}
 				break;
@@ -290,11 +295,11 @@ public class PredicateParser extends Parser {
 				_localctx = new LogicalExpressionInParenContext(_localctx);
 				_ctx = _localctx;
 				_prevctx = _localctx;
-				setState(25);
+				setState(27);
 				match(LPAREN);
-				setState(26);
+				setState(28);
 				logical_expr(0);
-				setState(27);
+				setState(29);
 				match(RPAREN);
 				}
 				break;
@@ -303,13 +308,13 @@ public class PredicateParser extends Parser {
 				_localctx = new NotFuncContext(_localctx);
 				_ctx = _localctx;
 				_prevctx = _localctx;
-				setState(29);
+				setState(31);
 				match(NOT);
-				setState(30);
+				setState(32);
 				match(LPAREN);
-				setState(31);
+				setState(33);
 				logical_expr(0);
-				setState(32);
+				setState(34);
 				match(RPAREN);
 				}
 				break;
@@ -318,13 +323,13 @@ public class PredicateParser extends Parser {
 				_localctx = new LogicalEntityContext(_localctx);
 				_ctx = _localctx;
 				_prevctx = _localctx;
-				setState(34);
+				setState(36);
 				logical_entity();
 				}
 				break;
 			}
 			_ctx.stop = _input.LT(-1);
-			setState(45);
+			setState(47);
 			_errHandler.sync(this);
 			_alt = getInterpreter().adaptivePredict(_input,2,_ctx);
 			while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
@@ -332,17 +337,17 @@ public class PredicateParser extends Parser {
 					if ( _parseListeners!=null ) triggerExitRuleEvent();
 					_prevctx = _localctx;
 					{
-					setState(43);
+					setState(45);
 					switch ( getInterpreter().adaptivePredict(_input,1,_ctx) ) {
 					case 1:
 						{
 						_localctx = new LogicalExpressionAndContext(new Logical_exprContext(_parentctx, _parentState));
 						pushNewRecursionContext(_localctx, _startState, RULE_logical_expr);
-						setState(37);
+						setState(39);
 						if (!(precpred(_ctx, 6))) throw new FailedPredicateException(this, "precpred(_ctx, 6)");
-						setState(38);
+						setState(40);
 						match(AND);
-						setState(39);
+						setState(41);
 						logical_expr(7);
 						}
 						break;
@@ -350,18 +355,18 @@ public class PredicateParser extends Parser {
 						{
 						_localctx = new LogicalExpressionOrContext(new Logical_exprContext(_parentctx, _parentState));
 						pushNewRecursionContext(_localctx, _startState, RULE_logical_expr);
-						setState(40);
+						setState(42);
 						if (!(precpred(_ctx, 5))) throw new FailedPredicateException(this, "precpred(_ctx, 5)");
-						setState(41);
+						setState(43);
 						match(OR);
-						setState(42);
+						setState(44);
 						logical_expr(6);
 						}
 						break;
 					}
 					} 
 				}
-				setState(47);
+				setState(49);
 				_errHandler.sync(this);
 				_alt = getInterpreter().adaptivePredict(_input,2,_ctx);
 			}
@@ -406,13 +411,13 @@ public class PredicateParser extends Parser {
 		}
 	}
 	public static class InExpressionContext extends Comparison_exprContext {
-		public Identifier_operandContext identifier_operand() {
-			return getRuleContext(Identifier_operandContext.class,0);
+		public List<Identifier_operandContext> identifier_operand() {
+			return getRuleContexts(Identifier_operandContext.class);
 		}
-		public TerminalNode IN() { return getToken(PredicateParser.IN, 0); }
-		public List_entityContext list_entity() {
-			return getRuleContext(List_entityContext.class,0);
+		public Identifier_operandContext identifier_operand(int i) {
+			return getRuleContext(Identifier_operandContext.class,i);
 		}
+		public TerminalNode IN() { return getToken(PredicateParser.IN, 0); }
 		public InExpressionContext(Comparison_exprContext ctx) { copyFrom(ctx); }
 		@Override
 		public void enterRule(ParseTreeListener listener) {
@@ -444,13 +449,13 @@ public class PredicateParser extends Parser {
 		}
 	}
 	public static class NInExpressionContext extends Comparison_exprContext {
-		public Identifier_operandContext identifier_operand() {
-			return getRuleContext(Identifier_operandContext.class,0);
+		public List<Identifier_operandContext> identifier_operand() {
+			return getRuleContexts(Identifier_operandContext.class);
 		}
-		public TerminalNode NIN() { return getToken(PredicateParser.NIN, 0); }
-		public List_entityContext list_entity() {
-			return getRuleContext(List_entityContext.class,0);
+		public Identifier_operandContext identifier_operand(int i) {
+			return getRuleContext(Identifier_operandContext.class,i);
 		}
+		public TerminalNode NIN() { return getToken(PredicateParser.NIN, 0); }
 		public NInExpressionContext(Comparison_exprContext ctx) { copyFrom(ctx); }
 		@Override
 		public void enterRule(ParseTreeListener listener) {
@@ -466,17 +471,17 @@ public class PredicateParser extends Parser {
 		Comparison_exprContext _localctx = new Comparison_exprContext(_ctx, getState());
 		enterRule(_localctx, 4, RULE_comparison_expr);
 		try {
-			setState(64);
+			setState(66);
 			switch ( getInterpreter().adaptivePredict(_input,3,_ctx) ) {
 			case 1:
 				_localctx = new ComparisonExpressionWithOperatorContext(_localctx);
 				enterOuterAlt(_localctx, 1);
 				{
-				setState(48);
+				setState(50);
 				comparison_operand();
-				setState(49);
+				setState(51);
 				comp_operator();
-				setState(50);
+				setState(52);
 				comparison_operand();
 				}
 				break;
@@ -484,35 +489,35 @@ public class PredicateParser extends Parser {
 				_localctx = new InExpressionContext(_localctx);
 				enterOuterAlt(_localctx, 2);
 				{
-				setState(52);
+				setState(54);
 				identifier_operand();
-				setState(53);
+				setState(55);
 				match(IN);
-				setState(54);
-				list_entity();
+				setState(56);
+				identifier_operand();
 				}
 				break;
 			case 3:
 				_localctx = new NInExpressionContext(_localctx);
 				enterOuterAlt(_localctx, 3);
 				{
-				setState(56);
+				setState(58);
 				identifier_operand();
-				setState(57);
+				setState(59);
 				match(NIN);
-				setState(58);
-				list_entity();
+				setState(60);
+				identifier_operand();
 				}
 				break;
 			case 4:
 				_localctx = new ComparisonExpressionParensContext(_localctx);
 				enterOuterAlt(_localctx, 4);
 				{
-				setState(60);
+				setState(62);
 				match(LPAREN);
-				setState(61);
+				setState(63);
 				comparison_expr();
-				setState(62);
+				setState(64);
 				match(RPAREN);
 				}
 				break;
@@ -591,14 +596,14 @@ public class PredicateParser extends Parser {
 		enterRule(_localctx, 6, RULE_logical_entity);
 		int _la;
 		try {
-			setState(76);
+			setState(78);
 			switch (_input.LA(1)) {
 			case TRUE:
 			case FALSE:
 				_localctx = new LogicalConstContext(_localctx);
 				enterOuterAlt(_localctx, 1);
 				{
-				setState(66);
+				setState(68);
 				_la = _input.LA(1);
 				if ( !(_la==TRUE || _la==FALSE) ) {
 				_errHandler.recoverInline(this);
@@ -611,13 +616,13 @@ public class PredicateParser extends Parser {
 				_localctx = new ExistsFuncContext(_localctx);
 				enterOuterAlt(_localctx, 2);
 				{
-				setState(67);
+				setState(69);
 				match(EXISTS);
-				setState(68);
+				setState(70);
 				match(LPAREN);
-				setState(69);
+				setState(71);
 				match(IDENTIFIER);
-				setState(70);
+				setState(72);
 				match(RPAREN);
 				}
 				break;
@@ -625,13 +630,13 @@ public class PredicateParser extends Parser {
 				_localctx = new LogicalFuncContext(_localctx);
 				enterOuterAlt(_localctx, 3);
 				{
-				setState(71);
+				setState(73);
 				match(IDENTIFIER);
-				setState(72);
+				setState(74);
 				match(LPAREN);
-				setState(73);
+				setState(75);
 				func_args();
-				setState(74);
+				setState(76);
 				match(RPAREN);
 				}
 				break;
@@ -676,11 +681,11 @@ public class PredicateParser extends Parser {
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(78);
+			setState(80);
 			match(LBRACKET);
-			setState(79);
+			setState(81);
 			op_list(0);
-			setState(80);
+			setState(82);
 			match(RBRACKET);
 			}
 		}
@@ -719,7 +724,7 @@ public class PredicateParser extends Parser {
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(82);
+			setState(84);
 			op_list(0);
 			}
 		}
@@ -772,11 +777,11 @@ public class PredicateParser extends Parser {
 			enterOuterAlt(_localctx, 1);
 			{
 			{
-			setState(85);
+			setState(87);
 			identifier_operand();
 			}
 			_ctx.stop = _input.LT(-1);
-			setState(92);
+			setState(94);
 			_errHandler.sync(this);
 			_alt = getInterpreter().adaptivePredict(_input,5,_ctx);
 			while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
@@ -787,16 +792,16 @@ public class PredicateParser extends Parser {
 					{
 					_localctx = new Op_listContext(_parentctx, _parentState);
 					pushNewRecursionContext(_localctx, _startState, RULE_op_list);
-					setState(87);
+					setState(89);
 					if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)");
-					setState(88);
+					setState(90);
 					match(COMMA);
-					setState(89);
+					setState(91);
 					identifier_operand();
 					}
 					} 
 				}
-				setState(94);
+				setState(96);
 				_errHandler.sync(this);
 				_alt = getInterpreter().adaptivePredict(_input,5,_ctx);
 			}
@@ -813,6 +818,63 @@ public class PredicateParser extends Parser {
 		return _localctx;
 	}
 
+	public static class T_funcContext extends ParserRuleContext {
+		public T_funcContext(ParserRuleContext parent, int invokingState) {
+			super(parent, invokingState);
+		}
+		@Override public int getRuleIndex() { return RULE_t_func; }
+	 
+		public T_funcContext() { }
+		public void copyFrom(T_funcContext ctx) {
+			super.copyFrom(ctx);
+		}
+	}
+	public static class TransformationFuncContext extends T_funcContext {
+		public TerminalNode IDENTIFIER() { return getToken(PredicateParser.IDENTIFIER, 0); }
+		public TerminalNode LPAREN() { return getToken(PredicateParser.LPAREN, 0); }
+		public Func_argsContext func_args() {
+			return getRuleContext(Func_argsContext.class,0);
+		}
+		public TerminalNode RPAREN() { return getToken(PredicateParser.RPAREN, 0); }
+		public TransformationFuncContext(T_funcContext ctx) { copyFrom(ctx); }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof PredicateListener ) ((PredicateListener)listener).enterTransformationFunc(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof PredicateListener ) ((PredicateListener)listener).exitTransformationFunc(this);
+		}
+	}
+
+	public final T_funcContext t_func() throws RecognitionException {
+		T_funcContext _localctx = new T_funcContext(_ctx, getState());
+		enterRule(_localctx, 14, RULE_t_func);
+		try {
+			_localctx = new TransformationFuncContext(_localctx);
+			enterOuterAlt(_localctx, 1);
+			{
+			setState(97);
+			match(IDENTIFIER);
+			setState(98);
+			match(LPAREN);
+			setState(99);
+			func_args();
+			setState(100);
+			match(RPAREN);
+			}
+		}
+		catch (RecognitionException re) {
+			_localctx.exception = re;
+			_errHandler.reportError(this, re);
+			_errHandler.recover(this, re);
+		}
+		finally {
+			exitRule();
+		}
+		return _localctx;
+	}
+
 	public static class Identifier_operandContext extends ParserRuleContext {
 		public Identifier_operandContext(ParserRuleContext parent, int invokingState) {
 			super(parent, invokingState);
@@ -848,35 +910,70 @@ public class PredicateParser extends Parser {
 			if ( listener instanceof PredicateListener ) ((PredicateListener)listener).exitStringLiteral(this);
 		}
 	}
-	public static class StringFuncContext extends Identifier_operandContext {
-		public TerminalNode IDENTIFIER() { return getToken(PredicateParser.IDENTIFIER, 0); }
-		public TerminalNode LPAREN() { return getToken(PredicateParser.LPAREN, 0); }
-		public Func_argsContext func_args() {
-			return getRuleContext(Func_argsContext.class,0);
+	public static class ListContext extends Identifier_operandContext {
+		public List_entityContext list_entity() {
+			return getRuleContext(List_entityContext.class,0);
 		}
-		public TerminalNode RPAREN() { return getToken(PredicateParser.RPAREN, 0); }
-		public StringFuncContext(Identifier_operandContext ctx) { copyFrom(ctx); }
+		public ListContext(Identifier_operandContext ctx) { copyFrom(ctx); }
 		@Override
 		public void enterRule(ParseTreeListener listener) {
-			if ( listener instanceof PredicateListener ) ((PredicateListener)listener).enterStringFunc(this);
+			if ( listener instanceof PredicateListener ) ((PredicateListener)listener).enterList(this);
 		}
 		@Override
 		public void exitRule(ParseTreeListener listener) {
-			if ( listener instanceof PredicateListener ) ((PredicateListener)listener).exitStringFunc(this);
+			if ( listener instanceof PredicateListener ) ((PredicateListener)listener).exitList(this);
+		}
+	}
+	public static class DoubleLiteralContext extends Identifier_operandContext {
+		public TerminalNode DOUBLE_LITERAL() { return getToken(PredicateParser.DOUBLE_LITERAL, 0); }
+		public DoubleLiteralContext(Identifier_operandContext ctx) { copyFrom(ctx); }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof PredicateListener ) ((PredicateListener)listener).enterDoubleLiteral(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof PredicateListener ) ((PredicateListener)listener).exitDoubleLiteral(this);
+		}
+	}
+	public static class Id_tfuncContext extends Identifier_operandContext {
+		public T_funcContext t_func() {
+			return getRuleContext(T_funcContext.class,0);
+		}
+		public Id_tfuncContext(Identifier_operandContext ctx) { copyFrom(ctx); }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof PredicateListener ) ((PredicateListener)listener).enterId_tfunc(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof PredicateListener ) ((PredicateListener)listener).exitId_tfunc(this);
+		}
+	}
+	public static class IntegerLiteralContext extends Identifier_operandContext {
+		public TerminalNode INT_LITERAL() { return getToken(PredicateParser.INT_LITERAL, 0); }
+		public IntegerLiteralContext(Identifier_operandContext ctx) { copyFrom(ctx); }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof PredicateListener ) ((PredicateListener)listener).enterIntegerLiteral(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof PredicateListener ) ((PredicateListener)listener).exitIntegerLiteral(this);
 		}
 	}
 
 	public final Identifier_operandContext identifier_operand() throws RecognitionException {
 		Identifier_operandContext _localctx = new Identifier_operandContext(_ctx, getState());
-		enterRule(_localctx, 14, RULE_identifier_operand);
+		enterRule(_localctx, 16, RULE_identifier_operand);
 		try {
-			setState(102);
+			setState(108);
 			switch ( getInterpreter().adaptivePredict(_input,6,_ctx) ) {
 			case 1:
 				_localctx = new StringLiteralContext(_localctx);
 				enterOuterAlt(_localctx, 1);
 				{
-				setState(95);
+				setState(102);
 				match(STRING_LITERAL);
 				}
 				break;
@@ -884,22 +981,40 @@ public class PredicateParser extends Parser {
 				_localctx = new LogicalVariableContext(_localctx);
 				enterOuterAlt(_localctx, 2);
 				{
-				setState(96);
+				setState(103);
 				match(IDENTIFIER);
 				}
 				break;
 			case 3:
-				_localctx = new StringFuncContext(_localctx);
+				_localctx = new Id_tfuncContext(_localctx);
 				enterOuterAlt(_localctx, 3);
 				{
-				setState(97);
-				match(IDENTIFIER);
-				setState(98);
-				match(LPAREN);
-				setState(99);
-				func_args();
-				setState(100);
-				match(RPAREN);
+				setState(104);
+				t_func();
+				}
+				break;
+			case 4:
+				_localctx = new IntegerLiteralContext(_localctx);
+				enterOuterAlt(_localctx, 4);
+				{
+				setState(105);
+				match(INT_LITERAL);
+				}
+				break;
+			case 5:
+				_localctx = new DoubleLiteralContext(_localctx);
+				enterOuterAlt(_localctx, 5);
+				{
+				setState(106);
+				match(DOUBLE_LITERAL);
+				}
+				break;
+			case 6:
+				_localctx = new ListContext(_localctx);
+				enterOuterAlt(_localctx, 6);
+				{
+				setState(107);
+				list_entity();
 				}
 				break;
 			}
@@ -957,15 +1072,15 @@ public class PredicateParser extends Parser {
 
 	public final Comparison_operandContext comparison_operand() throws RecognitionException {
 		Comparison_operandContext _localctx = new Comparison_operandContext(_ctx, getState());
-		enterRule(_localctx, 16, RULE_comparison_operand);
+		enterRule(_localctx, 18, RULE_comparison_operand);
 		try {
-			setState(106);
+			setState(112);
 			switch ( getInterpreter().adaptivePredict(_input,7,_ctx) ) {
 			case 1:
 				_localctx = new IdentifierOperandContext(_localctx);
 				enterOuterAlt(_localctx, 1);
 				{
-				setState(104);
+				setState(110);
 				identifier_operand();
 				}
 				break;
@@ -973,7 +1088,7 @@ public class PredicateParser extends Parser {
 				_localctx = new LogicalConstComparisonContext(_localctx);
 				enterOuterAlt(_localctx, 2);
 				{
-				setState(105);
+				setState(111);
 				logical_entity();
 				}
 				break;
@@ -1004,6 +1119,10 @@ public class PredicateParser extends Parser {
 	public static class ComparisonOpContext extends Comp_operatorContext {
 		public TerminalNode EQ() { return getToken(PredicateParser.EQ, 0); }
 		public TerminalNode NEQ() { return getToken(PredicateParser.NEQ, 0); }
+		public TerminalNode LT() { return getToken(PredicateParser.LT, 0); }
+		public TerminalNode LTE() { return getToken(PredicateParser.LTE, 0); }
+		public TerminalNode GT() { return getToken(PredicateParser.GT, 0); }
+		public TerminalNode GTE() { return getToken(PredicateParser.GTE, 0); }
 		public ComparisonOpContext(Comp_operatorContext ctx) { copyFrom(ctx); }
 		@Override
 		public void enterRule(ParseTreeListener listener) {
@@ -1017,15 +1136,15 @@ public class PredicateParser extends Parser {
 
 	public final Comp_operatorContext comp_operator() throws RecognitionException {
 		Comp_operatorContext _localctx = new Comp_operatorContext(_ctx, getState());
-		enterRule(_localctx, 18, RULE_comp_operator);
+		enterRule(_localctx, 20, RULE_comp_operator);
 		int _la;
 		try {
 			_localctx = new ComparisonOpContext(_localctx);
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(108);
+			setState(114);
 			_la = _input.LA(1);
-			if ( !(_la==EQ || _la==NEQ) ) {
+			if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << EQ) | (1L << NEQ) | (1L << LT) | (1L << LTE) | (1L << GT) | (1L << GTE))) != 0)) ) {
 			_errHandler.recoverInline(this);
 			} else {
 				consume();
@@ -1070,33 +1189,35 @@ public class PredicateParser extends Parser {
 	}
 
 	public static final String _serializedATN =
-		"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3\26q\4\2\t\2\4\3\t"+
-		"\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\3"+
-		"\2\3\2\3\2\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\5\3&\n\3\3"+
-		"\3\3\3\3\3\3\3\3\3\3\3\7\3.\n\3\f\3\16\3\61\13\3\3\4\3\4\3\4\3\4\3\4\3"+
-		"\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\5\4C\n\4\3\5\3\5\3\5\3\5\3"+
-		"\5\3\5\3\5\3\5\3\5\3\5\5\5O\n\5\3\6\3\6\3\6\3\6\3\7\3\7\3\b\3\b\3\b\3"+
-		"\b\3\b\3\b\7\b]\n\b\f\b\16\b`\13\b\3\t\3\t\3\t\3\t\3\t\3\t\3\t\5\ti\n"+
-		"\t\3\n\3\n\5\nm\n\n\3\13\3\13\3\13\2\4\4\16\f\2\4\6\b\n\f\16\20\22\24"+
-		"\2\4\3\2\6\7\3\2\b\tt\2\26\3\2\2\2\4%\3\2\2\2\6B\3\2\2\2\bN\3\2\2\2\n"+
-		"P\3\2\2\2\fT\3\2\2\2\16V\3\2\2\2\20h\3\2\2\2\22l\3\2\2\2\24n\3\2\2\2\26"+
-		"\27\5\4\3\2\27\30\7\2\2\3\30\3\3\2\2\2\31\32\b\3\1\2\32&\5\6\4\2\33\34"+
-		"\7\r\2\2\34\35\5\4\3\2\35\36\7\16\2\2\36&\3\2\2\2\37 \7\5\2\2 !\7\r\2"+
-		"\2!\"\5\4\3\2\"#\7\16\2\2#&\3\2\2\2$&\5\b\5\2%\31\3\2\2\2%\33\3\2\2\2"+
-		"%\37\3\2\2\2%$\3\2\2\2&/\3\2\2\2\'(\f\b\2\2()\7\3\2\2).\5\4\3\t*+\f\7"+
-		"\2\2+,\7\4\2\2,.\5\4\3\b-\'\3\2\2\2-*\3\2\2\2.\61\3\2\2\2/-\3\2\2\2/\60"+
-		"\3\2\2\2\60\5\3\2\2\2\61/\3\2\2\2\62\63\5\22\n\2\63\64\5\24\13\2\64\65"+
-		"\5\22\n\2\65C\3\2\2\2\66\67\5\20\t\2\678\7\17\2\289\5\n\6\29C\3\2\2\2"+
-		":;\5\20\t\2;<\7\20\2\2<=\5\n\6\2=C\3\2\2\2>?\7\r\2\2?@\5\6\4\2@A\7\16"+
-		"\2\2AC\3\2\2\2B\62\3\2\2\2B\66\3\2\2\2B:\3\2\2\2B>\3\2\2\2C\7\3\2\2\2"+
-		"DO\t\2\2\2EF\7\21\2\2FG\7\r\2\2GH\7\22\2\2HO\7\16\2\2IJ\7\22\2\2JK\7\r"+
-		"\2\2KL\5\f\7\2LM\7\16\2\2MO\3\2\2\2ND\3\2\2\2NE\3\2\2\2NI\3\2\2\2O\t\3"+
-		"\2\2\2PQ\7\13\2\2QR\5\16\b\2RS\7\f\2\2S\13\3\2\2\2TU\5\16\b\2U\r\3\2\2"+
-		"\2VW\b\b\1\2WX\5\20\t\2X^\3\2\2\2YZ\f\3\2\2Z[\7\n\2\2[]\5\20\t\2\\Y\3"+
-		"\2\2\2]`\3\2\2\2^\\\3\2\2\2^_\3\2\2\2_\17\3\2\2\2`^\3\2\2\2ai\7\23\2\2"+
-		"bi\7\22\2\2cd\7\22\2\2de\7\r\2\2ef\5\f\7\2fg\7\16\2\2gi\3\2\2\2ha\3\2"+
-		"\2\2hb\3\2\2\2hc\3\2\2\2i\21\3\2\2\2jm\5\20\t\2km\5\b\5\2lj\3\2\2\2lk"+
-		"\3\2\2\2m\23\3\2\2\2no\t\3\2\2o\25\3\2\2\2\n%-/BN^hl";
+		"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3\34w\4\2\t\2\4\3\t"+
+		"\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4"+
+		"\f\t\f\3\2\3\2\3\2\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\5\3"+
+		"(\n\3\3\3\3\3\3\3\3\3\3\3\3\3\7\3\60\n\3\f\3\16\3\63\13\3\3\4\3\4\3\4"+
+		"\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\5\4E\n\4\3\5\3\5"+
+		"\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\5\5Q\n\5\3\6\3\6\3\6\3\6\3\7\3\7\3\b"+
+		"\3\b\3\b\3\b\3\b\3\b\7\b_\n\b\f\b\16\bb\13\b\3\t\3\t\3\t\3\t\3\t\3\n\3"+
+		"\n\3\n\3\n\3\n\3\n\5\no\n\n\3\13\3\13\5\13s\n\13\3\f\3\f\3\f\2\4\4\16"+
+		"\r\2\4\6\b\n\f\16\20\22\24\26\2\4\3\2\6\7\3\2\b\r|\2\30\3\2\2\2\4\'\3"+
+		"\2\2\2\6D\3\2\2\2\bP\3\2\2\2\nR\3\2\2\2\fV\3\2\2\2\16X\3\2\2\2\20c\3\2"+
+		"\2\2\22n\3\2\2\2\24r\3\2\2\2\26t\3\2\2\2\30\31\5\4\3\2\31\32\7\2\2\3\32"+
+		"\3\3\2\2\2\33\34\b\3\1\2\34(\5\6\4\2\35\36\7\21\2\2\36\37\5\4\3\2\37 "+
+		"\7\22\2\2 (\3\2\2\2!\"\7\5\2\2\"#\7\21\2\2#$\5\4\3\2$%\7\22\2\2%(\3\2"+
+		"\2\2&(\5\b\5\2\'\33\3\2\2\2\'\35\3\2\2\2\'!\3\2\2\2\'&\3\2\2\2(\61\3\2"+
+		"\2\2)*\f\b\2\2*+\7\3\2\2+\60\5\4\3\t,-\f\7\2\2-.\7\4\2\2.\60\5\4\3\b/"+
+		")\3\2\2\2/,\3\2\2\2\60\63\3\2\2\2\61/\3\2\2\2\61\62\3\2\2\2\62\5\3\2\2"+
+		"\2\63\61\3\2\2\2\64\65\5\24\13\2\65\66\5\26\f\2\66\67\5\24\13\2\67E\3"+
+		"\2\2\289\5\22\n\29:\7\23\2\2:;\5\22\n\2;E\3\2\2\2<=\5\22\n\2=>\7\24\2"+
+		"\2>?\5\22\n\2?E\3\2\2\2@A\7\21\2\2AB\5\6\4\2BC\7\22\2\2CE\3\2\2\2D\64"+
+		"\3\2\2\2D8\3\2\2\2D<\3\2\2\2D@\3\2\2\2E\7\3\2\2\2FQ\t\2\2\2GH\7\25\2\2"+
+		"HI\7\21\2\2IJ\7\30\2\2JQ\7\22\2\2KL\7\30\2\2LM\7\21\2\2MN\5\f\7\2NO\7"+
+		"\22\2\2OQ\3\2\2\2PF\3\2\2\2PG\3\2\2\2PK\3\2\2\2Q\t\3\2\2\2RS\7\17\2\2"+
+		"ST\5\16\b\2TU\7\20\2\2U\13\3\2\2\2VW\5\16\b\2W\r\3\2\2\2XY\b\b\1\2YZ\5"+
+		"\22\n\2Z`\3\2\2\2[\\\f\3\2\2\\]\7\16\2\2]_\5\22\n\2^[\3\2\2\2_b\3\2\2"+
+		"\2`^\3\2\2\2`a\3\2\2\2a\17\3\2\2\2b`\3\2\2\2cd\7\30\2\2de\7\21\2\2ef\5"+
+		"\f\7\2fg\7\22\2\2g\21\3\2\2\2ho\7\31\2\2io\7\30\2\2jo\5\20\t\2ko\7\26"+
+		"\2\2lo\7\27\2\2mo\5\n\6\2nh\3\2\2\2ni\3\2\2\2nj\3\2\2\2nk\3\2\2\2nl\3"+
+		"\2\2\2nm\3\2\2\2o\23\3\2\2\2ps\5\22\n\2qs\5\b\5\2rp\3\2\2\2rq\3\2\2\2"+
+		"s\25\3\2\2\2tu\t\3\2\2u\27\3\2\2\2\n\'/\61DP`nr";
 	public static final ATN _ATN =
 		new ATNDeserializer().deserialize(_serializedATN.toCharArray());
 	static {

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/TransformationCompiler.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/TransformationCompiler.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/TransformationCompiler.java
new file mode 100644
index 0000000..2d9f0bd
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/TransformationCompiler.java
@@ -0,0 +1,160 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common.transformation;
+
+import com.google.common.base.Joiner;
+import org.apache.metron.common.dsl.Token;
+import org.apache.metron.common.dsl.TransformationFunctions;
+import org.apache.metron.common.dsl.FunctionMarker;
+import org.apache.metron.common.dsl.ParseException;
+import org.apache.metron.common.dsl.VariableResolver;
+import org.apache.metron.common.transformation.generated.TransformationBaseListener;
+import org.apache.metron.common.transformation.generated.TransformationParser;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Stack;
+import java.util.function.Function;
+
+public class TransformationCompiler extends TransformationBaseListener {
+  private VariableResolver resolver = null;
+  private Stack<Token> tokenStack = new Stack<>();
+  public TransformationCompiler(VariableResolver resolver) {
+    this.resolver = resolver;
+  }
+
+  @Override
+  public void enterTransformation(TransformationParser.TransformationContext ctx) {
+    tokenStack.clear();
+  }
+
+
+  @Override
+  public void exitVariable(TransformationParser.VariableContext ctx) {
+    tokenStack.push(new Token<>(resolver.resolve(ctx.getText()), Object.class));
+  }
+
+  @Override
+  public void exitStringLiteral(TransformationParser.StringLiteralContext ctx) {
+    tokenStack.push(new Token<>(ctx.getText().substring(1, ctx.getText().length() - 1), String.class));
+  }
+
+
+  @Override
+  public void exitIntegerLiteral(TransformationParser.IntegerLiteralContext ctx) {
+    tokenStack.push(new Token<>(Integer.parseInt(ctx.getText()), Integer.class));
+  }
+
+
+  @Override
+  public void exitDoubleLiteral(TransformationParser.DoubleLiteralContext ctx) {
+    tokenStack.push(new Token<>(Double.parseDouble(ctx.getText()), Double.class));
+  }
+
+
+  @Override
+  public void exitTransformationFunc(TransformationParser.TransformationFuncContext ctx) {
+    String funcName = ctx.getChild(0).getText();
+    Function<List<Object>, Object> func;
+    try {
+      func = TransformationFunctions.valueOf(funcName);
+    }
+    catch(IllegalArgumentException iae) {
+      throw new ParseException("Unable to find string function " + funcName + ".  Valid functions are "
+              + Joiner.on(',').join(TransformationFunctions.values())
+      );
+    }
+    Token<?> left = popStack();
+    List<Object> argList = null;
+    if(left.getUnderlyingType().equals(List.class)) {
+      argList = (List<Object>) left.getValue();
+    }
+    else {
+      throw new ParseException("Unable to process in clause because " + left.getValue() + " is not a set");
+    }
+    Object result = func.apply(argList);
+    tokenStack.push(new Token<>(result, Object.class));
+  }
+
+
+  @Override
+  public void enterFunc_args(TransformationParser.Func_argsContext ctx) {
+    tokenStack.push(new Token<>(new FunctionMarker(), FunctionMarker.class));
+  }
+
+
+  @Override
+  public void exitFunc_args(TransformationParser.Func_argsContext ctx) {
+    LinkedList<Object> args = new LinkedList<>();
+    while(true) {
+      Token<?> token = popStack();
+      if(token.getUnderlyingType().equals(FunctionMarker.class)) {
+        break;
+      }
+      else {
+        args.addFirst(token.getValue());
+      }
+    }
+    tokenStack.push(new Token<>(args, List.class));
+  }
+
+
+  @Override
+  public void exitList_entity(TransformationParser.List_entityContext ctx) {
+    LinkedList<Object> args = new LinkedList<>();
+    while(true) {
+      Token<?> token = popStack();
+      if(token.getUnderlyingType().equals(FunctionMarker.class)) {
+        break;
+      }
+      else {
+        args.addFirst(token.getValue());
+      }
+    }
+    tokenStack.push(new Token<>(args, List.class));
+  }
+
+  @Override
+  public void enterList_entity(TransformationParser.List_entityContext ctx) {
+    tokenStack.push(new Token<>(new FunctionMarker(), FunctionMarker.class));
+  }
+
+  public Token<?> popStack() {
+    if(tokenStack.empty()) {
+      throw new ParseException("Unable to pop an empty stack");
+    }
+    return tokenStack.pop();
+  }
+
+  public Object getResult() throws ParseException {
+    if(tokenStack.empty()) {
+      throw new ParseException("Invalid predicate: Empty stack.");
+    }
+    Token<?> token = popStack();
+    if(tokenStack.empty()) {
+      return token.getValue();
+    }
+    if(tokenStack.empty()) {
+      throw new ParseException("Invalid parse, stack not empty: " + Joiner.on(',').join(tokenStack));
+    }
+    else {
+      throw new ParseException("Invalid parse, found " + token);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/TransformationProcessor.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/TransformationProcessor.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/TransformationProcessor.java
new file mode 100644
index 0000000..83082c0
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/TransformationProcessor.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.common.transformation;
+
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.TokenStream;
+import org.apache.metron.common.dsl.ErrorListener;
+import org.apache.metron.common.dsl.ParseException;
+import org.apache.metron.common.dsl.VariableResolver;
+import org.apache.metron.common.transformation.generated.TransformationLexer;
+import org.apache.metron.common.transformation.generated.TransformationParser;
+
+import static org.apache.commons.lang3.StringUtils.isEmpty;
+
+public class TransformationProcessor {
+
+  public Object parse(String rule, VariableResolver resolver) {
+    if (rule == null || isEmpty(rule.trim())) {
+      return null;
+    }
+    ANTLRInputStream input = new ANTLRInputStream(rule);
+    TransformationLexer lexer = new TransformationLexer(input);
+    lexer.removeErrorListeners();
+    lexer.addErrorListener(new ErrorListener());
+    TokenStream tokens = new CommonTokenStream(lexer);
+    TransformationParser parser = new TransformationParser(tokens);
+
+    TransformationCompiler treeBuilder = new TransformationCompiler(resolver);
+    parser.addParseListener(treeBuilder);
+    parser.removeErrorListeners();
+    parser.addErrorListener(new ErrorListener());
+    parser.transformation();
+    return treeBuilder.getResult();
+  }
+
+  public boolean validate(String rule) throws ParseException {
+    return validate(rule, true);
+  }
+  public boolean validate(String rule, boolean throwException) throws ParseException {
+    try {
+      parse(rule, x -> null);
+      return true;
+    }
+    catch(Throwable t) {
+      if(throwException) {
+        throw new ParseException("Unable to parse " + rule + ": " + t.getMessage(), t);
+      }
+      else {
+        return false;
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bdbf33a9/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/PredicateLexer.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/PredicateLexer.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/PredicateLexer.java
new file mode 100644
index 0000000..321cbea
--- /dev/null
+++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/transformation/generated/PredicateLexer.java
@@ -0,0 +1,146 @@
+// Generated from org/apache/metron/common/transformation/generated/Transformation.g4 by ANTLR 4.5
+package org.apache.metron.common.transformation.generated;
+
+//CHECKSTYLE:OFF
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.antlr.v4.runtime.Lexer;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenStream;
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.atn.*;
+import org.antlr.v4.runtime.dfa.DFA;
+import org.antlr.v4.runtime.misc.*;
+
+@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
+public class PredicateLexer extends Lexer {
+	static { RuntimeMetaData.checkVersion("4.5", RuntimeMetaData.VERSION); }
+
+	protected static final DFA[] _decisionToDFA;
+	protected static final PredictionContextCache _sharedContextCache =
+		new PredictionContextCache();
+	public static final int
+		COMMA=1, LPAREN=2, RPAREN=3, INT_LITERAL=4, DOUBLE_LITERAL=5, IDENTIFIER=6, 
+		STRING_LITERAL=7, COMMENT=8, WS=9;
+	public static String[] modeNames = {
+		"DEFAULT_MODE"
+	};
+
+	public static final String[] ruleNames = {
+		"COMMA", "LPAREN", "RPAREN", "INT_LITERAL", "DOUBLE_LITERAL", "IDENTIFIER", 
+		"SCHAR", "STRING_LITERAL", "COMMENT", "WS"
+	};
+
+	private static final String[] _LITERAL_NAMES = {
+		null, "','", "'('", "')'"
+	};
+	private static final String[] _SYMBOLIC_NAMES = {
+		null, "COMMA", "LPAREN", "RPAREN", "INT_LITERAL", "DOUBLE_LITERAL", "IDENTIFIER", 
+		"STRING_LITERAL", "COMMENT", "WS"
+	};
+	public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
+
+	/**
+	 * @deprecated Use {@link #VOCABULARY} instead.
+	 */
+	@Deprecated
+	public static final String[] tokenNames;
+	static {
+		tokenNames = new String[_SYMBOLIC_NAMES.length];
+		for (int i = 0; i < tokenNames.length; i++) {
+			tokenNames[i] = VOCABULARY.getLiteralName(i);
+			if (tokenNames[i] == null) {
+				tokenNames[i] = VOCABULARY.getSymbolicName(i);
+			}
+
+			if (tokenNames[i] == null) {
+				tokenNames[i] = "<INVALID>";
+			}
+		}
+	}
+
+	@Override
+	@Deprecated
+	public String[] getTokenNames() {
+		return tokenNames;
+	}
+
+	@Override
+
+	public Vocabulary getVocabulary() {
+		return VOCABULARY;
+	}
+
+
+	public PredicateLexer(CharStream input) {
+		super(input);
+		_interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
+	}
+
+	@Override
+	public String getGrammarFileName() { return "Transformation.g4"; }
+
+	@Override
+	public String[] getRuleNames() { return ruleNames; }
+
+	@Override
+	public String getSerializedATN() { return _serializedATN; }
+
+	@Override
+	public String[] getModeNames() { return modeNames; }
+
+	@Override
+	public ATN getATN() { return _ATN; }
+
+	public static final String _serializedATN =
+		"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2\13\\\b\1\4\2\t\2"+
+		"\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+
+		"\t\13\3\2\3\2\3\3\3\3\3\4\3\4\3\5\6\5\37\n\5\r\5\16\5 \3\6\6\6$\n\6\r"+
+		"\6\16\6%\3\6\3\6\6\6*\n\6\r\6\16\6+\3\7\3\7\7\7\60\n\7\f\7\16\7\63\13"+
+		"\7\3\b\3\b\3\t\3\t\7\t9\n\t\f\t\16\t<\13\t\3\t\3\t\3\t\7\tA\n\t\f\t\16"+
+		"\tD\13\t\3\t\5\tG\n\t\3\n\3\n\3\n\3\n\6\nM\n\n\r\n\16\nN\3\n\5\nR\n\n"+
+		"\3\n\3\n\3\13\6\13W\n\13\r\13\16\13X\3\13\3\13\3N\2\f\3\3\5\4\7\5\t\6"+
+		"\13\7\r\b\17\2\21\t\23\n\25\13\3\2\7\5\2C\\aac|\b\2\60\60\62;C\\^^aac"+
+		"|\7\2\f\f\17\17$$))^^\3\3\f\f\5\2\13\f\16\17\"\"c\2\3\3\2\2\2\2\5\3\2"+
+		"\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\21\3\2\2\2\2\23"+
+		"\3\2\2\2\2\25\3\2\2\2\3\27\3\2\2\2\5\31\3\2\2\2\7\33\3\2\2\2\t\36\3\2"+
+		"\2\2\13#\3\2\2\2\r-\3\2\2\2\17\64\3\2\2\2\21F\3\2\2\2\23H\3\2\2\2\25V"+
+		"\3\2\2\2\27\30\7.\2\2\30\4\3\2\2\2\31\32\7*\2\2\32\6\3\2\2\2\33\34\7+"+
+		"\2\2\34\b\3\2\2\2\35\37\4\62;\2\36\35\3\2\2\2\37 \3\2\2\2 \36\3\2\2\2"+
+		" !\3\2\2\2!\n\3\2\2\2\"$\4\62;\2#\"\3\2\2\2$%\3\2\2\2%#\3\2\2\2%&\3\2"+
+		"\2\2&\'\3\2\2\2\')\7\60\2\2(*\4\62;\2)(\3\2\2\2*+\3\2\2\2+)\3\2\2\2+,"+
+		"\3\2\2\2,\f\3\2\2\2-\61\t\2\2\2.\60\t\3\2\2/.\3\2\2\2\60\63\3\2\2\2\61"+
+		"/\3\2\2\2\61\62\3\2\2\2\62\16\3\2\2\2\63\61\3\2\2\2\64\65\n\4\2\2\65\20"+
+		"\3\2\2\2\66:\7$\2\2\679\5\17\b\28\67\3\2\2\29<\3\2\2\2:8\3\2\2\2:;\3\2"+
+		"\2\2;=\3\2\2\2<:\3\2\2\2=G\7$\2\2>B\7)\2\2?A\5\17\b\2@?\3\2\2\2AD\3\2"+
+		"\2\2B@\3\2\2\2BC\3\2\2\2CE\3\2\2\2DB\3\2\2\2EG\7)\2\2F\66\3\2\2\2F>\3"+
+		"\2\2\2G\22\3\2\2\2HI\7\61\2\2IJ\7\61\2\2JL\3\2\2\2KM\13\2\2\2LK\3\2\2"+
+		"\2MN\3\2\2\2NO\3\2\2\2NL\3\2\2\2OQ\3\2\2\2PR\t\5\2\2QP\3\2\2\2RS\3\2\2"+
+		"\2ST\b\n\2\2T\24\3\2\2\2UW\t\6\2\2VU\3\2\2\2WX\3\2\2\2XV\3\2\2\2XY\3\2"+
+		"\2\2YZ\3\2\2\2Z[\b\13\2\2[\26\3\2\2\2\r\2 %+\61:BFNQX\3\b\2\2";
+	public static final ATN _ATN =
+		new ATNDeserializer().deserialize(_serializedATN.toCharArray());
+	static {
+		_decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
+		for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
+			_decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
+		}
+	}
+}
\ No newline at end of file