You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metron.apache.org by rm...@apache.org on 2018/08/17 15:34:24 UTC

[09/51] [abbrv] metron git commit: METRON-1638 Retrieve Pcap results in pdml format (merrimanr) closes apache/metron#1120

METRON-1638 Retrieve Pcap results in pdml format (merrimanr) closes apache/metron#1120


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

Branch: refs/heads/master
Commit: 3e5ef41d9b8639fb1155686e615c02a59b735397
Parents: f316d15
Author: merrimanr <me...@gmail.com>
Authored: Thu Jul 19 17:13:22 2018 -0500
Committer: rmerriman <me...@gmail.com>
Committed: Thu Jul 19 17:13:22 2018 -0500

----------------------------------------------------------------------
 dependencies_with_url.csv                       |   3 +
 .../docker/rpm-docker/SPECS/metron.spec         |   1 +
 metron-interface/metron-rest-client/pom.xml     |   5 +
 .../apache/metron/rest/model/pcap/Field.java    | 164 ++++++++++++
 .../apache/metron/rest/model/pcap/Packet.java   |  53 ++++
 .../org/apache/metron/rest/model/pcap/Pdml.java | 103 ++++++++
 .../apache/metron/rest/model/pcap/Proto.java    | 114 +++++++++
 metron-interface/metron-rest/README.md          |  34 ++-
 metron-interface/metron-rest/pom.xml            |   1 -
 .../src/main/config/rest_application.yml        |   5 +-
 .../apache/metron/rest/MetronRestConstants.java |   1 +
 .../apache/metron/rest/config/PcapConfig.java   |   6 +
 .../metron/rest/controller/PcapController.java  |  31 ++-
 .../apache/metron/rest/service/PcapService.java |   6 +
 .../rest/service/impl/PcapServiceImpl.java      |  47 +++-
 .../service/impl/PcapToPdmlScriptWrapper.java   |  59 +++++
 .../src/main/scripts/pcap_to_pdml.sh            |  19 ++
 .../apache/metron/rest/config/TestConfig.java   |   7 +
 .../PcapControllerIntegrationTest.java          |  65 +++--
 .../rest/mock/MockPcapToPdmlScriptWrapper.java  |  55 ++++
 .../rest/service/impl/PcapServiceImplTest.java  | 250 +++++++++++++++++--
 metron-interface/pom.xml                        |   3 +
 22 files changed, 981 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/dependencies_with_url.csv
----------------------------------------------------------------------
diff --git a/dependencies_with_url.csv b/dependencies_with_url.csv
index 40d3e06..bf3e382 100644
--- a/dependencies_with_url.csv
+++ b/dependencies_with_url.csv
@@ -141,12 +141,15 @@ com.fasterxml.jackson.dataformat:jackson-dataformat-smile:jar:2.6.6:compile,ASLv
 com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:jar:2.6.6:compile,ASLv2,https://github.com/FasterXML/jackson
 com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:jar:2.7.4:compile,ASLv2,http://wiki.fasterxml.com/JacksonForCbor
 com.fasterxml.jackson.dataformat:jackson-dataformat-smile:jar:2.7.4:compile,ASLv2,http://wiki.fasterxml.com/JacksonForSmile
+com.fasterxml.jackson.dataformat:jackson-dataformat-xml:jar:2.9.5:compile,ASLv2,https://github.com/FasterXML/jackson
 com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:jar:2.7.4:compile,ASLv2,https://github.com/FasterXML/jackson
 com.fasterxml.jackson.datatype:jackson-datatype-joda:jar:2.8.1:compile,ASLv2,https://github.com/FasterXML/jackson-datatype-joda
 com.fasterxml.jackson.datatype:jackson-datatype-joda:jar:2.9.5:compile,ASLv2,https://github.com/FasterXML/jackson-datatype-joda
 com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.9.5:compile,ASLv2,https://github.com/FasterXML/jackson-modules-java8
 com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.9.5:compile,ASLv2,https://github.com/FasterXML/jackson-modules-java8
 com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.9.5:compile,ASLv2,https://github.com/FasterXML/jackson-modules-java8
+com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.9.5:compile,ASLv2,https://github.com/FasterXML/jackson-modules-java8
+com.fasterxml.woodstox:woodstox-core:jar:5.0.3:compile,ASLv2,https://github.com/FasterXML/woodstox
 com.fasterxml:classmate:jar:1.3.1:compile,ASLv2,http://github.com/cowtowncoder/java-classmate
 com.fasterxml:classmate:jar:1.3.4:compile,ASLv2,http://github.com/cowtowncoder/java-classmate
 com.google.code.gson:gson:jar:2.2.4:compile,The Apache Software License, Version 2.0,http://code.google.com/p/google-gson/

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-deployment/packaging/docker/rpm-docker/SPECS/metron.spec
----------------------------------------------------------------------
diff --git a/metron-deployment/packaging/docker/rpm-docker/SPECS/metron.spec b/metron-deployment/packaging/docker/rpm-docker/SPECS/metron.spec
index 4b88fd0..3f090c8 100644
--- a/metron-deployment/packaging/docker/rpm-docker/SPECS/metron.spec
+++ b/metron-deployment/packaging/docker/rpm-docker/SPECS/metron.spec
@@ -419,6 +419,7 @@ This package installs the Metron Rest %{metron_home}
 %dir %{metron_home}/lib
 %{metron_home}/config/rest_application.yml
 %{metron_home}/bin/metron-rest.sh
+%{metron_home}/bin/pcap_to_pdml.sh
 %attr(0644,root,root) %{metron_home}/lib/metron-rest-%{full_version}.jar
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest-client/pom.xml
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest-client/pom.xml b/metron-interface/metron-rest-client/pom.xml
index a2f1288..d3fecfd 100644
--- a/metron-interface/metron-rest-client/pom.xml
+++ b/metron-interface/metron-rest-client/pom.xml
@@ -52,6 +52,11 @@
             <artifactId>javax.persistence</artifactId>
             <version>${eclipse.javax.persistence.version}</version>
         </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.dataformat</groupId>
