You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devicemap.apache.org by re...@apache.org on 2015/07/30 17:58:26 UTC

svn commit: r1693449 - in /devicemap/trunk/clients/2.0/reference/src: AttributeTransformer.java Attributes.java DeviceMapClient.java JsonFile.java Main.java TransformerIsNumber.java TransformerSplitAndGet.java

Author: rezan
Date: Thu Jul 30 15:58:25 2015
New Revision: 1693449

URL: http://svn.apache.org/r1693449
Log:
attributes

Added:
    devicemap/trunk/clients/2.0/reference/src/AttributeTransformer.java
    devicemap/trunk/clients/2.0/reference/src/Attributes.java
    devicemap/trunk/clients/2.0/reference/src/TransformerIsNumber.java
    devicemap/trunk/clients/2.0/reference/src/TransformerSplitAndGet.java
Modified:
    devicemap/trunk/clients/2.0/reference/src/DeviceMapClient.java
    devicemap/trunk/clients/2.0/reference/src/JsonFile.java
    devicemap/trunk/clients/2.0/reference/src/Main.java

Added: devicemap/trunk/clients/2.0/reference/src/AttributeTransformer.java
URL: http://svn.apache.org/viewvc/devicemap/trunk/clients/2.0/reference/src/AttributeTransformer.java?rev=1693449&view=auto
==============================================================================
--- devicemap/trunk/clients/2.0/reference/src/AttributeTransformer.java (added)
+++ devicemap/trunk/clients/2.0/reference/src/AttributeTransformer.java Thu Jul 30 15:58:25 2015
@@ -0,0 +1,65 @@
+/*
+ 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 java.util.ArrayList;
+import java.util.List;
+
+import org.codehaus.jackson.JsonNode;
+
+public class AttributeTransformer {
+  private final String defaultValue;
+  private final List<Transformer> transformers;
+
+  public AttributeTransformer(JsonNode json) throws Exception {
+    String defaultValueStr = "";
+
+    if(!JsonFile.empty(json, "defaultValue")) {
+      defaultValueStr = json.get("defaultValue").asText();
+    }
+
+    defaultValue = defaultValueStr;
+    transformers = new ArrayList<>();
+
+    if(JsonFile.get(json, "transformers").isArray()) {
+      for(int k = 0; k < json.get("transformers").size(); k++) {
+        JsonNode transformerNode = json.get("transformers").get(k);
+
+        Transformer transformer = DeviceMapClient.getTransformer(transformerNode);
+
+        transformers.add(transformer);
+      }
+    }
+
+    if(transformers.isEmpty()) {
+      throw new Exception("No transformers defined for attributeTranformer");
+    }
+  }
+
+  public String getValue(String input) throws Exception {
+    for(Transformer transformer : transformers) {
+      input = transformer.transform(input);
+    }
+
+    return input;
+  }
+
+  public String getDefaultValue() {
+    return defaultValue;
+  }
+}

Added: devicemap/trunk/clients/2.0/reference/src/Attributes.java
URL: http://svn.apache.org/viewvc/devicemap/trunk/clients/2.0/reference/src/Attributes.java?rev=1693449&view=auto
==============================================================================
--- devicemap/trunk/clients/2.0/reference/src/Attributes.java (added)
+++ devicemap/trunk/clients/2.0/reference/src/Attributes.java Thu Jul 30 15:58:25 2015
@@ -0,0 +1,114 @@
+/*
+ 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 java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.codehaus.jackson.JsonNode;
+
+public class Attributes {
+  private String patternId;
+  private Map<String, String> attributes;
+  private Map<String, AttributeTransformer> attributeTransformers;
+
+  public Attributes(JsonNode json) throws Exception {
+    if(JsonFile.empty(json, "patternId")) {
+      throw new Exception("Bad attribute patternId found");
+    }
+
+    patternId = json.get("patternId").asText();
+    attributes = new HashMap<>();
+    attributeTransformers = new HashMap<>();
+
+    //ATTRIBUTES
+
+    if(JsonFile.get(json, "attributes").isObject()) {
+      for(Iterator<String> j = json.get("attributes").getFieldNames(); j.hasNext();) {
+        String key = j.next();
+        String value = json.get("attributes").get(key).asText();
+
+        attributes.put(key, value);
+      }
+    }
+
+    attributes.put("patternId", patternId);
+
+    //ATTRIBUTE TRANFORMERS
+
+    if(JsonFile.get(json, "attributeTransformers").isObject()) {
+      for(Iterator<String> j = json.get("attributeTransformers").getFieldNames(); j.hasNext();) {
+        String key = j.next();
+        JsonNode attributeTransformerNode = json.get("attributeTransformers").get(key);
+
+        AttributeTransformer attributeTransformer = new AttributeTransformer(attributeTransformerNode);
+
+        attributeTransformers.put(key, attributeTransformer);
+      }
+
+      if(attributeTransformers.isEmpty()) {
+        throw new Exception("No attribute transformers found for " + patternId);
+      }
+    }
+
+    if(attributeTransformers.isEmpty()) {
+      attributes = Collections.unmodifiableMap(attributes);
+    }
+  }
+
+  public Map<String, String> getAttributes(String input) {
+    if(attributeTransformers.isEmpty()) {
+      return attributes;
+    }
+
+    Map<String, String> custom = new HashMap<>();
+
+    for(String key : attributes.keySet()) {
+      String value = attributes.get(key);
+      custom.put(key, value);
+    }
+
+    for(String key : attributeTransformers.keySet()) {
+      AttributeTransformer attributeTransformer = attributeTransformers.get(key);
+
+      try {
+        String value = attributeTransformer.getValue(input);
+
+        custom.put(key, value);
+      } catch(Exception e) {
+        String errorValue = attributeTransformer.getDefaultValue();
+
+        custom.put(key + "_error", errorValue);
+      }
+    }
+
+    return Collections.unmodifiableMap(custom);
+  }
+
+  @Override
+  public String toString() {
+    return "Attribute patternId: " + patternId + ", attribute(s): " + attributes.size() +
+        (attributeTransformers.size() > 0 ? " attributeTransformer(s): " + attributeTransformers.size() : "");
+  }
+
+  public String getPatternId() {
+    return patternId;
+  }
+}

Modified: devicemap/trunk/clients/2.0/reference/src/DeviceMapClient.java
URL: http://svn.apache.org/viewvc/devicemap/trunk/clients/2.0/reference/src/DeviceMapClient.java?rev=1693449&r1=1693448&r2=1693449&view=diff
==============================================================================
--- devicemap/trunk/clients/2.0/reference/src/DeviceMapClient.java (original)
+++ devicemap/trunk/clients/2.0/reference/src/DeviceMapClient.java Thu Jul 30 15:58:25 2015
@@ -18,6 +18,7 @@
  */
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -37,6 +38,7 @@ public class DeviceMapClient {
   private int ngramConcatSize;
 
   private Map<String, List<Pattern>> patterns;
+  private Map<String, Attributes> attributes;
 
   private String defaultId;
 
@@ -49,6 +51,7 @@ public class DeviceMapClient {
     ngramConcatSize = 1;
 
     patterns = new HashMap<>();
+    attributes = new HashMap<>();
 
     defaultId = null;
   }
@@ -145,7 +148,7 @@ public class DeviceMapClient {
     if(JsonFile.get(patternFile.getJsonNode(), "patternSet").isObject()) {
       JsonNode patternSet = patternFile.getJsonNode().get("patternSet");
 
-      if(JsonFile.get(patternSet, "defaultId").isTextual()) {
+      if(!JsonFile.empty(patternSet, "defaultId")) {
         defaultId = patternSet.get("defaultId").asText();
 
         Main.log("Found defaultId: " + defaultId, 2);
@@ -164,6 +167,8 @@ public class DeviceMapClient {
 
       //PATTERNS
 
+      int patternCount = 0;
+
       if(JsonFile.get(patternSet, "patterns").isArray()) {
         for(int i = 0; i < patternSet.get("patterns").size(); i++) {
           JsonNode patternNode = patternSet.get("patterns").get(i);
@@ -183,103 +188,69 @@ public class DeviceMapClient {
           }
 
           Main.log(pattern.toStringFull(), 3);
+
+          patternCount++;
         }
       }
 
-      Main.log("Found " + patterns.size() + " pattern(s)", 1);
+      if(patternCount == 0 && defaultId == null) {
+        throw new Exception("No patterns found");
+      }
+
+      Main.log("Found " + patternCount + " pattern(s), total: " + patterns.size(), 1);
     }
   }
 
-  public void loadAttributes(JsonFile attributes) throws Exception {
-    if(!attributes.getType().equals("pattern") && !attributes.getType().equals("attribute")) {
-      throw new Exception("Unknown pattern file type: " + attributes.getType());
+  public void loadAttributes(JsonFile attributeFile) throws Exception {
+    if(!attributeFile.getType().equals("pattern") && !attributeFile.getType().equals("attribute")) {
+      throw new Exception("Unknown pattern file type: " + attributeFile.getType());
     }
 
-    if(!attributes.getDomain().equals(domain)) {
-      throw new Exception("Domains do not match: " + domain + " != " + attributes.getDomain());
+    if(!attributeFile.getDomain().equals(domain)) {
+      throw new Exception("Domains do not match: " + domain + " != " + attributeFile.getDomain());
     }
 
-    if(!attributes.getDomainVersion().equals(domainVersion)) {
-      throw new Exception("DomainVersions do not match: " + domainVersion + " != " + attributes.getDomainVersion());
+    if(!attributeFile.getDomainVersion().equals(domainVersion)) {
+      throw new Exception("DomainVersions do not match: " + domainVersion + " != " + attributeFile.getDomainVersion());
     }
 
-    Main.log("Loading attributes: " + attributes.getDomain() + ", version: " + attributes.getDomainVersion(), 1);
+    Main.log("Loading attributes: " + attributeFile.getDomain() + ", version: " + attributeFile.getDomainVersion(), 1);
 
     //ATTRIBUTES
 
     int attributeCount = 0;
 
-    if(JsonFile.get(attributes.getJsonNode(), "attributes").isArray()) {
-        for(int i = 0; i < attributes.getJsonNode().get("attributes").size(); i++) {
-          JsonNode attribute = attributes.getJsonNode().get("attributes").get(i);
+    if(JsonFile.get(attributeFile.getJsonNode(), "attributes").isArray()) {
+      for(int i = 0; i < attributeFile.getJsonNode().get("attributes").size(); i++) {
+        JsonNode attributeNode = attributeFile.getJsonNode().get("attributes").get(i);
 
-          if(JsonFile.get(attribute, "patternId").asText().isEmpty()) {
-            throw new Exception("Bad attribute patternId found, position: " + attributeCount);
-          }
-
-          String patternId = attribute.get("patternId").asText();
+        Attributes patternAttributes = new Attributes(attributeNode);
 
-          Main.log("Attribute patternId: " + patternId, 3);
+        Main.log(patternAttributes.toString(), 3);
 
-          if(JsonFile.get(attribute, "attributes").isObject()) {
-            for(Iterator<String> j = attribute.get("attributes").getFieldNames(); j.hasNext();) {
-              String key = j.next();
-              String value = attribute.get("attributes").get(key).asText();
-            }
-          }
+        attributes.put(patternAttributes.getPatternId(), patternAttributes);
 
-          //ATTRIBUTE TRANFORMERS
-
-          if(JsonFile.get(attribute, "attributeTransformers").isArray()) {
-            for(int j = 0; j < attribute.get("attributeTransformers").size(); j++) {
-              JsonNode attributeTransformer = attribute.get("attributeTransformers").get(j);
-
-              if(JsonFile.get(attributeTransformer, "name").asText().isEmpty()) {
-                throw new Exception("Bad attributeTransformer name, position: " + attributeCount);
-              }
-
-              String name = attributeTransformer.get("name").asText();
-
-              if(JsonFile.get(attributeTransformer, "transformers").isArray()) {
-                for(int k = 0; k < attributeTransformer.get("transformers").size(); k++) {
-                  JsonNode transformer = attributeTransformer.get("transformers").get(k);
-                }
-              }
-            }
-          }
-
-          attributeCount++;
-        }
+        attributeCount++;
       }
+    }
 
-    Main.log("Found " + attributeCount + " attributes(s)", 1);
-  }
-
-  public static Transformer getTransformer(JsonNode transformer) throws Exception {
-    String type = JsonFile.get(transformer, "type").asText();
-    JsonNode parameters = JsonFile.get(transformer, "parameters");
-
-    if(type.equals("LowerCase")) {
-      return new TransformerLowerCase();
-    } else if(type.equals("UpperCase")) {
-      return new TransformerUpperCase();
-    } else if(type.equals("ReplaceAll")) {
-      return new TransformerReplaceAll(parameters);
+    if(attributeCount == 0) {
+      throw new Exception("No attributes found");
     }
 
-    throw new Exception("Transformer not found: " + type);
+    Main.log("Found " + attributeCount + " attributes(s), total: " + attributes.size(), 1);
   }
 
-  public String classify(String text) throws Exception {
-    if(text == null) {
-      text = "";
+  public Map<String, String> classify(String input) throws Exception {
+    if(input == null) {
+      input = "";
     }
 
-    Main.log("Classify: '" + text + "'", 2);
+    Main.log("Classify: '" + input + "'", 2);
 
     //TRANFORM THE INPUT
 
-    String transformed = text;
+    String transformed = input;
 
     for(Transformer transformer : transformers) {
       transformed = transformer.transform(transformed);
@@ -289,42 +260,7 @@ public class DeviceMapClient {
 
     //TOKENIZE THE INPUT
 
-    List<String> tokens = new ArrayList<>();
-
-    String source = transformed;
-    int sourcePos = 0;
-    int destStart = 0;
-    int destEnd = 0;
-
-    source:
-    while(sourcePos < source.length()) {
-      seperator:
-      for(String seperator : tokenSeperators) {
-        int i;
-
-        for(i = 0; i < seperator.length(); i++) {
-          if(sourcePos + i >= source.length() || source.charAt(sourcePos + i) != seperator.charAt(i)) {
-            continue seperator;
-          }
-        }
-
-        if(destEnd - destStart > 0) {
-          tokens.add(source.substring(destStart, destEnd));
-        }
-
-        sourcePos += i;
-        destStart = destEnd = sourcePos;
-        
-        continue source;
-      }
-      
-      sourcePos++;
-      destEnd++;
-    }
-
-    if(destEnd - destStart > 0) {
-      tokens.add(source.substring(destStart, destEnd));
-    }
+    List<String> tokens = split(transformed, tokenSeperators);
 
     Main.log("Tokens: " + tokens, 3);
 
@@ -395,13 +331,85 @@ public class DeviceMapClient {
 
     if(winner == null) {
       if(defaultId != null) {
-        return defaultId;
+        return getPatternAttributes(defaultId, input);
       } else {
         return null;
       }
     }
     
-    return winner.getPatternId();
+    return getPatternAttributes(winner.getPatternId(), input);
+  }
+
+  private Map<String, String> getPatternAttributes(String patternId, String input) {
+    Attributes patternAttributes = attributes.get(patternId);
+
+    if(patternAttributes != null) {
+      return patternAttributes.getAttributes(input);
+    }
+
+    Map<String, String> custom = new HashMap<>();
+
+    custom.put("patternId", patternId);
+
+    return Collections.unmodifiableMap(custom);
+  }
+
+  public static List<String> split(String source, List<String> tokenSeperators) {
+    List<String> tokens = new ArrayList<>();
+    int sourcePos = 0;
+    int destStart = 0;
+    int destEnd = 0;
+
+    source:
+    while(sourcePos < source.length()) {
+      seperator:
+      for(String seperator : tokenSeperators) {
+        int i;
+
+        for(i = 0; i < seperator.length(); i++) {
+          if(sourcePos + i >= source.length() || source.charAt(sourcePos + i) != seperator.charAt(i)) {
+            continue seperator;
+          }
+        }
+
+        if(destEnd - destStart > 0) {
+          tokens.add(source.substring(destStart, destEnd));
+        }
+
+        sourcePos += i;
+        destStart = destEnd = sourcePos;
+
+        continue source;
+      }
+
+      sourcePos++;
+      destEnd++;
+    }
+
+    if(destEnd - destStart > 0) {
+      tokens.add(source.substring(destStart, destEnd));
+    }
+
+    return tokens;
+  }
+
+  public static Transformer getTransformer(JsonNode transformer) throws Exception {
+    String type = JsonFile.get(transformer, "type").asText();
+    JsonNode parameters = JsonFile.get(transformer, "parameters");
+
+    if(type.equals("LowerCase")) {
+      return new TransformerLowerCase();
+    } else if(type.equals("UpperCase")) {
+      return new TransformerUpperCase();
+    } else if(type.equals("ReplaceAll")) {
+      return new TransformerReplaceAll(parameters);
+    } else if(type.equals("SplitAndGet")) {
+      return new TransformerSplitAndGet(parameters);
+    } else if(type.equals("IsNumber")) {
+      return new TransformerIsNumber();
+    }
+
+    throw new Exception("Transformer not found: " + type);
   }
 
   public String getDomain() {

Modified: devicemap/trunk/clients/2.0/reference/src/JsonFile.java
URL: http://svn.apache.org/viewvc/devicemap/trunk/clients/2.0/reference/src/JsonFile.java?rev=1693449&r1=1693448&r2=1693449&view=diff
==============================================================================
--- devicemap/trunk/clients/2.0/reference/src/JsonFile.java (original)
+++ devicemap/trunk/clients/2.0/reference/src/JsonFile.java Thu Jul 30 15:58:25 2015
@@ -62,7 +62,11 @@ public class JsonFile {
   }
 
   public static JsonNode get(JsonNode node, String name) throws Exception {
-    JsonNode ret = node.get(name);
+    JsonNode ret = null;
+    
+    if(node != null) {
+      ret = node.get(name);
+    }
 
     if(ret != null) {
       return ret;
@@ -77,7 +81,7 @@ public class JsonFile {
   }
 
   public static boolean empty(JsonNode node, String name) {
-    return (node.get(name) == null || node.get(name).asText().isEmpty());
+    return (node == null || node.get(name) == null || node.get(name).asText().isEmpty());
   }
 
   public String getType() {

Modified: devicemap/trunk/clients/2.0/reference/src/Main.java
URL: http://svn.apache.org/viewvc/devicemap/trunk/clients/2.0/reference/src/Main.java?rev=1693449&r1=1693448&r2=1693449&view=diff
==============================================================================
--- devicemap/trunk/clients/2.0/reference/src/Main.java (original)
+++ devicemap/trunk/clients/2.0/reference/src/Main.java Thu Jul 30 15:58:25 2015
@@ -20,6 +20,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import org.codehaus.jackson.JsonNode;
 
@@ -94,7 +95,7 @@ public class Main {
 
     if(testString != null) {
       log("Test string: '" + testString + "'", 0);
-      String result = client.classify(testString);
+      Map<String, String> result = client.classify(testString);
       log("Test result: " + result, -1);
     }
 
@@ -110,7 +111,8 @@ public class Main {
     log("  -t <file>            load DeviceMap 2.0 test file", -1);
     log("  -h                   print help", -1);
     log("  -q                   quiet", -1);
-    log("  -v[v]                verbose", -1);
+    log("  -v                   verbose", -1);
+    log("  -vv                  very verbose", -1);
     log("  STRING               test string", -1);
     log("", -1);
   }
@@ -177,15 +179,20 @@ public class Main {
             }
           }
 
-          String result = client.classify(input);
+          Map<String, String> result = client.classify(input);
+          String patternId = null;
+
+          if(result != null) {
+            patternId = result.get("patternId");
+          }
 
           boolean pass = false;
 
           if(resultPatternId == null) {
-            if(result == null) {
+            if(patternId == null) {
               pass = true;
             }
-          } else if(resultPatternId.equals(result)) {
+          } else if(resultPatternId.equals(patternId)) {
             pass = true;
           }
 
@@ -193,7 +200,7 @@ public class Main {
             passCount++;
             log("Passed, expected: " + resultPatternId, 2);
           } else {
-            log("FAILED, expected: " + resultPatternId + ", result: " + result, 2);
+            log("FAILED, expected: " + resultPatternId + ", result: " + patternId, 2);
           }
 
           testCount++;

Added: devicemap/trunk/clients/2.0/reference/src/TransformerIsNumber.java
URL: http://svn.apache.org/viewvc/devicemap/trunk/clients/2.0/reference/src/TransformerIsNumber.java?rev=1693449&view=auto
==============================================================================
--- devicemap/trunk/clients/2.0/reference/src/TransformerIsNumber.java (added)
+++ devicemap/trunk/clients/2.0/reference/src/TransformerIsNumber.java Thu Jul 30 15:58:25 2015
@@ -0,0 +1,36 @@
+/*
+ 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.
+ */
+
+public class TransformerIsNumber implements Transformer {
+  @Override
+  public String transform(String input) throws Exception {
+    try {
+      Double.parseDouble(input);
+    } catch(NumberFormatException nfe) {
+      throw new Exception(nfe.getMessage());
+    }
+    
+    return input;
+  }
+
+  @Override
+  public String toString() {
+    return "TransformerIsNumber";
+  }
+}

Added: devicemap/trunk/clients/2.0/reference/src/TransformerSplitAndGet.java
URL: http://svn.apache.org/viewvc/devicemap/trunk/clients/2.0/reference/src/TransformerSplitAndGet.java?rev=1693449&view=auto
==============================================================================
--- devicemap/trunk/clients/2.0/reference/src/TransformerSplitAndGet.java (added)
+++ devicemap/trunk/clients/2.0/reference/src/TransformerSplitAndGet.java Thu Jul 30 15:58:25 2015
@@ -0,0 +1,69 @@
+/*
+ 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 java.util.ArrayList;
+import java.util.List;
+
+import org.codehaus.jackson.JsonNode;
+
+public class TransformerSplitAndGet implements Transformer {
+  private final List<String> delimeter;
+  private final int get;
+
+  public TransformerSplitAndGet(JsonNode json) throws Exception {
+    if(JsonFile.empty(json, "delimeter")) {
+      throw new Exception("SplitAndGet delimeter not defined");
+    }
+
+    if(JsonFile.empty(json, "get")) {
+      throw new Exception("SplitAndGet get not defined");
+    }
+
+    delimeter = new ArrayList<>();
+    delimeter.add(json.get("delimeter").asText());
+    
+    get = Integer.parseInt(json.get("get").asText());
+
+    if(get < -1) {
+      throw new Exception("Invalid value of get for SplitAndGet: " + get);
+    }
+  }
+
+  @Override
+  public String transform(String input) throws Exception {
+    List<String> parts = DeviceMapClient.split(input, delimeter);
+    
+    int i = get;
+
+    if(get == -1) {
+      i = parts.size() - 1;
+    }
+
+    if(i < 0 || i >= parts.size()) {
+      throw new Exception("SplitAndGet index out of range: " + i);
+    }
+
+    return parts.get(i);
+  }
+
+  @Override
+  public String toString() {
+    return "SplitAndGet, delimeter: '" + delimeter + "', get: " + get;
+  }
+}