+            <artifactId>jackson-dataformat-xml</artifactId>
+            <version>${jackson.version}</version>
+        </dependency>
     </dependencies>
 
 </project>

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/pcap/Field.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/pcap/Field.java b/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/pcap/Field.java
new file mode 100644
index 0000000..9c2878b
--- /dev/null
+++ b/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/pcap/Field.java
@@ -0,0 +1,164 @@
+/**
+ * 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.rest.model.pcap;
+
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Field {
+
+  @JacksonXmlProperty(isAttribute = true)
+  private String name;
+  @JacksonXmlProperty(isAttribute = true)
+  private String pos;
+  @JacksonXmlProperty(isAttribute = true)
+  private String showname;
+  @JacksonXmlProperty(isAttribute = true)
+  private String size;
+  @JacksonXmlProperty(isAttribute = true)
+  private String value;
+  @JacksonXmlProperty(isAttribute = true)
+  private String show;
+  @JacksonXmlProperty(isAttribute = true)
+  private String unmaskedvalue;
+  @JacksonXmlProperty(isAttribute = true)
+  private String hide;
+  @JacksonXmlProperty(localName = "field")
+  @JacksonXmlElementWrapper(useWrapping = false)
+  private List<Field> fields;
+  @JacksonXmlProperty(localName = "proto")
+  @JacksonXmlElementWrapper(useWrapping = false)
+  private List<Proto> protos;
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getPos() {
+    return pos;
+  }
+
+  public void setPos(String pos) {
+    this.pos = pos;
+  }
+
+  public String getShowname() {
+    return showname;
+  }
+
+  public void setShowname(String showname) {
+    this.showname = showname;
+  }
+
+  public String getSize() {
+    return size;
+  }
+
+  public void setSize(String size) {
+    this.size = size;
+  }
+
+  public String getValue() {
+    return value;
+  }
+
+  public void setValue(String value) {
+    this.value = value;
+  }
+
+  public String getShow() {
+    return show;
+  }
+
+  public void setShow(String show) {
+    this.show = show;
+  }
+
+  public String getUnmaskedvalue() {
+    return unmaskedvalue;
+  }
+
+  public void setUnmaskedvalue(String unmaskedvalue) {
+    this.unmaskedvalue = unmaskedvalue;
+  }
+
+  public String getHide() {
+    return hide;
+  }
+
+  public void setHide(String hide) {
+    this.hide = hide;
+  }
+
+  public List<Field> getFields() {
+    return fields;
+  }
+
+  public void setFields(List<Field> fields) {
+    this.fields = fields;
+  }
+
+  public List<Proto> getProtos() {
+    return protos;
+  }
+
+  public void setProtos(List<Proto> protos) {
+    this.protos = protos;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    Field field = (Field) o;
+
+    return (getName() != null ? getName().equals(field.getName()) : field.getName() != null) &&
+            (getPos() != null ? getPos().equals(field.getPos()) : field.getPos() == null) &&
+            (getShowname() != null ? getShowname().equals(field.getShowname()) : field.getShowname() == null) &&
+            (getSize() != null ? getSize().equals(field.getSize()) : field.getSize() == null) &&
+            (getValue() != null ? getValue().equals(field.getValue()) : field.getValue() == null) &&
+            (getShow() != null ? getShow().equals(field.getShow()) : field.getShow() == null) &&
+            (getUnmaskedvalue() != null ? getUnmaskedvalue().equals(field.getUnmaskedvalue()) : field.getUnmaskedvalue() == null) &&
+            (getHide() != null ? getHide().equals(field.getHide()) : field.getHide() == null) &&
+            (getFields() != null ? getFields().equals(field.getFields()) : field.getFields() == null) &&
+            (getProtos() != null ? getProtos().equals(field.getProtos()) : field.getProtos() == null);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = getName() != null ? getName().hashCode() : 0;
+    result = 31 * result + (getPos() != null ? getPos().hashCode() : 0);
+    result = 31 * result + (getShowname() != null ? getShowname().hashCode() : 0);
+    result = 31 * result + (getSize() != null ? getSize().hashCode() : 0);
+    result = 31 * result + (getValue() != null ? getValue().hashCode() : 0);
+    result = 31 * result + (getShow() != null ? getShow().hashCode() : 0);
+    result = 31 * result + (getUnmaskedvalue() != null ? getUnmaskedvalue().hashCode() : 0);
+    result = 31 * result + (getHide() != null ? getHide().hashCode() : 0);
+    result = 31 * result + (getFields() != null ? getFields().hashCode() : 0);
+    result = 31 * result + (getProtos() != null ? getProtos().hashCode() : 0);
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/pcap/Packet.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/pcap/Packet.java b/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/pcap/Packet.java
new file mode 100644
index 0000000..de21e6b
--- /dev/null
+++ b/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/pcap/Packet.java
@@ -0,0 +1,53 @@
+/**
+ * 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.rest.model.pcap;
+
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+
+import java.util.List;
+
+public class Packet {
+
+  @JacksonXmlProperty(localName = "proto")
+  @JacksonXmlElementWrapper(useWrapping = false)
+  private List<Proto> protos;
+
+  public List<Proto> getProtos() {
+    return protos;
+  }
+
+  public void setProtos(List<Proto> protos) {
+    this.protos = protos;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    Packet packet = (Packet) o;
+
+    return (getProtos() != null ? getProtos().equals(packet.getProtos()) : packet.getProtos() == null);
+  }
+
+  @Override
+  public int hashCode() {
+    return getProtos() != null ? getProtos().hashCode() : 0;
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/pcap/Pdml.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/pcap/Pdml.java b/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/pcap/Pdml.java
new file mode 100644
index 0000000..f44f96b
--- /dev/null
+++ b/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/pcap/Pdml.java
@@ -0,0 +1,103 @@
+/**
+ * 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.rest.model.pcap;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+
+import java.util.List;
+
+public class Pdml {
+
+  @JacksonXmlProperty(isAttribute = true)
+  private String version;
+  @JacksonXmlProperty(isAttribute = true)
+  private String creator;
+  @JacksonXmlProperty(isAttribute = true)
+  private String time;
+  @JacksonXmlProperty(isAttribute = true, localName = "capture_file")
+  private String captureFile;
+  @JacksonXmlProperty(localName = "packet")
+  @JacksonXmlElementWrapper(useWrapping = false)
+  private List<Packet> packets;
+
+  public String getVersion() {
+    return version;
+  }
+
+  public void setVersion(String version) {
+    this.version = version;
+  }
+
+  public String getCreator() {
+    return creator;
+  }
+
+  public void setCreator(String creator) {
+    this.creator = creator;
+  }
+
+  public String getTime() {
+    return time;
+  }
+
+  public void setTime(String time) {
+    this.time = time;
+  }
+
+  public String getCaptureFile() {
+    return captureFile;
+  }
+
+  public void setCaptureFile(String captureFile) {
+    this.captureFile = captureFile;
+  }
+
+  public List<Packet> getPackets() {
+    return packets;
+  }
+
+  public void setPackets(List<Packet> packets) {
+    this.packets = packets;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    Pdml pdml = (Pdml) o;
+
+    return (getVersion() != null ? getVersion().equals(pdml.getVersion()) : pdml.getVersion() != null) &&
+            (getCreator() != null ? getCreator().equals(pdml.getCreator()) : pdml.getCreator() == null) &&
+            (getTime() != null ? getTime().equals(pdml.getTime()) : pdml.getTime() == null) &&
+            (getCaptureFile() != null ? getCaptureFile().equals(pdml.getCaptureFile()) : pdml.getCaptureFile() == null) &&
+            (getPackets() != null ? getPackets().equals(pdml.getPackets()) : pdml.getPackets() == null);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = getVersion() != null ? getVersion().hashCode() : 0;
+    result = 31 * result + (getCreator() != null ? getCreator().hashCode() : 0);
+    result = 31 * result + (getTime() != null ? getTime().hashCode() : 0);
+    result = 31 * result + (getCaptureFile() != null ? getCaptureFile().hashCode() : 0);
+    result = 31 * result + (getPackets() != null ? getPackets().hashCode() : 0);
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/pcap/Proto.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/pcap/Proto.java b/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/pcap/Proto.java
new file mode 100644
index 0000000..bdd5c1f
--- /dev/null
+++ b/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/pcap/Proto.java
@@ -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.
+ */
+package org.apache.metron.rest.model.pcap;
+
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+
+import java.util.List;
+
+public class Proto {
+
+  @JacksonXmlProperty(isAttribute = true)
+  private String name;
+  @JacksonXmlProperty(isAttribute = true)
+  private String pos;
+  @JacksonXmlProperty(isAttribute = true)
+  private String showname;
+  @JacksonXmlProperty(isAttribute = true)
+  private String size;
+  @JacksonXmlProperty(isAttribute = true)
+  private String hide;
+  @JacksonXmlProperty(localName = "field")
+  @JacksonXmlElementWrapper(useWrapping = false)
+  private List<Field> fields;
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getPos() {
+    return pos;
+  }
+
+  public void setPos(String pos) {
+    this.pos = pos;
+  }
+
+  public String getShowname() {
+    return showname;
+  }
+
+  public void setShowname(String showname) {
+    this.showname = showname;
+  }
+
+  public String getSize() {
+    return size;
+  }
+
+  public void setSize(String size) {
+    this.size = size;
+  }
+
+  public String getHide() {
+    return hide;
+  }
+
+  public void setHide(String hide) {
+    this.hide = hide;
+  }
+
+  public List<Field> getFields() {
+    return fields;
+  }
+
+  public void setFields(List<Field> fields) {
+    this.fields = fields;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    Proto proto = (Proto) o;
+
+    return (getName() != null ? getName().equals(proto.getName()) : proto.getName() != null) &&
+            (getPos() != null ? getPos().equals(proto.getPos()) : proto.getPos() == null) &&
+            (getShowname() != null ? getShowname().equals(proto.getShowname()) : proto.getShowname() == null) &&
+            (getSize() != null ? getSize().equals(proto.getSize()) : proto.getSize() == null) &&
+            (getHide() != null ? getHide().equals(proto.getHide()) : proto.getHide() == null) &&
+            (getFields() != null ? getFields().equals(proto.getFields()) : proto.getFields() == null);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = getName() != null ? getName().hashCode() : 0;
+    result = 31 * result + (getPos() != null ? getPos().hashCode() : 0);
+    result = 31 * result + (getShowname() != null ? getShowname().hashCode() : 0);
+    result = 31 * result + (getSize() != null ? getSize().hashCode() : 0);
+    result = 31 * result + (getHide() != null ? getHide().hashCode() : 0);
+    result = 31 * result + (getFields() != null ? getFields().hashCode() : 0);
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest/README.md
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/README.md b/metron-interface/metron-rest/README.md
index 7ccedc8..7b3a263 100644
--- a/metron-interface/metron-rest/README.md
+++ b/metron-interface/metron-rest/README.md
@@ -210,6 +210,17 @@ Setting active profiles is done with the METRON_SPRING_PROFILES_ACTIVE variable.
 METRON_SPRING_PROFILES_ACTIVE="vagrant,dev"
 ```
 
+## Pcap Query
+
+The REST application exposes endpoints for querying Pcap data.  For more information about filtering options see [Query Filter Utility](/metron-platform/metron-pcap-backend#query-filter-utility).
+
+There is an endpoint available that will return Pcap data in [PDML](https://wiki.wireshark.org/PDML) format.  [Wireshark](https://www.wireshark.org/) must be installed for this feature to work.
+Installing wireshark in CentOS can be done with `yum -y install wireshark`.
+
+The REST application uses a Java Process object to call out to the `pcap_to_pdml.sh` script.  This script is installed at `$METRON_HOME/bin/pcap_to_pdml.sh` by default.
+Out of the box it is a simple wrapper around the tshark command to transform raw pcap data to PDML.  However it can be extended to do additional processing as long as the expected input/output is maintained.
+REST will supply the script with raw pcap data through standard in and expects PDML data serialized as XML.
+
 ## API
 
 Request and Response objects are JSON formatted.  The JSON schemas are available in the Swagger UI.
@@ -243,6 +254,8 @@ Request and Response objects are JSON formatted.  The JSON schemas are available
 | [ `GET /api/v1/metaalert/remove/alert`](#get-apiv1metaalertremovealert)|
 | [ `GET /api/v1/metaalert/update/status/{guid}/{status}`](#get-apiv1metaalertupdatestatusguidstatus)|
 | [ `GET /api/v1/pcap/fixed`](#get-apiv1pcapfixed)|
+| [ `GET /api/v1/pcap/{jobId}`](#get-apiv1pcapjobid)|
+| [ `GET /api/v1/pcap/{jobId}/pdml`](#get-apiv1pcapjobidpdml)|
 | [ `GET /api/v1/search/search`](#get-apiv1searchsearch)|
 | [ `POST /api/v1/search/search`](#get-apiv1searchsearch)|
 | [ `POST /api/v1/search/group`](#get-apiv1searchgroup)|
@@ -490,9 +503,26 @@ Request and Response objects are JSON formatted.  The JSON schemas are available
 ### `POST /api/v1/pcap/fixed`
   * Description: Executes a Fixed Pcap Query.
   * Input:
-    * fixedPcapRequest - A Fixed Pcap Request which includes fixed filter fields like ip source address and protocol.
+    * fixedPcapRequest - A Fixed Pcap Request which includes fixed filter fields like ip source address and protocol
+  * Returns:
+    * 200 - Returns a job status with job ID.
+    
+### `POST /api/v1/pcap/{jobId}`
+  * Description: Gets job status for Pcap query job.
+  * Input:
+    * jobId - Job ID of submitted job
+  * Returns:
+    * 200 - Returns a job status for the Job ID.
+    * 404 - Job is missing.
+    
+### `POST /api/v1/pcap/{jobId}/pdml`
+  * Description: Gets Pcap Results for a page in PDML format.
+  * Input:
+    * jobId - Job ID of submitted job
+    * page - Page number
   * Returns:
-    * 200 - Returns a PcapResponse containing an array of pcaps.
+    * 200 - Returns PDML in json format.
+    * 404 - Job or page is missing.
 
 ### `POST /api/v1/search/search`
   * Description: Searches the indexing store. GUIDs must be quoted to ensure correct results.

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest/pom.xml
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/pom.xml b/metron-interface/metron-rest/pom.xml
index 733ef6a..1bf0fd6 100644
--- a/metron-interface/metron-rest/pom.xml
+++ b/metron-interface/metron-rest/pom.xml
@@ -36,7 +36,6 @@
         <spring-kafka.version>2.0.4.RELEASE</spring-kafka.version>
         <spring.version>5.0.5.RELEASE</spring.version>
         <eclipse.link.version>2.6.4</eclipse.link.version>
-        <jackson.version>2.9.5</jackson.version>
         <jsonpath.version>2.4.0</jsonpath.version>
     </properties>
     <dependencies>

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest/src/main/config/rest_application.yml
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/config/rest_application.yml b/metron-interface/metron-rest/src/main/config/rest_application.yml
index 4cc51ff..3999393 100644
--- a/metron-interface/metron-rest/src/main/config/rest_application.yml
+++ b/metron-interface/metron-rest/src/main/config/rest_application.yml
@@ -52,4 +52,7 @@ storm:
 kerberos:
   enabled: ${SECURITY_ENABLED}
   principal: ${METRON_PRINCIPAL_NAME}
-  keytab: ${METRON_SERVICE_KEYTAB}
\ No newline at end of file
+  keytab: ${METRON_SERVICE_KEYTAB}
+
+pcap:
+  pdml.script.path: ${METRON_HOME}/bin/pcap_to_pdml.sh
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/MetronRestConstants.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/MetronRestConstants.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/MetronRestConstants.java
index 8e14e38..b65d037 100644
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/MetronRestConstants.java
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/MetronRestConstants.java
@@ -79,4 +79,5 @@ public class MetronRestConstants {
   public static final String PCAP_BASE_INTERIM_RESULT_PATH_SPRING_PROPERTY = "pcap.base.interim.result.path";
   public static final String PCAP_FINAL_OUTPUT_PATH_SPRING_PROPERTY = "pcap.final.output.path";
   public static final String PCAP_PAGE_SIZE_SPRING_PROPERTY = "pcap.page.size";
+  public static final String PCAP_PDML_SCRIPT_PATH_SPRING_PROPERTY = "pcap.pdml.script.path";
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/PcapConfig.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/PcapConfig.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/PcapConfig.java
index a0b7f18..323df05 100644
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/PcapConfig.java
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/PcapConfig.java
@@ -19,6 +19,7 @@ package org.apache.metron.rest.config;
 
 import org.apache.metron.job.manager.InMemoryJobManager;
 import org.apache.metron.job.manager.JobManager;
+import org.apache.metron.rest.service.impl.PcapToPdmlScriptWrapper;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Profile;
@@ -39,5 +40,10 @@ public class PcapConfig {
     return new PcapJobSupplier();
   }
 
+  @Bean
+  public PcapToPdmlScriptWrapper pcapToPdmlScriptWrapper() {
+    return new PcapToPdmlScriptWrapper();
+  }
+
 
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/PcapController.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/PcapController.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/PcapController.java
index 6663659..47bc6a0 100644
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/PcapController.java
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/PcapController.java
@@ -24,6 +24,7 @@ import io.swagger.annotations.ApiResponses;
 import org.apache.metron.rest.RestException;
 import org.apache.metron.rest.model.pcap.FixedPcapRequest;
 import org.apache.metron.rest.model.pcap.PcapStatus;
+import org.apache.metron.rest.model.pcap.Pdml;
 import org.apache.metron.rest.security.SecurityUtils;
 import org.apache.metron.rest.service.PcapService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -33,6 +34,7 @@ import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 @RestController
@@ -46,16 +48,18 @@ public class PcapController {
   @ApiResponses(value = { @ApiResponse(message = "Returns a job status with job ID.", code = 200)})
   @RequestMapping(value = "/fixed", method = RequestMethod.POST)
   ResponseEntity<PcapStatus> fixed(@ApiParam(name="fixedPcapRequest", value="A Fixed Pcap Request"
-          + " which includes fixed filter fields like ip source address and protocol.", required=true)@RequestBody FixedPcapRequest fixedPcapRequest) throws RestException {
+          + " which includes fixed filter fields like ip source address and protocol", required=true)@RequestBody FixedPcapRequest fixedPcapRequest) throws RestException {
     PcapStatus pcapStatus = pcapQueryService.fixed(SecurityUtils.getCurrentUser(), fixedPcapRequest);
     return new ResponseEntity<>(pcapStatus, HttpStatus.OK);
   }
 
-  @ApiOperation(value = "Gets job status for running job.")
-  @ApiResponses(value = { @ApiResponse(message = "Returns a job status for the passed job.", code = 200)})
+  @ApiOperation(value = "Gets job status for Pcap query job.")
+  @ApiResponses(value = {
+          @ApiResponse(message = "Returns a job status for the Job ID.", code = 200),
+          @ApiResponse(message = "Job is missing.", code = 404)
+  })
   @RequestMapping(value = "/{jobId}", method = RequestMethod.GET)
-  ResponseEntity<PcapStatus> getStatus(@ApiParam(name="jobId", value="Job ID of submitted job"
-      + " which includes fixed filter fields like ip source address and protocol.", required=true)@PathVariable String jobId) throws RestException {
+  ResponseEntity<PcapStatus> getStatus(@ApiParam(name="jobId", value="Job ID of submitted job", required=true)@PathVariable String jobId) throws RestException {
     PcapStatus jobStatus = pcapQueryService.getJobStatus(SecurityUtils.getCurrentUser(), jobId);
     if (jobStatus != null) {
       return new ResponseEntity<>(jobStatus, HttpStatus.OK);
@@ -64,6 +68,23 @@ public class PcapController {
     }
   }
 
+  @ApiOperation(value = "Gets Pcap Results for a page in PDML format.")
+  @ApiResponses(value = {
+          @ApiResponse(message = "Returns PDML in json format.", code = 200),
+          @ApiResponse(message = "Job or page is missing.", code = 404)
+  })
+  @RequestMapping(value = "/{jobId}/pdml", method = RequestMethod.GET)
+  ResponseEntity<Pdml> pdml(@ApiParam(name="jobId", value="Job ID of submitted job", required=true)@PathVariable String jobId,
+                            @ApiParam(name="page", value="Page number", required=true)@RequestParam Integer page) throws RestException {
+    Pdml pdml = pcapQueryService.getPdml(SecurityUtils.getCurrentUser(), jobId, page);
+    if (pdml != null) {
+      return new ResponseEntity<>(pdml, HttpStatus.OK);
+    } else {
+      return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+    }
+  }
+
+
   @ApiOperation(value = "Kills running job.")
   @ApiResponses(value = { @ApiResponse(message = "Kills passed job.", code = 200)})
   @RequestMapping(value = "/kill/{jobId}", method = RequestMethod.DELETE)

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/PcapService.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/PcapService.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/PcapService.java
index 8073573..9421ce3 100644
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/PcapService.java
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/PcapService.java
@@ -17,9 +17,12 @@
  */
 package org.apache.metron.rest.service;
 
+import org.apache.hadoop.fs.Path;
 import org.apache.metron.rest.RestException;
 import org.apache.metron.rest.model.pcap.FixedPcapRequest;
 import org.apache.metron.rest.model.pcap.PcapStatus;
+import org.apache.metron.rest.model.pcap.Pdml;
+import org.apache.metron.rest.model.pcap.Pdml;
 
 public interface PcapService {
 
@@ -29,4 +32,7 @@ public interface PcapService {
 
   PcapStatus killJob(String username, String jobId) throws RestException;
 
+  Path getPath(String username, String jobId, Integer page) throws RestException;
+
+  Pdml getPdml(String username, String jobId, Integer page) throws RestException;
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/PcapServiceImpl.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/PcapServiceImpl.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/PcapServiceImpl.java
index 6c21e77..7894b1a 100644
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/PcapServiceImpl.java
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/PcapServiceImpl.java
@@ -17,7 +17,7 @@
  */
 package org.apache.metron.rest.service.impl;
 
-import java.io.IOException;
+import com.fasterxml.jackson.dataformat.xml.XmlMapper;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
@@ -34,11 +34,15 @@ import org.apache.metron.rest.config.PcapJobSupplier;
 import org.apache.metron.rest.model.pcap.FixedPcapRequest;
 import org.apache.metron.rest.model.pcap.PcapRequest;
 import org.apache.metron.rest.model.pcap.PcapStatus;
+import org.apache.metron.rest.model.pcap.Pdml;
 import org.apache.metron.rest.service.PcapService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.env.Environment;
 import org.springframework.stereotype.Service;
 
+import java.io.IOException;
+import java.io.InputStream;
+
 @Service
 public class PcapServiceImpl implements PcapService {
 
@@ -46,13 +50,15 @@ public class PcapServiceImpl implements PcapService {
   private Configuration configuration;
   private PcapJobSupplier pcapJobSupplier;
   private JobManager<Path> jobManager;
+  private PcapToPdmlScriptWrapper pcapToPdmlScriptWrapper;
 
   @Autowired
-  public PcapServiceImpl(Environment environment, Configuration configuration, PcapJobSupplier pcapJobSupplier, JobManager<Path> jobManager) {
+  public PcapServiceImpl(Environment environment, Configuration configuration, PcapJobSupplier pcapJobSupplier, JobManager<Path> jobManager, PcapToPdmlScriptWrapper pcapToPdmlScriptWrapper) {
     this.environment = environment;
     this.configuration = configuration;
     this.pcapJobSupplier = pcapJobSupplier;
     this.jobManager = jobManager;
+    this.pcapToPdmlScriptWrapper = pcapToPdmlScriptWrapper;
   }
 
   @Override
@@ -103,6 +109,43 @@ public class PcapServiceImpl implements PcapService {
     return getJobStatus(username, jobId);
   }
 
+  @Override
+  public Path getPath(String username, String jobId, Integer page) throws RestException {
+    Path path = null;
+    try {
+      Statusable<Path> statusable = jobManager.getJob(username, jobId);
+      if (statusable != null && statusable.isDone()) {
+        Pageable<Path> pageable = statusable.get();
+        if (pageable != null && page <= pageable.getSize() && page > 0) {
+          path = pageable.getPage(page - 1);
+        }
+      }
+    } catch (JobNotFoundException e) {
+      // do nothing and return null pcapStatus
+    } catch (JobException | InterruptedException e) {
+      throw new RestException(e);
+    }
+    return path;
+  }
+
+  @Override
+  public Pdml getPdml(String username, String jobId, Integer page) throws RestException {
+    Pdml pdml = null;
+    Path path = getPath(username, jobId, page);
+    try {
+      FileSystem fileSystem = getFileSystem();
+      if (path!= null && fileSystem.exists(path)) {
+        String scriptPath = environment.getProperty(MetronRestConstants.PCAP_PDML_SCRIPT_PATH_SPRING_PROPERTY);
+        InputStream processInputStream = pcapToPdmlScriptWrapper.execute(scriptPath, fileSystem, path);
+        pdml = new XmlMapper().readValue(processInputStream, Pdml.class);
+        processInputStream.close();
+      }
+    } catch (IOException e) {
+      throw new RestException(e);
+    }
+    return pdml;
+  }
+
   protected void setPcapOptions(String username, PcapRequest pcapRequest) throws IOException {
     PcapOptions.JOB_NAME.put(pcapRequest, "jobName");
     PcapOptions.USERNAME.put(pcapRequest, username);

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/PcapToPdmlScriptWrapper.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/PcapToPdmlScriptWrapper.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/PcapToPdmlScriptWrapper.java
new file mode 100644
index 0000000..b5e3033
--- /dev/null
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/PcapToPdmlScriptWrapper.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.rest.service.impl;
+
+import com.fasterxml.jackson.dataformat.xml.XmlMapper;
+import org.apache.commons.io.IOUtils;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.metron.rest.MetronRestConstants;
+import org.apache.metron.rest.RestException;
+import org.apache.metron.rest.model.pcap.Pdml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+
+public class PcapToPdmlScriptWrapper {
+
+  public InputStream execute(String scriptPath, FileSystem fileSystem, Path pcapPath) throws IOException {
+    ProcessBuilder processBuilder = getProcessBuilder(scriptPath, pcapPath.toUri().getPath());
+    Process process = processBuilder.start();
+    InputStream rawInputStream = getRawInputStream(fileSystem, pcapPath);
+    OutputStream processOutputStream = process.getOutputStream();
+    IOUtils.copy(rawInputStream, processOutputStream);
+    rawInputStream.close();
+    if (process.isAlive()) {
+      // need to close processOutputStream if script doesn't exit with an error
+      processOutputStream.close();
+      return process.getInputStream();
+    } else {
+      String errorMessage = IOUtils.toString(process.getErrorStream(), StandardCharsets.UTF_8);
+      throw new IOException(errorMessage);
+    }
+  }
+
+  protected InputStream getRawInputStream(FileSystem fileSystem, Path path) throws IOException {
+    return fileSystem.open(path);
+  }
+
+  protected ProcessBuilder getProcessBuilder(String... command) {
+    return new ProcessBuilder(command);
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest/src/main/scripts/pcap_to_pdml.sh
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/scripts/pcap_to_pdml.sh b/metron-interface/metron-rest/src/main/scripts/pcap_to_pdml.sh
new file mode 100755
index 0000000..81c3781
--- /dev/null
+++ b/metron-interface/metron-rest/src/main/scripts/pcap_to_pdml.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+#
+tshark -i - -T pdml

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/config/TestConfig.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/config/TestConfig.java b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/config/TestConfig.java
index a5a0236..942ff78 100644
--- a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/config/TestConfig.java
+++ b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/config/TestConfig.java
@@ -51,8 +51,10 @@ import org.apache.metron.job.manager.JobManager;
 import org.apache.metron.rest.RestException;
 import org.apache.metron.rest.mock.MockPcapJob;
 import org.apache.metron.rest.mock.MockPcapJobSupplier;
+import org.apache.metron.rest.mock.MockPcapToPdmlScriptWrapper;
 import org.apache.metron.rest.mock.MockStormCLIClientWrapper;
 import org.apache.metron.rest.mock.MockStormRestTemplate;
+import org.apache.metron.rest.service.impl.PcapToPdmlScriptWrapper;
 import org.apache.metron.rest.service.impl.StormCLIWrapper;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -205,4 +207,9 @@ public class TestConfig {
     mockPcapJobSupplier.setMockPcapJob(mockPcapJob);
     return mockPcapJobSupplier;
   }
+
+  @Bean
+  public PcapToPdmlScriptWrapper pcapToPdmlScriptWrapper() {
+    return new MockPcapToPdmlScriptWrapper();
+  }
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/PcapControllerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/PcapControllerIntegrationTest.java b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/PcapControllerIntegrationTest.java
index 2363204..2fa64cd 100644
--- a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/PcapControllerIntegrationTest.java
+++ b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/PcapControllerIntegrationTest.java
@@ -183,9 +183,6 @@ public class PcapControllerIntegrationTest {
   public void testGetStatus() throws Exception {
     MockPcapJob mockPcapJob = (MockPcapJob) wac.getBean("mockPcapJob");
 
-    this.mockMvc.perform(get(pcapUrl + "/jobId").with(httpBasic(user, password)))
-            .andExpect(status().isNotFound());
-
     mockPcapJob.setStatus(new JobStatus().withJobId("jobId").withState(JobStatus.State.RUNNING));
 
     this.mockMvc.perform(post(pcapUrl + "/fixed").with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(fixedJson))
@@ -226,6 +223,9 @@ public class PcapControllerIntegrationTest {
             .andExpect(status().isOk())
             .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
             .andExpect(jsonPath("$.jobStatus").value("KILLED"));
+
+    this.mockMvc.perform(get(pcapUrl + "/someJobId").with(httpBasic(user, password)))
+            .andExpect(status().isNotFound());
   }
 
   @Test
@@ -233,23 +233,23 @@ public class PcapControllerIntegrationTest {
     MockPcapJob mockPcapJob = (MockPcapJob) wac.getBean("mockPcapJob");
 
     this.mockMvc.perform(get(pcapUrl + "/jobId123").with(httpBasic(user, password)))
-        .andExpect(status().isNotFound());
+            .andExpect(status().isNotFound());
 
     mockPcapJob.setStatus(new JobStatus().withJobId("jobId123").withState(JobStatus.State.RUNNING));
 
     this.mockMvc.perform(post(pcapUrl + "/fixed").with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(fixedJson))
-        .andExpect(status().isOk())
-        .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
-        .andExpect(jsonPath("$.jobId").value("jobId123"))
-        .andExpect(jsonPath("$.jobStatus").value("RUNNING"));
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.jobId").value("jobId123"))
+            .andExpect(jsonPath("$.jobStatus").value("RUNNING"));
 
     mockPcapJob.setStatus(new JobStatus().withJobId("jobId123").withState(JobStatus.State.KILLED));
 
     this.mockMvc.perform(delete(pcapUrl + "/kill/{id}", "jobId123").with(httpBasic(user, password)))
-        .andExpect(status().isOk())
-        .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
-        .andExpect(jsonPath("$.jobId").value("jobId123"))
-        .andExpect(jsonPath("$.jobStatus").value("KILLED"));
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.jobId").value("jobId123"))
+            .andExpect(jsonPath("$.jobStatus").value("KILLED"));
 
     mockPcapJob.setStatus(new JobStatus().withJobId("jobId").withState(JobStatus.State.KILLED));
   }
@@ -259,10 +259,47 @@ public class PcapControllerIntegrationTest {
     MockPcapJob mockPcapJob = (MockPcapJob) wac.getBean("mockPcapJob");
 
     this.mockMvc.perform(get(pcapUrl + "/jobId123").with(httpBasic(user, password)))
-        .andExpect(status().isNotFound());
+            .andExpect(status().isNotFound());
 
     this.mockMvc.perform(delete(pcapUrl + "/kill/{id}", "jobId123").with(httpBasic(user, password)))
-        .andExpect(status().isNotFound());
+            .andExpect(status().isNotFound());
+  }
+
+  @Test
+  public void testGetPdml() throws Exception {
+    MockPcapJob mockPcapJob = (MockPcapJob) wac.getBean("mockPcapJob");
+
+    mockPcapJob.setStatus(new JobStatus().withJobId("jobId").withState(JobStatus.State.RUNNING));
+
+    this.mockMvc.perform(post(pcapUrl + "/fixed").with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(fixedJson))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.jobId").value("jobId"))
+            .andExpect(jsonPath("$.jobStatus").value("RUNNING"));
+
+    Pageable<Path> pageable = new PcapPages(Arrays.asList(new Path("./target")));
+    mockPcapJob.setIsDone(true);
+    mockPcapJob.setPageable(pageable);
+
+    this.mockMvc.perform(get(pcapUrl + "/jobId/pdml?page=1").with(httpBasic(user, password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.version").value("0"))
+            .andExpect(jsonPath("$.creator").value("wireshark/2.6.1"))
+            .andExpect(jsonPath("$.time").value("Thu Jun 28 14:14:38 2018"))
+            .andExpect(jsonPath("$.captureFile").value("/tmp/pcap-data-201806272004-289365c53112438ca55ea047e13a12a5+0001.pcap"))
+            .andExpect(jsonPath("$.packets[0].protos[0].name").value("geninfo"))
+            .andExpect(jsonPath("$.packets[0].protos[0].fields[0].name").value("num"))
+            .andExpect(jsonPath("$.packets[0].protos[1].name").value("ip"))
+            .andExpect(jsonPath("$.packets[0].protos[1].fields[0].name").value("ip.addr"))
+    ;
+
+    this.mockMvc.perform(get(pcapUrl + "/jobId/pdml?page=0").with(httpBasic(user, password)))
+            .andExpect(status().isNotFound());
+
+    this.mockMvc.perform(get(pcapUrl + "/jobId/pdml?page=2").with(httpBasic(user, password)))
+            .andExpect(status().isNotFound());
   }
 
+
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/mock/MockPcapToPdmlScriptWrapper.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/mock/MockPcapToPdmlScriptWrapper.java b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/mock/MockPcapToPdmlScriptWrapper.java
new file mode 100644
index 0000000..940648c
--- /dev/null
+++ b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/mock/MockPcapToPdmlScriptWrapper.java
@@ -0,0 +1,55 @@
+/*
+ * 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.rest.mock;
+
+import org.adrianwalker.multilinestring.Multiline;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.metron.rest.service.impl.PcapToPdmlScriptWrapper;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class MockPcapToPdmlScriptWrapper extends PcapToPdmlScriptWrapper {
+
+  /**
+   *<?xml version="1.0" encoding="utf-8"?>
+   *<?xml-stylesheet type="text/xsl" href="pdml2html.xsl"?>
+   *<pdml version="0" creator="wireshark/2.6.1" time="Thu Jun 28 14:14:38 2018" capture_file="/tmp/pcap-data-201806272004-289365c53112438ca55ea047e13a12a5+0001.pcap">
+   *<packet>
+   *<proto name="geninfo" pos="0" showname="General information" size="722" hide="no">
+   *<field name="num" pos="0" show="1" showname="Number" value="1" size="722"/>
+   *</proto>
+   *<proto name="ip" showname="Internet Protocol Version 4, Src: 192.168.66.1, Dst: 192.168.66.121" size="20" pos="14" hide="yes">
+   *<field name="ip.addr" showname="Source or Destination Address: 192.168.66.121" hide="yes" size="4" pos="30" show="192.168.66.121" value="c0a84279"/>
+   *<field name="ip.flags" showname="Flags: 0x4000, Don&#x27;t fragment" size="2" pos="20" show="0x00004000" value="4000">
+   *<field name="ip.flags.mf" showname="..0. .... .... .... = More fragments: Not set" size="2" pos="20" show="0" value="0" unmaskedvalue="4000"/>
+   *</field>
+   *</proto>
+   *</packet>
+   *</pdml>
+   */
+  @Multiline
+  private String pdmlXml;
+
+  @Override
+  public InputStream execute(String scriptPath, FileSystem fileSystem, Path pcapPath) throws IOException {
+    return new ByteArrayInputStream(pdmlXml.getBytes());
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/impl/PcapServiceImplTest.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/impl/PcapServiceImplTest.java b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/impl/PcapServiceImplTest.java
index 8b628b3..d818c77 100644
--- a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/impl/PcapServiceImplTest.java
+++ b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/impl/PcapServiceImplTest.java
@@ -17,25 +17,15 @@
  */
 package org.apache.metron.rest.service.impl;
 
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.powermock.api.mockito.PowerMockito.doReturn;
-
-import java.util.HashMap;
-import java.util.Map;
+import org.adrianwalker.multilinestring.Multiline;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
 import org.apache.metron.common.Constants;
+import org.apache.metron.common.utils.JSONUtils;
 import org.apache.metron.job.JobException;
 import org.apache.metron.job.JobNotFoundException;
 import org.apache.metron.job.JobStatus;
-import org.apache.metron.job.JobStatus.State;
 import org.apache.metron.job.Pageable;
 import org.apache.metron.job.manager.InMemoryJobManager;
 import org.apache.metron.job.manager.JobManager;
@@ -48,33 +38,154 @@ import org.apache.metron.rest.mock.MockPcapJob;
 import org.apache.metron.rest.mock.MockPcapJobSupplier;
 import org.apache.metron.rest.model.pcap.FixedPcapRequest;
 import org.apache.metron.rest.model.pcap.PcapStatus;
+import org.apache.metron.rest.model.pcap.Pdml;
 import org.hamcrest.CoreMatchers;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
 import org.springframework.core.env.Environment;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.anyVararg;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.powermock.api.mockito.PowerMockito.doReturn;
+import static org.powermock.api.mockito.PowerMockito.whenNew;
+
 @SuppressWarnings("ALL")
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({PcapToPdmlScriptWrapper.class, ProcessBuilder.class})
 public class PcapServiceImplTest {
   @Rule
   public final ExpectedException exception = ExpectedException.none();
 
+  /**
+   *<?xml version="1.0" encoding="utf-8"?>
+   *<?xml-stylesheet type="text/xsl" href="pdml2html.xsl"?>
+   *<pdml version="0" creator="wireshark/2.6.1" time="Thu Jun 28 14:14:38 2018" capture_file="/tmp/pcap-data-201806272004-289365c53112438ca55ea047e13a12a5+0001.pcap">
+   *<packet>
+   *<proto name="geninfo" pos="0" showname="General information" size="722" hide="no">
+   *<field name="num" pos="0" show="1" showname="Number" value="1" size="722"/>
+   *</proto>
+   *<proto name="ip" showname="Internet Protocol Version 4, Src: 192.168.66.1, Dst: 192.168.66.121" size="20" pos="14" hide="yes">
+   *<field name="ip.addr" showname="Source or Destination Address: 192.168.66.121" hide="yes" size="4" pos="30" show="192.168.66.121" value="c0a84279"/>
+   *<field name="ip.flags" showname="Flags: 0x4000, Don&#x27;t fragment" size="2" pos="20" show="0x00004000" value="4000">
+   *<field name="ip.flags.mf" showname="..0. .... .... .... = More fragments: Not set" size="2" pos="20" show="0" value="0" unmaskedvalue="4000"/>
+   *</field>
+   *</proto>
+   *</packet>
+   *</pdml>
+   */
+  @Multiline
+  private String pdmlXml;
+
+  /**
+   *{
+   "version": "0",
+   "creator": "wireshark/2.6.1",
+   "time": "Thu Jun 28 14:14:38 2018",
+   "captureFile": "/tmp/pcap-data-201806272004-289365c53112438ca55ea047e13a12a5+0001.pcap",
+   "packets": [
+   {
+   "protos": [
+   {
+   "name": "geninfo",
+   "pos": "0",
+   "showname": "General information",
+   "size": "722",
+   "hide": "no",
+   "fields": [
+   {
+   "name": "num",
+   "pos": "0",
+   "showname": "Number",
+   "size": "722",
+   "value": "1",
+   "show": "1"
+   }
+   ]
+   },
+   {
+   "name": "ip",
+   "pos": "14",
+   "showname": "Internet Protocol Version 4, Src: 192.168.66.1, Dst: 192.168.66.121",
+   "size": "20",
+   "hide": "yes",
+   "fields": [
+   {
+   "name": "ip.addr",
+   "pos": "30",
+   "showname": "Source or Destination Address: 192.168.66.121",
+   "size": "4",
+   "value": "c0a84279",
+   "show": "192.168.66.121",
+   "hide": "yes"
+   },
+   {
+   "name": "ip.flags",
+   "pos": "20",
+   "showname": "Flags: 0x4000, Don't fragment",
+   "size": "2",
+   "value": "4000",
+   "show": "0x00004000",
+   "fields": [
+   {
+   "name": "ip.flags.mf",
+   "pos": "20",
+   "showname": "..0. .... .... .... = More fragments: Not set",
+   "size": "2",
+   "value": "0",
+   "show": "0",
+   "unmaskedvalue": "4000"
+   }
+   ]
+   }
+   ]
+   }
+   ]
+   }
+   ]
+   }
+   */
+  @Multiline
+  private String expectedPdml;
+
   Environment environment;
   Configuration configuration;
   MockPcapJobSupplier mockPcapJobSupplier;
+  PcapToPdmlScriptWrapper pcapToPdmlScriptWrapper;
 
   @Before
   public void setUp() throws Exception {
     environment = mock(Environment.class);
     configuration = mock(Configuration.class);
     mockPcapJobSupplier = new MockPcapJobSupplier();
+    pcapToPdmlScriptWrapper = new PcapToPdmlScriptWrapper();
 
     when(environment.getProperty(MetronRestConstants.PCAP_BASE_PATH_SPRING_PROPERTY)).thenReturn("/base/path");
     when(environment.getProperty(MetronRestConstants.PCAP_BASE_INTERIM_RESULT_PATH_SPRING_PROPERTY)).thenReturn("/base/interim/result/path");
     when(environment.getProperty(MetronRestConstants.PCAP_FINAL_OUTPUT_PATH_SPRING_PROPERTY)).thenReturn("/final/output/path");
     when(environment.getProperty(MetronRestConstants.PCAP_PAGE_SIZE_SPRING_PROPERTY)).thenReturn("100");
+    when(environment.getProperty(MetronRestConstants.PCAP_PDML_SCRIPT_PATH_SPRING_PROPERTY)).thenReturn("/path/to/pdml/script");
   }
 
   @Test
@@ -97,7 +208,7 @@ public class PcapServiceImplTest {
     mockPcapJobSupplier.setMockPcapJob(mockPcapJob);
     JobManager jobManager = new InMemoryJobManager<>();
 
-    PcapServiceImpl pcapService = spy(new PcapServiceImpl(environment, configuration, mockPcapJobSupplier, jobManager));
+    PcapServiceImpl pcapService = spy(new PcapServiceImpl(environment, configuration, mockPcapJobSupplier, jobManager, pcapToPdmlScriptWrapper));
     FileSystem fileSystem = mock(FileSystem.class);
     doReturn(fileSystem).when(pcapService).getFileSystem();
     mockPcapJob.setStatus(new JobStatus()
@@ -149,7 +260,7 @@ public class PcapServiceImplTest {
     mockPcapJobSupplier.setMockPcapJob(mockPcapJob);
     JobManager jobManager = new InMemoryJobManager<>();
 
-    PcapServiceImpl pcapService = spy(new PcapServiceImpl(environment, configuration, mockPcapJobSupplier, jobManager));
+    PcapServiceImpl pcapService = spy(new PcapServiceImpl(environment, configuration, mockPcapJobSupplier, jobManager, pcapToPdmlScriptWrapper));
     FileSystem fileSystem = mock(FileSystem.class);
     doReturn(fileSystem).when(pcapService).getFileSystem();
     mockPcapJob.setStatus(new JobStatus()
@@ -184,7 +295,7 @@ public class PcapServiceImplTest {
     FixedPcapRequest fixedPcapRequest = new FixedPcapRequest();
     JobManager jobManager = mock(JobManager.class);
     PcapJobSupplier pcapJobSupplier = new PcapJobSupplier();
-    PcapServiceImpl pcapService = spy(new PcapServiceImpl(environment, configuration, pcapJobSupplier, jobManager));
+    PcapServiceImpl pcapService = spy(new PcapServiceImpl(environment, configuration, pcapJobSupplier, jobManager, pcapToPdmlScriptWrapper));
     FileSystem fileSystem = mock(FileSystem.class);
     doReturn(fileSystem).when(pcapService).getFileSystem();
     when(jobManager.submit(pcapJobSupplier, "user")).thenThrow(new JobException("some job exception"));
@@ -208,7 +319,7 @@ public class PcapServiceImplTest {
     when(mockPcapJob.get()).thenReturn(pageable);
     when(jobManager.getJob("user", "jobId")).thenReturn(mockPcapJob);
 
-    PcapServiceImpl pcapService = new PcapServiceImpl(environment, configuration, mockPcapJobSupplier, jobManager);
+    PcapServiceImpl pcapService = new PcapServiceImpl(environment, configuration, mockPcapJobSupplier, jobManager, pcapToPdmlScriptWrapper);
     PcapStatus expectedPcapStatus = new PcapStatus();
     expectedPcapStatus.setJobId("jobId");
     expectedPcapStatus.setJobStatus(JobStatus.State.SUCCEEDED.name());
@@ -222,7 +333,7 @@ public class PcapServiceImplTest {
   @Test
   public void getStatusShouldReturnNullOnMissingStatus() throws Exception {
     JobManager jobManager = new InMemoryJobManager();
-    PcapServiceImpl pcapService = new PcapServiceImpl(environment, configuration, new PcapJobSupplier(), jobManager);
+    PcapServiceImpl pcapService = new PcapServiceImpl(environment, configuration, new PcapJobSupplier(), jobManager, pcapToPdmlScriptWrapper);
 
     Assert.assertNull(pcapService.getJobStatus("user", "jobId"));
   }
@@ -235,7 +346,7 @@ public class PcapServiceImplTest {
     JobManager jobManager = mock(JobManager.class);
     when(jobManager.getJob("user", "jobId")).thenThrow(new JobException("some job exception"));
 
-    PcapServiceImpl pcapService = new PcapServiceImpl(environment, configuration, new PcapJobSupplier(), jobManager);
+    PcapServiceImpl pcapService = new PcapServiceImpl(environment, configuration, new PcapJobSupplier(), jobManager, pcapToPdmlScriptWrapper);
     pcapService.getJobStatus("user", "jobId");
   }
 
@@ -244,10 +355,10 @@ public class PcapServiceImplTest {
     MockPcapJob mockPcapJob = mock(MockPcapJob.class);
     JobManager jobManager = mock(JobManager.class);
     JobStatus actualJobStatus = new JobStatus()
-        .withJobId("jobId")
-        .withState(State.KILLED)
-        .withDescription("description")
-        .withPercentComplete(100.0);
+            .withJobId("jobId")
+            .withState(JobStatus.State.KILLED)
+            .withDescription("description")
+            .withPercentComplete(100.0);
     Pageable pageable = mock(Pageable.class);
     when(pageable.getSize()).thenReturn(0);
     when(mockPcapJob.getStatus()).thenReturn(actualJobStatus);
@@ -255,10 +366,10 @@ public class PcapServiceImplTest {
     when(mockPcapJob.get()).thenReturn(pageable);
     when(jobManager.getJob("user", "jobId")).thenReturn(mockPcapJob);
 
-    PcapServiceImpl pcapService = new PcapServiceImpl(environment, configuration, mockPcapJobSupplier, jobManager);
+    PcapServiceImpl pcapService = new PcapServiceImpl(environment, configuration, mockPcapJobSupplier, jobManager, pcapToPdmlScriptWrapper);
     PcapStatus status = pcapService.killJob("user", "jobId");
     verify(jobManager, times(1)).killJob("user", "jobId");
-    assertThat(status.getJobStatus(), CoreMatchers.equalTo(State.KILLED.toString()));
+    assertThat(status.getJobStatus(), CoreMatchers.equalTo(JobStatus.State.KILLED.toString()));
   }
 
   @Test
@@ -267,10 +378,97 @@ public class PcapServiceImplTest {
     JobManager jobManager = mock(JobManager.class);
     doThrow(new JobNotFoundException("Not found test exception.")).when(jobManager).killJob("user", "jobId");
 
-    PcapServiceImpl pcapService = new PcapServiceImpl(environment, configuration, mockPcapJobSupplier, jobManager);
+    PcapServiceImpl pcapService = new PcapServiceImpl(environment, configuration, mockPcapJobSupplier, jobManager, pcapToPdmlScriptWrapper);
     PcapStatus status = pcapService.killJob("user", "jobId");
     verify(jobManager, times(1)).killJob("user", "jobId");
     assertNull(status);
   }
 
+  @Test
+  public void getPathShouldProperlyReturnPath() throws Exception {
+    Path actualPath = new Path("/path");
+    MockPcapJob mockPcapJob = mock(MockPcapJob.class);
+    JobManager jobManager = mock(JobManager.class);
+    Pageable pageable = mock(Pageable.class);
+    PcapServiceImpl pcapService = new PcapServiceImpl(environment, configuration, new PcapJobSupplier(), jobManager, pcapToPdmlScriptWrapper);
+
+    when(pageable.getSize()).thenReturn(2);
+    when(mockPcapJob.isDone()).thenReturn(true);
+    when(mockPcapJob.get()).thenReturn(pageable);
+    when(pageable.getPage(0)).thenReturn(actualPath);
+    when(jobManager.getJob("user", "jobId")).thenReturn(mockPcapJob);
+
+    Assert.assertEquals("/path", pcapService.getPath("user", "jobId", 1).toUri().getPath());
+  }
+
+  @Test
+  public void getPathShouldReturnNullOnInvalidPageSize() throws Exception {
+    MockPcapJob mockPcapJob = mock(MockPcapJob.class);
+    JobManager jobManager = mock(JobManager.class);
+    Pageable pageable = mock(Pageable.class);
+    PcapServiceImpl pcapService = new PcapServiceImpl(environment, configuration, new PcapJobSupplier(), jobManager, pcapToPdmlScriptWrapper);
+
+    when(pageable.getSize()).thenReturn(2);
+    when(mockPcapJob.isDone()).thenReturn(true);
+    when(mockPcapJob.get()).thenReturn(pageable);
+    when(jobManager.getJob("user", "jobId")).thenReturn(mockPcapJob);
+
+    Assert.assertNull(pcapService.getPath("user", "jobId", 0));
+    Assert.assertNull(pcapService.getPath("user", "jobId", 3));
+  }
+
+  @Test
+  public void getPdmlShouldGetPdml() throws Exception {
+    Path path = new Path("./target");
+    PcapToPdmlScriptWrapper pcapToPdmlScriptWrapper = spy(new PcapToPdmlScriptWrapper());
+    PcapServiceImpl pcapService = spy(new PcapServiceImpl(environment, configuration, new PcapJobSupplier(), new InMemoryJobManager<>(), pcapToPdmlScriptWrapper));
+    FileSystem fileSystem = mock(FileSystem.class);
+    doReturn(fileSystem).when(pcapService).getFileSystem();
+    when(fileSystem.exists(path)).thenReturn(true);
+    doReturn(path).when(pcapService).getPath("user", "jobId", 1);
+    doReturn(new ByteArrayInputStream(pdmlXml.getBytes())).when(pcapToPdmlScriptWrapper).getRawInputStream(fileSystem, path);
+    ProcessBuilder pb = PowerMockito.mock(ProcessBuilder.class);
+    Process p = PowerMockito.mock(Process.class);
+    OutputStream outputStream = new ByteArrayOutputStream();
+    when(p.getOutputStream()).thenReturn(outputStream);
+    when(p.isAlive()).thenReturn(true);
+    when(p.getInputStream()).thenReturn(new ByteArrayInputStream(pdmlXml.getBytes()));
+    whenNew(ProcessBuilder.class).withParameterTypes(String[].class).withArguments(anyVararg()).thenReturn(pb);
+    PowerMockito.when(pb.start()).thenReturn(p);
+
+    assertEquals(JSONUtils.INSTANCE.load(expectedPdml, Pdml.class), pcapService.getPdml("user", "jobId", 1));
+  }
+
+  @Test
+  public void getPdmlShouldReturnNullOnNonexistentPath() throws Exception {
+    Path path = new Path("/some/path");
+
+    PcapServiceImpl pcapService = spy(new PcapServiceImpl(environment, configuration, new PcapJobSupplier(), new InMemoryJobManager<>(), pcapToPdmlScriptWrapper));
+    FileSystem fileSystem = mock(FileSystem.class);
+    doReturn(fileSystem).when(pcapService).getFileSystem();
+    when(fileSystem.exists(path)).thenReturn(false);
+    doReturn(path).when(pcapService).getPath("user", "jobId", 1);
+
+    assertNull(pcapService.getPdml("user", "jobId", 1));
+  }
+
+  @Test
+  public void getPdmlShouldThrowException() throws Exception {
+    exception.expect(RestException.class);
+    exception.expectMessage("some exception");
+
+    Path path = new Path("./target");
+    PcapToPdmlScriptWrapper pcapToPdmlScriptWrapper = spy(new PcapToPdmlScriptWrapper());
+    PcapServiceImpl pcapService = spy(new PcapServiceImpl(environment, configuration, new PcapJobSupplier(), new InMemoryJobManager<>(), pcapToPdmlScriptWrapper));
+    FileSystem fileSystem = mock(FileSystem.class);
+    doReturn(fileSystem).when(pcapService).getFileSystem();
+    when(fileSystem.exists(path)).thenReturn(true);
+    doReturn(path).when(pcapService).getPath("user", "jobId", 1);
+    ProcessBuilder pb = PowerMockito.mock(ProcessBuilder.class);
+    doReturn(pb).when(pcapToPdmlScriptWrapper).getProcessBuilder("/path/to/pdml/script", "target");
+    PowerMockito.when(pb.start()).thenThrow(new IOException("some exception"));
+
+    pcapService.getPdml("user", "jobId", 1);
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/3e5ef41d/metron-interface/pom.xml
----------------------------------------------------------------------
diff --git a/metron-interface/pom.xml b/metron-interface/pom.xml
index e6ccd2d..c8f863c 100644
--- a/metron-interface/pom.xml
+++ b/metron-interface/pom.xml
@@ -25,6 +25,9 @@
     </parent>
     <description>Interfaces for Metron</description>
     <url>https://metron.apache.org/</url>
+    <properties>
+        <jackson.version>2.9.5</jackson.version>
+    </properties>
     <scm>
         <connection>scm:git:https://git-wip-us.apache.org/repos/asf/metron.git</connection>
         <developerConnection>scm:git:https://git-wip-us.apache.org/repos/asf/metron.git</developerConnection>