http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/main/java/org/apache/metron/bundles/bundle/BundleDetails.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/main/java/org/apache/metron/bundles/bundle/BundleDetails.java 
b/bundles-lib/src/main/java/org/apache/metron/bundles/bundle/BundleDetails.java
new file mode 100644
index 0000000..7813775
--- /dev/null
+++ 
b/bundles-lib/src/main/java/org/apache/metron/bundles/bundle/BundleDetails.java
@@ -0,0 +1,205 @@
+/*
+ * 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.bundles.bundle;
+
+import org.apache.commons.vfs2.FileObject;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import org.apache.commons.vfs2.FileSystemException;
+
+/**
+ * Metadata about a bundle. the coordinates and bundleFile properties are 
required
+ */
+public class BundleDetails {
+
+  private final FileObject bundleFile;
+
+  private final BundleCoordinates coordinates;
+  private final BundleCoordinates dependencyCoordinates;
+
+  private final String buildTag;
+  private final String buildRevision;
+  private final String buildBranch;
+  private final String buildTimestamp;
+  private final String buildJdk;
+  private final String builtBy;
+
+  private BundleDetails(final Builder builder) {
+    this.bundleFile = builder.bundleFile;
+    this.coordinates = builder.coordinates;
+    this.dependencyCoordinates = builder.dependencyCoordinates;
+
+    this.buildTag = builder.buildTag;
+    this.buildRevision = builder.buildRevision;
+    this.buildBranch = builder.buildBranch;
+    this.buildTimestamp = builder.buildTimestamp;
+    this.buildJdk = builder.buildJdk;
+    this.builtBy = builder.builtBy;
+
+    if (this.coordinates == null) {
+      if (this.bundleFile == null) {
+        throw new IllegalStateException("Coordinate cannot be null");
+      } else {
+        throw new IllegalStateException(
+            "Coordinate cannot be null for " + this.bundleFile.getName());
+      }
+    }
+
+    if (this.bundleFile == null) {
+      throw new IllegalStateException("bundleFile cannot be null for " + 
this.coordinates
+          .getId());
+    }
+  }
+
+  public FileObject getBundleFile() {
+    return bundleFile;
+  }
+
+  public BundleCoordinates getCoordinates() {
+    return coordinates;
+  }
+
+  public BundleCoordinates getDependencyCoordinates() {
+    return dependencyCoordinates;
+  }
+
+  public String getBuildTag() {
+    return buildTag;
+  }
+
+  public String getBuildRevision() {
+    return buildRevision;
+  }
+
+  public String getBuildBranch() {
+    return buildBranch;
+  }
+
+  public String getBuildTimestamp() {
+    return buildTimestamp;
+  }
+
+  public String getBuildJdk() {
+    return buildJdk;
+  }
+
+  public String getBuiltBy() {
+    return builtBy;
+  }
+
+  @Override
+  public String toString() {
+    return coordinates.toString();
+  }
+
+  public Date getBuildTimestampDate() {
+    if (buildTimestamp != null && !buildTimestamp.isEmpty()) {
+      try {
+        SimpleDateFormat buildTimestampFormat = new 
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+        Date buildTimestampDate = buildTimestampFormat.parse(buildTimestamp);
+        return buildTimestampDate;
+      } catch (ParseException parseEx) {
+        return null;
+      }
+    } else {
+      return null;
+    }
+  }
+
+  /**
+   * Builder for BundleDetails. The withCoordinates and withBundleFile 
properties are required
+   */
+  public static class Builder {
+
+    private FileObject bundleFile;
+
+    private BundleCoordinates coordinates;
+    private BundleCoordinates dependencyCoordinates;
+
+    private String buildTag;
+    private String buildRevision;
+    private String buildBranch;
+    private String buildTimestamp;
+    private String buildJdk;
+    private String builtBy;
+
+    public Builder withBundleFile(final FileObject bundleFile) {
+      this.bundleFile = bundleFile;
+      return this;
+    }
+
+    public Builder withCoordinates(final BundleCoordinates coordinates) {
+      this.coordinates = coordinates;
+      return this;
+    }
+
+    public Builder withDependencyCoordinates(final BundleCoordinates 
dependencyCoordinates) {
+      this.dependencyCoordinates = dependencyCoordinates;
+      return this;
+    }
+
+    public Builder withBuildTag(final String buildTag) {
+      this.buildTag = buildTag;
+      return this;
+    }
+
+    public Builder withBuildRevision(final String buildRevision) {
+      this.buildRevision = buildRevision;
+      return this;
+    }
+
+    public Builder withBuildBranch(final String buildBranch) {
+      this.buildBranch = buildBranch;
+      return this;
+    }
+
+    public Builder withBuildTimestamp(final String buildTimestamp) {
+      this.buildTimestamp = buildTimestamp;
+      return this;
+    }
+
+    public Builder withBuildJdk(final String buildJdk) {
+      this.buildJdk = buildJdk;
+      return this;
+    }
+
+    public Builder withBuiltBy(final String builtBy) {
+      this.builtBy = builtBy;
+      return this;
+    }
+
+    /**
+     * Builds a BundleDetails instance. withBundleFile and withCoordinates are 
required. An
+     * IllegalStateException will result if they are missing on build()
+     */
+    public BundleDetails build() {
+      try {
+        if (this.bundleFile == null || this.bundleFile.exists() == false) {
+          throw new IllegalStateException("Invalid Bundle File");
+        } else if (this.coordinates == null) {
+          throw new IllegalStateException("Invalid Coordinates");
+        }
+        return new BundleDetails(this);
+      } catch (FileSystemException e) {
+        throw new IllegalStateException(e);
+      }
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/main/java/org/apache/metron/bundles/util/BundleProperties.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/main/java/org/apache/metron/bundles/util/BundleProperties.java
 
b/bundles-lib/src/main/java/org/apache/metron/bundles/util/BundleProperties.java
new file mode 100644
index 0000000..81cbe1a
--- /dev/null
+++ 
b/bundles-lib/src/main/java/org/apache/metron/bundles/util/BundleProperties.java
@@ -0,0 +1,247 @@
+/*
+ * 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.bundles.util;
+
+import org.apache.metron.bundles.bundle.Bundle;
+
+import java.io.*;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.Paths;
+import java.util.*;
+
+/**
+ * The BundleProperties class holds all properties which are needed for 
various values to be
+ * available at runtime. The properties contains keys and values.
+ */
+public abstract class BundleProperties {
+
+  // core properties
+  public static final String PROPERTIES_FILE_PATH = 
"bundle.properties.file.path";
+  public static final String BUNDLE_LIBRARY_DIRECTORY = 
"bundle.library.directory";
+  public static final String BUNDLE_LIBRARY_DIRECTORY_PREFIX = 
"bundle.library.directory.";
+  public static final String ARCHIVE_EXTENSION = "bundle.archive.extension";
+  public static final String META_ID_PREFIX = "bundle.meta.id.prefix";
+  public static final String BUNDLE_EXTENSION_TYPE_PREFIX = 
"bundle.extension.type.";
+
+  // defaults
+  public static final String DEFAULT_ARCHIVE_EXTENSION = "bundle";
+  public static final String DEFAULT_BUNDLE_LIBRARY_DIR = "./lib/";
+  public static final String DEFAULT_META_ID_PREFIX = "Bundle";
+
+  /**
+   * Retrieves the property value for the given property key.
+   *
+   * @param key the key of property value to lookup
+   * @return value of property at given key or null if not found
+   */
+  public abstract String getProperty(String key);
+
+  public abstract void setProperty(String key, String value);
+
+  public abstract void unSetProperty(String key);
+
+  public abstract boolean match(BundleProperties other);
+
+  public abstract void storeProperties(OutputStream outputStream, String 
comments)
+      throws IOException;
+
+  /**
+   * Retrieves all known property keys.
+   *
+   * @return all known property keys
+   */
+  public abstract Set<String> getPropertyKeys();
+
+  public String getProperty(final String key, final String defaultValue) {
+    final String value = getProperty(key);
+    return (value == null || value.trim().isEmpty()) ? defaultValue : value;
+  }
+
+  // getters for core properties //
+
+  private static URI getConcatedDirURI(URI original, String dir) throws 
URISyntaxException {
+    String uri = original.toString();
+    StringBuilder builder = new StringBuilder(uri);
+    if (uri.endsWith("/") == false) {
+      builder.append("/");
+    }
+    builder.append(dir);
+    return new URI(builder.toString());
+  }
+
+  public URI getBundleLibraryDirectory() throws URISyntaxException {
+    String bundleLib = getProperty(BUNDLE_LIBRARY_DIRECTORY);
+      return getURI(bundleLib);
+  }
+
+  public List<URI> getBundleLibraryDirectories() throws URISyntaxException {
+
+    List<URI> bundleLibraryPaths = new ArrayList<>();
+
+    // go through each property
+    for (String propertyName : getPropertyKeys()) {
+      // determine if the property is a bundle library path
+      if (StringUtils.startsWith(propertyName, BUNDLE_LIBRARY_DIRECTORY_PREFIX)
+          || BUNDLE_LIBRARY_DIRECTORY.equals(propertyName)) {
+        // attempt to resolve the path specified
+        String bundleLib = getProperty(propertyName);
+        if (!StringUtils.isBlank(bundleLib)) {
+            bundleLibraryPaths.add(getURI(bundleLib));
+        }
+      }
+    }
+
+    if (bundleLibraryPaths.isEmpty()) {
+      bundleLibraryPaths.add(getURI(DEFAULT_BUNDLE_LIBRARY_DIR));
+    }
+
+    return bundleLibraryPaths;
+  }
+
+  public Map<String, String> getBundleExtensionTypes() {
+    HashMap<String, String> extensionTypeMap = new HashMap<>();
+
+    // go through each property
+    for (String propertyName : getPropertyKeys()) {
+      // determine if the property is an extention type
+      if (StringUtils.startsWith(propertyName, BUNDLE_EXTENSION_TYPE_PREFIX)) {
+        // attempt to resolve class name
+        String className = getProperty(propertyName);
+        if (!StringUtils.isBlank(className)) {
+          // get the extension name
+          String extensionName = StringUtils.substringAfterLast(propertyName, 
".");
+          if (!StringUtils.isBlank(extensionName)) {
+            extensionTypeMap.put(extensionName, className);
+          }
+        }
+      }
+    }
+    return extensionTypeMap;
+  }
+
+  public static URI getURI(String path) throws URISyntaxException {
+    // we may have URI's or paths or relative paths
+    //
+    // if it is not a URI string then use Paths.get().getURI()
+    if (path.matches("^[A-Za-z].*//.*$")) {
+      return new URI(path);
+    }
+    return Paths.get(path).toUri();
+  }
+
+  public String getMetaIdPrefix() {
+    return getProperty(META_ID_PREFIX, DEFAULT_META_ID_PREFIX);
+  }
+
+  public String getArchiveExtension() {
+    return getProperty(ARCHIVE_EXTENSION, DEFAULT_ARCHIVE_EXTENSION);
+  }
+
+  public static BundleProperties createBasicBundleProperties(final InputStream 
inStream,
+      final Map<String, String> additionalProperties) {
+    final Map<String, String> addProps =
+        (additionalProperties == null) ? new HashMap<>() : 
additionalProperties;
+    final Properties properties = new Properties();
+    try {
+      properties.load(inStream);
+    } catch (final Exception ex) {
+      throw new RuntimeException("Cannot load properties file due to "
+          + ex.getLocalizedMessage(), ex);
+    } finally {
+      if (null != inStream) {
+        try {
+          inStream.close();
+        } catch (final Exception ex) {
+          /**
+           * do nothing *
+           */
+        }
+      }
+    }
+    addProps.entrySet().stream().forEach((entry) -> {
+      properties.setProperty(entry.getKey(), entry.getValue());
+    });
+    return new BundleProperties() {
+      @Override
+      public String getProperty(String key) {
+        return properties.getProperty(key);
+      }
+
+      @Override
+      public Set<String> getPropertyKeys() {
+        return properties.stringPropertyNames();
+      }
+
+      @Override
+      public void setProperty(String key, String value) {
+        properties.setProperty(key, value);
+      }
+
+      @Override
+      public void unSetProperty(String key) { properties.remove(key);}
+
+      @Override
+      public boolean match(BundleProperties other){
+        return properties.equals(other);
+      }
+
+      @Override
+      public void storeProperties(OutputStream outputStream, String comments) 
throws IOException {
+        properties.store(outputStream, comments);
+      }
+    };
+
+  }
+
+  public static BundleProperties createBasicBundleProperties(final String 
propertiesFilePath,
+      final Map<String, String> additionalProperties) {
+    final String bundlePropertiesFilePath = (propertiesFilePath == null)
+        ? System.getProperty(BundleProperties.PROPERTIES_FILE_PATH)
+        : propertiesFilePath;
+    if (bundlePropertiesFilePath != null) {
+      final File propertiesFile = new File(bundlePropertiesFilePath.trim());
+      if (!propertiesFile.exists()) {
+        throw new RuntimeException("Properties file doesn't exist \'"
+            + propertiesFile.getAbsolutePath() + "\'");
+      }
+      if (!propertiesFile.canRead()) {
+        throw new RuntimeException("Properties file exists but cannot be read 
\'"
+            + propertiesFile.getAbsolutePath() + "\'");
+      }
+      InputStream inStream = null;
+      try {
+        inStream = new BufferedInputStream(new 
FileInputStream(propertiesFile));
+        return createBasicBundleProperties(inStream, additionalProperties);
+      } catch (final Exception ex) {
+        throw new RuntimeException("Cannot load properties file due to "
+            + ex.getLocalizedMessage(), ex);
+      } finally {
+        if (null != inStream) {
+          try {
+            inStream.close();
+          } catch (final Exception ex) {
+            /**
+             * do nothing *
+             */
+          }
+        }
+      }
+    }
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/main/java/org/apache/metron/bundles/util/BundleSelector.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/main/java/org/apache/metron/bundles/util/BundleSelector.java 
b/bundles-lib/src/main/java/org/apache/metron/bundles/util/BundleSelector.java
new file mode 100644
index 0000000..ba0753e
--- /dev/null
+++ 
b/bundles-lib/src/main/java/org/apache/metron/bundles/util/BundleSelector.java
@@ -0,0 +1,48 @@
+/*
+ * 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.bundles.util;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.vfs2.FileSelectInfo;
+import org.apache.commons.vfs2.FileSelector;
+
+public class BundleSelector implements FileSelector{
+
+  private String archiveExtension;
+  public BundleSelector(){
+    this(BundleProperties.DEFAULT_ARCHIVE_EXTENSION);
+  }
+
+  public BundleSelector(String archiveExtension){
+    if(StringUtils.isEmpty(archiveExtension)){
+      this.archiveExtension = BundleProperties.DEFAULT_ARCHIVE_EXTENSION;
+    }
+    this.archiveExtension = archiveExtension;
+  }
+
+  @Override
+  public boolean includeFile(FileSelectInfo fileSelectInfo) throws Exception {
+    final String nameToTest = 
fileSelectInfo.getFile().getName().getExtension();
+    return nameToTest.equals(archiveExtension) && 
fileSelectInfo.getFile().isFile();
+  }
+
+  @Override
+  public boolean traverseDescendents(FileSelectInfo fileSelectInfo) throws 
Exception {
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/main/java/org/apache/metron/bundles/util/BundleUtil.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/main/java/org/apache/metron/bundles/util/BundleUtil.java 
b/bundles-lib/src/main/java/org/apache/metron/bundles/util/BundleUtil.java
new file mode 100644
index 0000000..8c90a87
--- /dev/null
+++ b/bundles-lib/src/main/java/org/apache/metron/bundles/util/BundleUtil.java
@@ -0,0 +1,145 @@
+/*
+ * 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.bundles.util;
+
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSystemException;
+import org.apache.metron.bundles.BundleManifestEntry;
+import org.apache.metron.bundles.bundle.BundleCoordinates;
+import org.apache.metron.bundles.bundle.BundleDetails;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+public class BundleUtil {
+
+    /**
+     * Creates a BundleDetails from the given Bundle working directory.
+     *
+     * @param bundleDirectory the directory of an exploded Bundle which 
contains a META-INF/MANIFEST.MF
+     *
+     * @return the BundleDetails constructed from the information in 
META-INF/MANIFEST.MF
+     */
+    public static BundleDetails fromBundleTestDirectory(final FileObject 
bundleDirectory, BundleProperties props) throws FileSystemException, 
IllegalStateException {
+        if (bundleDirectory == null) {
+            throw new IllegalArgumentException("Bundle Directory cannot be 
null");
+        }
+
+        final FileObject manifestFile = 
bundleDirectory.resolveFile("META-INF/MANIFEST.MF");
+        try (final InputStream fis = 
manifestFile.getContent().getInputStream()) {
+            final Manifest manifest = new Manifest(fis);
+
+            final Attributes attributes = manifest.getMainAttributes();
+            final String prefix = props.getMetaIdPrefix();
+            final BundleDetails.Builder builder = new BundleDetails.Builder();
+
+            // NOTE there is no File here
+            builder.withBundleFile(bundleDirectory);
+
+            final String group = attributes.getValue(prefix + 
BundleManifestEntry.PRE_GROUP.getManifestName());
+            final String id = attributes.getValue(prefix + 
BundleManifestEntry.PRE_ID.getManifestName());
+            final String version = attributes.getValue(prefix + 
BundleManifestEntry.PRE_VERSION.getManifestName());
+            builder.withCoordinates(new BundleCoordinates(group, id, version));
+
+            final String dependencyGroup = attributes.getValue(prefix + 
BundleManifestEntry.PRE_DEPENDENCY_GROUP.getManifestName());
+            final String dependencyId = attributes.getValue(prefix + 
BundleManifestEntry.PRE_DEPENDENCY_ID.getManifestName());
+            final String dependencyVersion = attributes.getValue(prefix + 
BundleManifestEntry.PRE_DEPENDENCY_VERSION.getManifestName());
+            if (!StringUtils.isBlank(dependencyId)) {
+                builder.withDependencyCoordinates(new 
BundleCoordinates(dependencyGroup, dependencyId, dependencyVersion));
+            }
+
+            
builder.withBuildBranch(attributes.getValue(BundleManifestEntry.BUILD_BRANCH.getManifestName()));
+            
builder.withBuildTag(attributes.getValue(BundleManifestEntry.BUILD_TAG.getManifestName()));
+            
builder.withBuildRevision(attributes.getValue(BundleManifestEntry.BUILD_REVISION.getManifestName()));
+            
builder.withBuildTimestamp(attributes.getValue(BundleManifestEntry.BUILD_TIMESTAMP.getManifestName()));
+            
builder.withBuildJdk(attributes.getValue(BundleManifestEntry.BUILD_JDK.getManifestName()));
+            
builder.withBuiltBy(attributes.getValue(BundleManifestEntry.BUILT_BY.getManifestName()));
+
+            return builder.build();
+        }catch(IOException ioe){
+            throw new FileSystemException("failed reading manifest file " + 
manifestFile.getURL(),ioe);
+        }
+    }
+
+    /**
+     * Creates a BundleDetails from the given Bundle working directory.
+     *
+     * @param bundleFile the  Bundle which contains a META-INF/MANIFEST.MF
+     *
+     * @return the BundleDetails constructed from the information in 
META-INF/MANIFEST.MF
+     */
+    public static BundleDetails fromBundleFile(final FileObject bundleFile, 
BundleProperties props) throws FileSystemException, IllegalStateException {
+        if (bundleFile == null) {
+            throw new IllegalArgumentException("Bundle Directory cannot be 
null");
+        }
+
+        FileObject bundleFileSystem = 
bundleFile.getFileSystem().getFileSystemManager().createFileSystem(bundleFile);
+        final FileObject manifestFile = 
bundleFileSystem.resolveFile("META-INF/MANIFEST.MF");
+        try (final InputStream fis = 
manifestFile.getContent().getInputStream()) {
+            final Manifest manifest = new Manifest(fis);
+
+            final Attributes attributes = manifest.getMainAttributes();
+            final String prefix = props.getMetaIdPrefix();
+            final BundleDetails.Builder builder = new BundleDetails.Builder();
+            builder.withBundleFile(bundleFile);
+
+            final String group = attributes.getValue(prefix + 
BundleManifestEntry.PRE_GROUP.getManifestName());
+            final String id = attributes.getValue(prefix + 
BundleManifestEntry.PRE_ID.getManifestName());
+            final String version = attributes.getValue(prefix + 
BundleManifestEntry.PRE_VERSION.getManifestName());
+            builder.withCoordinates(new BundleCoordinates(group, id, version));
+
+            final String dependencyGroup = attributes.getValue(prefix + 
BundleManifestEntry.PRE_DEPENDENCY_GROUP.getManifestName());
+            final String dependencyId = attributes.getValue(prefix + 
BundleManifestEntry.PRE_DEPENDENCY_ID.getManifestName());
+            final String dependencyVersion = attributes.getValue(prefix + 
BundleManifestEntry.PRE_DEPENDENCY_VERSION.getManifestName());
+            if (!StringUtils.isBlank(dependencyId)) {
+                builder.withDependencyCoordinates(new 
BundleCoordinates(dependencyGroup, dependencyId, dependencyVersion));
+            }
+
+            
builder.withBuildBranch(attributes.getValue(BundleManifestEntry.BUILD_BRANCH.getManifestName()));
+            
builder.withBuildTag(attributes.getValue(BundleManifestEntry.BUILD_TAG.getManifestName()));
+            
builder.withBuildRevision(attributes.getValue(BundleManifestEntry.BUILD_REVISION.getManifestName()));
+            
builder.withBuildTimestamp(attributes.getValue(BundleManifestEntry.BUILD_TIMESTAMP.getManifestName()));
+            
builder.withBuildJdk(attributes.getValue(BundleManifestEntry.BUILD_JDK.getManifestName()));
+            
builder.withBuiltBy(attributes.getValue(BundleManifestEntry.BUILT_BY.getManifestName()));
+
+            return builder.build();
+        }catch(IOException ioe){
+            throw new FileSystemException("failed reading manifest file " + 
manifestFile.getURL(),ioe);
+        }
+    }
+
+    public static BundleCoordinates coordinateFromBundleFile(final FileObject 
bundleFile, BundleProperties props) throws FileSystemException{
+        FileObject bundleFileSystem = 
bundleFile.getFileSystem().getFileSystemManager().createFileSystem(bundleFile);
+        final FileObject manifestFile = 
bundleFileSystem.resolveFile("META-INF/MANIFEST.MF");
+        try (final InputStream fis = 
manifestFile.getContent().getInputStream()) {
+            final Manifest manifest = new Manifest(fis);
+
+            final Attributes attributes = manifest.getMainAttributes();
+            final String prefix = props.getMetaIdPrefix();
+
+            final String bundleId = attributes.getValue(prefix + 
BundleManifestEntry.PRE_ID.getManifestName());
+            final String groupId = attributes.getValue(prefix + 
BundleManifestEntry.PRE_GROUP.getManifestName());
+            final String version = attributes.getValue(prefix + 
BundleManifestEntry.PRE_VERSION.getManifestName());
+            return new BundleCoordinates(groupId,bundleId,version);
+        }catch(IOException ioe){
+            throw new FileSystemException("failed reading manifest file " + 
manifestFile.getURL(),ioe);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/main/java/org/apache/metron/bundles/util/DummyFileObject.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/main/java/org/apache/metron/bundles/util/DummyFileObject.java 
b/bundles-lib/src/main/java/org/apache/metron/bundles/util/DummyFileObject.java
new file mode 100644
index 0000000..044358f
--- /dev/null
+++ 
b/bundles-lib/src/main/java/org/apache/metron/bundles/util/DummyFileObject.java
@@ -0,0 +1,230 @@
+/*
+ * 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.bundles.util;
+
+import java.net.URL;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.commons.vfs2.FileContent;
+import org.apache.commons.vfs2.FileName;
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSelector;
+import org.apache.commons.vfs2.FileSystem;
+import org.apache.commons.vfs2.FileSystemException;
+import org.apache.commons.vfs2.FileType;
+import org.apache.commons.vfs2.NameScope;
+import org.apache.commons.vfs2.operations.FileOperations;
+
+/**
+ * This is a dummy FileObject Implementation
+ * It will return true if exists() is called
+ */
+public class DummyFileObject implements FileObject{
+
+  @Override
+  public boolean canRenameTo(FileObject fileObject) {
+    return false;
+  }
+
+  @Override
+  public void close() throws FileSystemException {
+
+  }
+
+  @Override
+  public void copyFrom(FileObject fileObject, FileSelector fileSelector)
+      throws FileSystemException {
+
+  }
+
+  @Override
+  public void createFile() throws FileSystemException {
+
+  }
+
+  @Override
+  public void createFolder() throws FileSystemException {
+
+  }
+
+  @Override
+  public boolean delete() throws FileSystemException {
+    return false;
+  }
+
+  @Override
+  public int delete(FileSelector fileSelector) throws FileSystemException {
+    return 0;
+  }
+
+  @Override
+  public int deleteAll() throws FileSystemException {
+    return 0;
+  }
+
+  @Override
+  public boolean exists() throws FileSystemException {
+    return true;
+  }
+
+  @Override
+  public FileObject[] findFiles(FileSelector fileSelector) throws 
FileSystemException {
+    return new FileObject[0];
+  }
+
+  @Override
+  public void findFiles(FileSelector fileSelector, boolean b, List<FileObject> 
list)
+      throws FileSystemException {
+
+  }
+
+  @Override
+  public FileObject getChild(String s) throws FileSystemException {
+    return null;
+  }
+
+  @Override
+  public FileObject[] getChildren() throws FileSystemException {
+    return new FileObject[0];
+  }
+
+  @Override
+  public FileContent getContent() throws FileSystemException {
+    return null;
+  }
+
+  @Override
+  public FileOperations getFileOperations() throws FileSystemException {
+    return null;
+  }
+
+  @Override
+  public FileSystem getFileSystem() {
+    return null;
+  }
+
+  @Override
+  public FileName getName() {
+    return null;
+  }
+
+  @Override
+  public FileObject getParent() throws FileSystemException {
+    return null;
+  }
+
+  @Override
+  public String getPublicURIString() {
+    return null;
+  }
+
+  @Override
+  public FileType getType() throws FileSystemException {
+    return null;
+  }
+
+  @Override
+  public URL getURL() throws FileSystemException {
+    return null;
+  }
+
+  @Override
+  public boolean isAttached() {
+    return false;
+  }
+
+  @Override
+  public boolean isContentOpen() {
+    return false;
+  }
+
+  @Override
+  public boolean isExecutable() throws FileSystemException {
+    return false;
+  }
+
+  @Override
+  public boolean isFile() throws FileSystemException {
+    return false;
+  }
+
+  @Override
+  public boolean isFolder() throws FileSystemException {
+    return false;
+  }
+
+  @Override
+  public boolean isHidden() throws FileSystemException {
+    return false;
+  }
+
+  @Override
+  public boolean isReadable() throws FileSystemException {
+    return false;
+  }
+
+  @Override
+  public boolean isWriteable() throws FileSystemException {
+    return false;
+  }
+
+  @Override
+  public void moveTo(FileObject fileObject) throws FileSystemException {
+
+  }
+
+  @Override
+  public void refresh() throws FileSystemException {
+
+  }
+
+  @Override
+  public FileObject resolveFile(String s) throws FileSystemException {
+    return null;
+  }
+
+  @Override
+  public FileObject resolveFile(String s, NameScope nameScope) throws 
FileSystemException {
+    return null;
+  }
+
+  @Override
+  public boolean setExecutable(boolean b, boolean b1) throws 
FileSystemException {
+    return false;
+  }
+
+  @Override
+  public boolean setReadable(boolean b, boolean b1) throws FileSystemException 
{
+    return false;
+  }
+
+  @Override
+  public boolean setWritable(boolean b, boolean b1) throws FileSystemException 
{
+    return false;
+  }
+
+  @Override
+  public int compareTo(FileObject o) {
+    return 0;
+  }
+
+  @Override
+  public Iterator<FileObject> iterator() {
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/main/java/org/apache/metron/bundles/util/FileSystemManagerFactory.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/main/java/org/apache/metron/bundles/util/FileSystemManagerFactory.java
 
b/bundles-lib/src/main/java/org/apache/metron/bundles/util/FileSystemManagerFactory.java
new file mode 100644
index 0000000..ec800df
--- /dev/null
+++ 
b/bundles-lib/src/main/java/org/apache/metron/bundles/util/FileSystemManagerFactory.java
@@ -0,0 +1,87 @@
+/**
+ * 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.bundles.util;
+
+import java.lang.invoke.MethodHandles;
+import org.apache.accumulo.start.classloader.vfs.UniqueFileReplicator;
+import org.apache.commons.vfs2.*;
+import org.apache.commons.vfs2.cache.SoftRefFilesCache;
+import org.apache.commons.vfs2.impl.DefaultFileSystemManager;
+import org.apache.commons.vfs2.impl.FileContentInfoFilenameFactory;
+import org.apache.commons.vfs2.provider.hdfs.HdfsFileProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+
+public class FileSystemManagerFactory {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+  /**
+   * Create a FileSystem manager suitable for our purposes.
+   * This manager supports files of the following types by default:
+   * * jar
+   * * HDFS
+   * * file
+   *
+   * @return
+   * @throws FileSystemException
+   */
+  public static FileSystemManager createFileSystemManager() throws 
FileSystemException {
+    return createFileSystemManager(null);
+  }
+
+  /**
+   * Create a FileSystem manager suitable for our purposes.
+   * This manager supports files of the following types by default:
+   * * jar
+   * * HDFS
+   * * file
+   *
+   * Other jar types can be supported through the jarExtensionToRegister 
parameter
+   *
+   * @param jarExtensionsToRegister Other extensions to jar compatible files
+   * @return
+   * @throws FileSystemException
+   */
+  public static FileSystemManager createFileSystemManager(String[] 
jarExtensionsToRegister) throws FileSystemException {
+    DefaultFileSystemManager vfs = new DefaultFileSystemManager();
+
+    if (jarExtensionsToRegister != null && jarExtensionsToRegister.length > 0) 
{
+      for (String jarExtensionToRegister : jarExtensionsToRegister) {
+        if (!StringUtils.isBlank(jarExtensionToRegister)) {
+          vfs.addExtensionMap(jarExtensionToRegister, "jar");
+          vfs.addProvider(jarExtensionToRegister,
+              new org.apache.commons.vfs2.provider.jar.JarFileProvider());
+        }
+      }
+    }
+
+    vfs.addProvider("file", new 
org.apache.commons.vfs2.provider.local.DefaultLocalFileProvider());
+    vfs.addProvider("jar", new 
org.apache.commons.vfs2.provider.jar.JarFileProvider());
+    vfs.addProvider("hdfs", new HdfsFileProvider());
+    vfs.addExtensionMap("jar", "jar");
+
+    vfs.setFileContentInfoFactory(new FileContentInfoFilenameFactory());
+    vfs.setFilesCache(new SoftRefFilesCache());
+    vfs.setReplicator(new UniqueFileReplicator(new 
File(System.getProperty("java.io.tmpdir"))));
+    vfs.setCacheStrategy(CacheStrategy.ON_RESOLVE);
+    vfs.init();
+    return vfs;
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/main/java/org/apache/metron/bundles/util/FileUtils.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/main/java/org/apache/metron/bundles/util/FileUtils.java 
b/bundles-lib/src/main/java/org/apache/metron/bundles/util/FileUtils.java
new file mode 100644
index 0000000..af2223f
--- /dev/null
+++ b/bundles-lib/src/main/java/org/apache/metron/bundles/util/FileUtils.java
@@ -0,0 +1,35 @@
+/*
+ * 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.bundles.util;
+
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSystemException;
+
+public class FileUtils {
+
+  public static void ensureDirectoryExistAndCanRead(FileObject dir) throws 
FileSystemException {
+    if (dir.exists() && !dir.isFolder()) {
+      throw new FileSystemException(dir.getURL() + " is not a directory");
+    } else if (!dir.exists()) {
+      throw new FileSystemException(dir.getURL() + " does not exist");
+    }
+    if (!dir.isReadable()) {
+      throw new FileSystemException(
+          dir.getURL().toString() + " directory does not have read privilege");
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/main/java/org/apache/metron/bundles/util/ImmutableCollectionUtils.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/main/java/org/apache/metron/bundles/util/ImmutableCollectionUtils.java
 
b/bundles-lib/src/main/java/org/apache/metron/bundles/util/ImmutableCollectionUtils.java
new file mode 100644
index 0000000..52199ba
--- /dev/null
+++ 
b/bundles-lib/src/main/java/org/apache/metron/bundles/util/ImmutableCollectionUtils.java
@@ -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.
+ */
+
+package org.apache.metron.bundles.util;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utility class for creating immutable versions of collections, where the 
inner collection needs to
+ * be immutable as well.
+ *
+ * {@see com.google.common.collect}
+ */
+public class ImmutableCollectionUtils {
+
+  /**
+   * Creates an {@link ImmutableMap} of the passed {@link Map}. This includes 
{@link ImmutableSet}
+   * versions of the value {@link Set}
+   * @param map The {@link Map} to make immutable
+   * @param <T> The type of the key
+   * @param <K> The type of the {@link Set} elements
+   * @return An {@link ImmutableMap} of {@link ImmutableSet}
+   */
+  public static <T, K> Map<T, Set<K>> immutableMapOfSets(Map<T, Set<K>> map) {
+    for (T key : map.keySet()) {
+      map.put(key, ImmutableSet.copyOf(map.get(key)));
+    }
+    return ImmutableMap.copyOf(map);
+  }
+
+  /**
+   * Creates an {@link ImmutableMap} of the passed {@link Map}.  This includes
+   * {@link ImmutableList} instances of the value {@link List}
+   * @param map The {@link Map} to make immutable
+   * @param <T> The type of the key
+   * @param <K> The type of the {@link List} elements
+   * @return An {@link ImmutableMap} of {@link ImmutableList}
+   */
+  public static <T, K> Map<T, List<K>> immutableMapOfLists(Map<T, List<K>> 
map) {
+    for (T key : map.keySet()) {
+      map.put(key, ImmutableList.copyOf(map.get(key)));
+    }
+    return ImmutableMap.copyOf(map);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/main/java/org/apache/metron/bundles/util/StringUtils.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/main/java/org/apache/metron/bundles/util/StringUtils.java 
b/bundles-lib/src/main/java/org/apache/metron/bundles/util/StringUtils.java
new file mode 100644
index 0000000..7402026
--- /dev/null
+++ b/bundles-lib/src/main/java/org/apache/metron/bundles/util/StringUtils.java
@@ -0,0 +1,118 @@
+/*
+ * 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.bundles.util;
+
+import java.util.Collection;
+
+/**
+ * String Utils based on the Apache Commons Lang String Utils.
+ * These simple util methods here allow us to avoid a dependency in the core
+ */
+public class StringUtils {
+
+    public static final String EMPTY = "";
+
+    public static boolean isBlank(final String str) {
+        if (str == null || str.isEmpty()) {
+            return true;
+        }
+        for (int i = 0; i < str.length(); i++) {
+            if (!Character.isWhitespace(str.charAt(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean isEmpty(final String str) {
+        return str == null || str.isEmpty();
+    }
+
+    public static boolean startsWith(final String str, final String prefix) {
+        if (str == null || prefix == null) {
+            return (str == null && prefix == null);
+        }
+        if (prefix.length() > str.length()) {
+            return false;
+        }
+        return str.regionMatches(false, 0, prefix, 0, prefix.length());
+    }
+
+    public static String substringAfter(final String str, final String 
separator) {
+        if (isEmpty(str)) {
+            return str;
+        }
+        if (separator == null) {
+            return EMPTY;
+        }
+        int pos = str.indexOf(separator);
+        if (pos == -1) {
+            return EMPTY;
+        }
+        return str.substring(pos + separator.length());
+    }
+
+    public static String substringAfterLast(final String str, final String 
separator) {
+        if (isEmpty(str)) {
+            return str;
+        }
+        if (separator == null) {
+            return EMPTY;
+        }
+        int pos = str.lastIndexOf(separator);
+        if (pos == -1) {
+            return EMPTY;
+        }
+        return str.substring(pos + separator.length());
+    }
+
+
+    public static String join(final Collection collection, String delimiter) {
+        if (collection == null || collection.size() == 0) {
+            return EMPTY;
+        }
+        final StringBuilder sb = new StringBuilder(collection.size() * 16);
+        for (Object element : collection) {
+            sb.append((String) element);
+            sb.append(delimiter);
+        }
+        return sb.toString().substring(0, sb.lastIndexOf(delimiter));
+    }
+
+    public static String padLeft(final String source, int length, char 
padding) {
+        if (source != null) {
+            StringBuilder sb = new StringBuilder(source).reverse();
+            while (sb.length() < length) {
+                sb.append(padding);
+            }
+            return sb.reverse().toString();
+        }
+        return null;
+    }
+
+    public static String padRight(final String source, int length, char 
padding) {
+        if (source != null) {
+            StringBuilder sb = new StringBuilder(source);
+            while (sb.length() < length) {
+                sb.append(padding);
+            }
+            return sb.toString();
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/test/java/org/apache/metron/bundles/AbstractFoo.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/test/java/org/apache/metron/bundles/AbstractFoo.java 
b/bundles-lib/src/test/java/org/apache/metron/bundles/AbstractFoo.java
new file mode 100644
index 0000000..ede969d
--- /dev/null
+++ b/bundles-lib/src/test/java/org/apache/metron/bundles/AbstractFoo.java
@@ -0,0 +1,24 @@
+/*
+ * 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.bundles;
+
+public abstract class AbstractFoo {
+
+  public void Do(){
+    System.out.println("Foo");
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/test/java/org/apache/metron/bundles/BundleClassLoadersTest.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/test/java/org/apache/metron/bundles/BundleClassLoadersTest.java
 
b/bundles-lib/src/test/java/org/apache/metron/bundles/BundleClassLoadersTest.java
new file mode 100644
index 0000000..fa32e01
--- /dev/null
+++ 
b/bundles-lib/src/test/java/org/apache/metron/bundles/BundleClassLoadersTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.bundles;
+
+import static org.apache.metron.bundles.util.TestUtil.loadSpecifiedProperties;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.vfs2.FileSystemManager;
+import org.apache.metron.bundles.bundle.Bundle;
+import org.apache.metron.bundles.util.BundleProperties;
+import org.apache.metron.bundles.util.FileSystemManagerFactory;
+import org.apache.metron.bundles.util.ResourceCopier;
+import org.apache.metron.bundles.util.TestUtil;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class BundleClassLoadersTest {
+
+  static final Map<String, String> EMPTY_MAP = new HashMap<String, String>();
+
+  @AfterClass
+  public static void after() {
+    BundleClassLoaders.reset();
+  }
+
+  @BeforeClass
+  public static void copyResources() throws IOException {
+    ResourceCopier.copyResources(Paths.get("./src/test/resources"), 
Paths.get("./target"));
+  }
+
+  @Test
+  public void testReset() throws Exception {
+    // this test is to ensure that we can
+    // reset the BundleClassLoaders and initialize
+    // a second time
+    BundleProperties properties = 
loadSpecifiedProperties("/BundleMapper/conf/bundle.properties",
+        EMPTY_MAP);
+
+    assertEquals("./target/BundleMapper/lib/",
+        properties.getProperty("bundle.library.directory"));
+    assertEquals("./target/BundleMapper/lib2/",
+        properties.getProperty("bundle.library.directory.alt"));
+
+    String altLib = properties.getProperty("bundle.library.directory.alt");
+    properties.unSetProperty("bundle.library.directory.alt");
+
+    FileSystemManager fileSystemManager = FileSystemManagerFactory
+        .createFileSystemManager(new String[] 
{properties.getArchiveExtension()});
+
+    BundleClassLoaders.init(fileSystemManager, 
TestUtil.getExtensionLibs(fileSystemManager, properties),
+            properties);
+
+    Set<Bundle> bundles = BundleClassLoaders.getInstance().getBundles();
+
+    Assert.assertEquals(1, bundles.size());
+    for (Bundle thisBundle : bundles) {
+      Assert.assertEquals("org.apache.metron:metron-parser-bar-bundle:0.4.1",
+          thisBundle.getBundleDetails().getCoordinates().getCoordinates());
+    }
+
+
+
+    properties.setProperty("bundle.library.directory", altLib);
+    boolean thrown = false;
+    try {
+      BundleClassLoaders.getInstance()
+          .init(fileSystemManager, 
TestUtil.getExtensionLibs(fileSystemManager, properties),
+              properties);
+    } catch (IllegalStateException ise){
+      thrown = true;
+    }
+    Assert.assertTrue(thrown);
+
+    BundleClassLoaders.reset();
+
+    BundleClassLoaders
+        .init(fileSystemManager, TestUtil.getExtensionLibs(fileSystemManager, 
properties),
+            properties);
+
+    bundles = BundleClassLoaders.getInstance().getBundles();
+
+    Assert.assertEquals(1, bundles.size());
+    for (Bundle thisBundle : bundles) {
+      Assert.assertEquals("org.apache.metron:metron-parser-foo-bundle:0.4.1",
+          thisBundle.getBundleDetails().getCoordinates().getCoordinates());
+    }
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/test/java/org/apache/metron/bundles/BundleMapperTest.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/test/java/org/apache/metron/bundles/BundleMapperTest.java 
b/bundles-lib/src/test/java/org/apache/metron/bundles/BundleMapperTest.java
new file mode 100644
index 0000000..15c7eba
--- /dev/null
+++ b/bundles-lib/src/test/java/org/apache/metron/bundles/BundleMapperTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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.bundles;
+
+import org.apache.commons.vfs2.FileSystemException;
+import org.apache.commons.vfs2.FileSystemManager;
+import org.apache.metron.bundles.bundle.Bundle;
+import org.apache.metron.bundles.util.BundleProperties;
+import org.apache.metron.bundles.util.FileSystemManagerFactory;
+import org.apache.metron.bundles.util.ResourceCopier;
+import org.apache.metron.parsers.interfaces.MessageParser;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.*;
+
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+
+import static org.apache.metron.bundles.util.TestUtil.loadSpecifiedProperties;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class BundleMapperTest {
+
+  static final Map<String, String> EMPTY_MAP = new HashMap<String, String>();
+
+  @AfterClass
+  public static void after() {
+    ExtensionManager.reset();
+    BundleClassLoaders.reset();
+  }
+
+  @After
+  public void afterTest() {
+    ExtensionManager.reset();
+    BundleClassLoaders.reset();
+  }
+
+  @BeforeClass
+  public static void copyResources() throws IOException {
+    
ResourceCopier.copyResources(Paths.get("./src/test/resources"),Paths.get("./target"));
+  }
+
+  @Test
+  public void testUnpackBundles()
+      throws FileSystemException, URISyntaxException, NotInitializedException {
+
+    BundleProperties properties = 
loadSpecifiedProperties("/BundleMapper/conf/bundle.properties",
+        EMPTY_MAP);
+
+    assertEquals("./target/BundleMapper/lib/",
+        properties.getProperty("bundle.library.directory"));
+    assertEquals("./target/BundleMapper/lib2/",
+        properties.getProperty("bundle.library.directory.alt"));
+
+    FileSystemManager fileSystemManager = 
FileSystemManagerFactory.createFileSystemManager(new String[] 
{properties.getArchiveExtension()});
+    ArrayList<Class> classes = new ArrayList<>();
+    classes.add(MessageParser.class);
+    final ExtensionMapping extensionMapping = BundleMapper
+        .mapBundles(fileSystemManager,
+            properties);
+
+    assertEquals(2, extensionMapping.getAllExtensionNames().size());
+
+    assertTrue(extensionMapping.getAllExtensionNames().keySet().contains(
+        "org.apache.metron.foo.FooParser"));
+    assertTrue(extensionMapping.getAllExtensionNames().keySet().contains(
+        "org.apache.metron.bar.BarParser"));
+  }
+
+  @Test
+  public void testUnpackBundlesFromEmptyDir()
+      throws IOException, FileSystemException, URISyntaxException, 
NotInitializedException {
+
+    final File emptyDir = new File("./target/empty/dir");
+    emptyDir.delete();
+    emptyDir.deleteOnExit();
+    assertTrue(emptyDir.mkdirs());
+
+    final Map<String, String> others = new HashMap<>();
+    others.put("bundle.library.directory.alt", emptyDir.toString());
+    BundleProperties properties = 
loadSpecifiedProperties("/BundleMapper/conf/bundle.properties",
+        others);
+    FileSystemManager fileSystemManager = 
FileSystemManagerFactory.createFileSystemManager(new String[] 
{properties.getArchiveExtension()});
+    ArrayList<Class> classes = new ArrayList<>();
+    classes.add(MessageParser.class);
+    // create a FileSystemManager
+    Bundle systemBundle = 
ExtensionManager.createSystemBundle(fileSystemManager, properties);
+    ExtensionManager.init(classes, systemBundle, Collections.emptySet());
+    final ExtensionMapping extensionMapping = BundleMapper
+        .mapBundles(fileSystemManager,
+             properties);
+
+    assertNotNull(extensionMapping);
+    assertEquals(1, extensionMapping.getAllExtensionNames().size());
+    assertTrue(extensionMapping.getAllExtensionNames().keySet().contains(
+        "org.apache.metron.bar.BarParser"));
+  }
+
+  @Test
+  public void testUnpackBundlesFromNonExistantDir()
+      throws FileSystemException, URISyntaxException, NotInitializedException {
+
+    final File nonExistantDir = new 
File("./target/this/dir/should/not/exist/");
+    nonExistantDir.delete();
+    nonExistantDir.deleteOnExit();
+
+    final Map<String, String> others = new HashMap<>();
+    others.put("bundle.library.directory.alt", nonExistantDir.toString());
+    BundleProperties properties = 
loadSpecifiedProperties("/BundleMapper/conf/bundle.properties",
+        others);
+    FileSystemManager fileSystemManager = 
FileSystemManagerFactory.createFileSystemManager(new String[] 
{properties.getArchiveExtension()});
+    ArrayList<Class> classes = new ArrayList<>();
+    classes.add(MessageParser.class);
+    // create a FileSystemManager
+    Bundle systemBundle = 
ExtensionManager.createSystemBundle(fileSystemManager, properties);
+    ExtensionManager.init(classes, systemBundle, Collections.emptySet());
+    final ExtensionMapping extensionMapping = BundleMapper
+        .mapBundles(fileSystemManager,
+             properties);
+
+    assertTrue(extensionMapping.getAllExtensionNames().keySet().contains(
+        "org.apache.metron.bar.BarParser"));
+
+    assertEquals(1, extensionMapping.getAllExtensionNames().size());
+  }
+
+  @Test
+  public void testUnpackBundlesFromNonDir()
+      throws IOException, FileSystemException, URISyntaxException, 
NotInitializedException {
+
+    final File nonDir = new File("./target/file.txt");
+    nonDir.createNewFile();
+    nonDir.deleteOnExit();
+
+    final Map<String, String> others = new HashMap<>();
+    others.put("bundle.library.directory.alt", nonDir.toString());
+    BundleProperties properties = 
loadSpecifiedProperties("/BundleMapper/conf/bundle.properties",
+        others);
+    // create a FileSystemManager
+    FileSystemManager fileSystemManager = 
FileSystemManagerFactory.createFileSystemManager(new String[] 
{properties.getArchiveExtension()});
+    ArrayList<Class> classes = new ArrayList<>();
+    classes.add(MessageParser.class);
+    // create a FileSystemManager
+    Bundle systemBundle = 
ExtensionManager.createSystemBundle(fileSystemManager, properties);
+    ExtensionManager.init(classes, systemBundle, Collections.emptySet());
+    final ExtensionMapping extensionMapping = BundleMapper
+        .mapBundles(fileSystemManager,
+            properties);
+
+    assertNull(extensionMapping);
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/test/java/org/apache/metron/bundles/BundleSystemTest.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/test/java/org/apache/metron/bundles/BundleSystemTest.java 
b/bundles-lib/src/test/java/org/apache/metron/bundles/BundleSystemTest.java
new file mode 100644
index 0000000..ee0fd40
--- /dev/null
+++ b/bundles-lib/src/test/java/org/apache/metron/bundles/BundleSystemTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.bundles;
+
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+import 
org.apache.metron.bundles.BundleThreadContextClassLoaderTest.WithPropertiesConstructor;
+import org.apache.metron.bundles.util.BundleProperties;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class BundleSystemTest {
+
+  @AfterClass
+  public static void after() {
+    BundleClassLoaders.reset();
+    ExtensionManager.reset();;
+  }
+  
+  @Test
+  public void createInstance() throws Exception {
+    BundleProperties properties = BundleProperties
+        .createBasicBundleProperties("src/test/resources/bundle.properties", 
null);
+
+    
properties.setProperty(BundleProperties.BUNDLE_LIBRARY_DIRECTORY,"src/test/resources/BundleMapper/lib");
+    BundleSystem bundleSystem = new 
BundleSystem.Builder().withBundleProperties(properties).withExtensionClasses(
+        Arrays.asList(AbstractFoo.class)).build();
+    Assert.assertTrue(
+        bundleSystem.createInstance(WithPropertiesConstructor.class.getName(),
+            WithPropertiesConstructor.class) instanceof 
WithPropertiesConstructor);
+
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void createInstanceFail() throws Exception {
+    BundleSystem bundleSystem = new BundleSystem.Builder().build();
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/test/java/org/apache/metron/bundles/BundleThreadContextClassLoaderTest.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/test/java/org/apache/metron/bundles/BundleThreadContextClassLoaderTest.java
 
b/bundles-lib/src/test/java/org/apache/metron/bundles/BundleThreadContextClassLoaderTest.java
new file mode 100644
index 0000000..e148567
--- /dev/null
+++ 
b/bundles-lib/src/test/java/org/apache/metron/bundles/BundleThreadContextClassLoaderTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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.bundles;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.vfs2.FileSystemManager;
+import org.apache.metron.bundles.bundle.Bundle;
+import org.apache.metron.bundles.util.BundleProperties;
+import org.apache.metron.bundles.util.FileSystemManagerFactory;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Test;
+
+public class BundleThreadContextClassLoaderTest {
+  @AfterClass
+  public static void after() {
+    BundleClassLoaders.reset();
+    ExtensionManager.reset();
+  }
+
+  @After
+  public void afterTest() {
+    BundleClassLoaders.reset();
+    ExtensionManager.reset();
+  }
+
+  @Test
+  public void validateWithPropertiesConstructor() throws Exception {
+    BundleProperties properties = BundleProperties
+        .createBasicBundleProperties("src/test/resources/bundle.properties", 
null);
+
+    
properties.setProperty(BundleProperties.BUNDLE_LIBRARY_DIRECTORY,"src/test/resources/BundleMapper/lib");
+
+    ArrayList<Class> classes = new ArrayList<>();
+    classes.add(AbstractFoo.class);
+    // create a FileSystemManager
+    FileSystemManager fileSystemManager = 
FileSystemManagerFactory.createFileSystemManager(new String[] 
{properties.getArchiveExtension()});
+    Bundle systemBundle = 
ExtensionManager.createSystemBundle(fileSystemManager, properties);
+    ExtensionManager.init(classes, systemBundle, Collections.emptySet());
+
+    assertTrue(
+        
BundleThreadContextClassLoader.createInstance(WithPropertiesConstructor.class.getName(),
+            WithPropertiesConstructor.class, properties) instanceof 
WithPropertiesConstructor);
+  }
+
+  @Test(expected = IllegalStateException.class)
+  public void validateWithPropertiesConstructorInstantiationFailure() throws 
Exception {
+    ArrayList<Class> classes = new ArrayList<>();
+    classes.add(AbstractFoo.class);
+    Map<String, String> additionalProperties = new HashMap<>();
+    additionalProperties.put("fail", "true");
+    BundleProperties properties = BundleProperties
+        .createBasicBundleProperties("src/test/resources/bundle.properties", 
additionalProperties);
+    
properties.setProperty(BundleProperties.BUNDLE_LIBRARY_DIRECTORY,"src/test/resources/BundleMapper/lib");
+    // create a FileSystemManager
+    FileSystemManager fileSystemManager = 
FileSystemManagerFactory.createFileSystemManager(new String[] 
{properties.getArchiveExtension()});
+    Bundle systemBundle = 
ExtensionManager.createSystemBundle(fileSystemManager, properties);
+    ExtensionManager.init(classes, systemBundle, Collections.emptySet());
+
+    BundleThreadContextClassLoader
+        .createInstance(WithPropertiesConstructor.class.getName(), 
WithPropertiesConstructor.class,
+            properties);
+  }
+
+  @Test
+  public void validateWithDefaultConstructor() throws Exception {
+    BundleProperties properties = BundleProperties
+        .createBasicBundleProperties("src/test/resources/bundle.properties", 
null);
+    
properties.setProperty(BundleProperties.BUNDLE_LIBRARY_DIRECTORY,"src/test/resources/BundleMapper/lib");
+    ArrayList<Class> classes = new ArrayList<>();
+    classes.add(AbstractFoo.class);
+    // create a FileSystemManager
+    FileSystemManager fileSystemManager = 
FileSystemManagerFactory.createFileSystemManager(new String[] 
{properties.getArchiveExtension()});
+    Bundle systemBundle = 
ExtensionManager.createSystemBundle(fileSystemManager, properties);
+    ExtensionManager.init(classes, systemBundle, Collections.emptySet());
+
+    
assertTrue(BundleThreadContextClassLoader.createInstance(WithDefaultConstructor.class.getName(),
+        WithDefaultConstructor.class, properties) instanceof 
WithDefaultConstructor);
+  }
+
+  @Test(expected = IllegalStateException.class)
+  public void validateWithWrongConstructor() throws Exception {
+    BundleProperties properties = BundleProperties
+        .createBasicBundleProperties("src/test/resources/bundle.properties", 
null);
+    
properties.setProperty(BundleProperties.BUNDLE_LIBRARY_DIRECTORY,"src/test/resources/BundleMapper/lib");
+    ArrayList<Class> classes = new ArrayList<>();
+    classes.add(AbstractFoo.class);
+    // create a FileSystemManager
+    FileSystemManager fileSystemManager = 
FileSystemManagerFactory.createFileSystemManager(new String[] 
{properties.getArchiveExtension()});
+    Bundle systemBundle = 
ExtensionManager.createSystemBundle(fileSystemManager, properties);
+    ExtensionManager.init(classes, systemBundle, Collections.emptySet());
+
+    BundleThreadContextClassLoader
+        .createInstance(WrongConstructor.class.getName(), 
WrongConstructor.class, properties);
+  }
+
+  public static class WithPropertiesConstructor extends AbstractFoo {
+
+    public WithPropertiesConstructor() {
+    }
+
+    public WithPropertiesConstructor(BundleProperties properties) {
+      if (properties.getProperty("fail") != null) {
+        throw new RuntimeException("Intentional failure");
+      }
+    }
+  }
+
+  public static class WithDefaultConstructor extends AbstractFoo {
+
+    public WithDefaultConstructor() {
+
+    }
+  }
+
+  public static class WrongConstructor extends AbstractFoo {
+
+    public WrongConstructor(String s) {
+
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/test/java/org/apache/metron/bundles/BundleUtilTest.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/test/java/org/apache/metron/bundles/BundleUtilTest.java 
b/bundles-lib/src/test/java/org/apache/metron/bundles/BundleUtilTest.java
new file mode 100644
index 0000000..a6d20da
--- /dev/null
+++ b/bundles-lib/src/test/java/org/apache/metron/bundles/BundleUtilTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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.bundles;
+
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSystemManager;
+import org.apache.metron.bundles.bundle.BundleCoordinates;
+import org.apache.metron.bundles.bundle.BundleDetails;
+import org.apache.metron.bundles.util.BundleProperties;
+import org.apache.metron.bundles.util.BundleUtil;
+import org.apache.metron.bundles.util.FileSystemManagerFactory;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+public class BundleUtilTest {
+    Map<String, String> additionalProperties = new HashMap<>();
+    @Test
+    public void testManifestWithVersioningAndBuildInfo() throws IOException , 
URISyntaxException{
+
+        BundleProperties properties = 
BundleProperties.createBasicBundleProperties("src/test/resources/bundle.properties",
 additionalProperties);
+        // create a FileSystemManager
+        FileSystemManager fileSystemManager = 
FileSystemManagerFactory.createFileSystemManager(new String[] 
{properties.getArchiveExtension()});
+
+        final FileObject bundleDir = 
fileSystemManager.resolveFile(BundleProperties.getURI("src/test/resources/utils-bundles/bundle-with-versioning"));
+        final BundleDetails bundleDetails = 
BundleUtil.fromBundleTestDirectory(bundleDir, properties);
+        assertEquals(bundleDir.getURL(), 
bundleDetails.getBundleFile().getURL());
+
+        assertEquals("org.apache.metron", 
bundleDetails.getCoordinates().getGroup());
+        assertEquals("metron-hadoop-bundle", 
bundleDetails.getCoordinates().getId());
+        assertEquals("1.2.0", bundleDetails.getCoordinates().getVersion());
+
+        assertEquals("org.apache.metron.hadoop", 
bundleDetails.getDependencyCoordinates().getGroup());
+        assertEquals("metron-hadoop-libraries-bundle", 
bundleDetails.getDependencyCoordinates().getId());
+        assertEquals("1.2.1", 
bundleDetails.getDependencyCoordinates().getVersion());
+
+        assertEquals("METRON-3380", bundleDetails.getBuildBranch());
+        assertEquals("1.8.0_74", bundleDetails.getBuildJdk());
+        assertEquals("a032175", bundleDetails.getBuildRevision());
+        assertEquals("HEAD", bundleDetails.getBuildTag());
+        assertEquals("2017-01-23T10:36:27Z", 
bundleDetails.getBuildTimestamp());
+        assertEquals("ottobackwards", bundleDetails.getBuiltBy());
+    }
+
+    @Test
+    public void testManifestWithoutVersioningAndBuildInfo() throws 
IOException, URISyntaxException {
+        BundleProperties properties = 
BundleProperties.createBasicBundleProperties("src/test/resources/bundle.properties",
  additionalProperties);
+        // create a FileSystemManager
+        FileSystemManager fileSystemManager = 
FileSystemManagerFactory.createFileSystemManager(new String[] 
{properties.getArchiveExtension()});
+
+        final FileObject bundleDir = 
fileSystemManager.resolveFile(BundleProperties.getURI("src/test/resources/utils-bundles/bundle-without-versioning"));
+        final BundleDetails bundleDetails = 
BundleUtil.fromBundleTestDirectory(bundleDir, properties);
+        assertEquals(bundleDir.getURL(), 
bundleDetails.getBundleFile().getURL());
+
+        assertEquals(BundleCoordinates.DEFAULT_GROUP, 
bundleDetails.getCoordinates().getGroup());
+        assertEquals("metron-hadoop-bundle", 
bundleDetails.getCoordinates().getId());
+        assertEquals(BundleCoordinates.DEFAULT_VERSION, 
bundleDetails.getCoordinates().getVersion());
+
+        assertEquals(BundleCoordinates.DEFAULT_GROUP, 
bundleDetails.getDependencyCoordinates().getGroup());
+        assertEquals("metron-hadoop-libraries-bundle", 
bundleDetails.getDependencyCoordinates().getId());
+        assertEquals(BundleCoordinates.DEFAULT_VERSION, 
bundleDetails.getDependencyCoordinates().getVersion());
+
+        assertNull(bundleDetails.getBuildBranch());
+        assertEquals("1.8.0_74", bundleDetails.getBuildJdk());
+        assertNull(bundleDetails.getBuildRevision());
+        assertNull(bundleDetails.getBuildTag());
+        assertNull(bundleDetails.getBuildTimestamp());
+        assertEquals("ottobackwards", bundleDetails.getBuiltBy());
+    }
+
+    @Test
+    public void testManifestWithoutBundleDependency() throws IOException, 
URISyntaxException {
+        BundleProperties properties = 
BundleProperties.createBasicBundleProperties("src/test/resources/bundle.properties",
  additionalProperties);
+        // create a FileSystemManager
+        FileSystemManager fileSystemManager = 
FileSystemManagerFactory.createFileSystemManager(new String[] 
{properties.getArchiveExtension()});
+
+        final FileObject bundleDir = 
fileSystemManager.resolveFile(BundleProperties.getURI("src/test/resources/utils-bundles/bundle-without-dependency"));
+        final BundleDetails bundleDetails = 
BundleUtil.fromBundleTestDirectory(bundleDir, properties);
+        assertEquals(bundleDir.getURL(), 
bundleDetails.getBundleFile().getURL());
+
+        assertEquals("org.apache.metron", 
bundleDetails.getCoordinates().getGroup());
+        assertEquals("metron-hadoop-bundle", 
bundleDetails.getCoordinates().getId());
+        assertEquals("1.2.0", bundleDetails.getCoordinates().getVersion());
+
+        assertNull(bundleDetails.getDependencyCoordinates());
+
+        assertEquals("METRON-3380", bundleDetails.getBuildBranch());
+        assertEquals("1.8.0_74", bundleDetails.getBuildJdk());
+        assertEquals("a032175", bundleDetails.getBuildRevision());
+        assertEquals("HEAD", bundleDetails.getBuildTag());
+        assertEquals("2017-01-23T10:36:27Z", 
bundleDetails.getBuildTimestamp());
+        assertEquals("ottobackwards", bundleDetails.getBuiltBy());
+    }
+
+    @Test(expected = IOException.class)
+    public void testFromManifestWhenBundleDirectoryDoesNotExist() throws 
IOException, URISyntaxException {
+        BundleProperties properties = 
BundleProperties.createBasicBundleProperties("src/test/resources/bundle.properties",
 additionalProperties);
+        // create a FileSystemManager
+        FileSystemManager fileSystemManager = 
FileSystemManagerFactory.createFileSystemManager(new String[] 
{properties.getArchiveExtension()});
+
+        final FileObject manifest = 
fileSystemManager.resolveFile(BundleProperties.getURI("src/test/resources/utils-bundles/bundle-does-not-exist"));
+        BundleUtil.fromBundleTestDirectory(manifest, properties );
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/test/java/org/apache/metron/bundles/ExtensionClassInitializerTest.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/test/java/org/apache/metron/bundles/ExtensionClassInitializerTest.java
 
b/bundles-lib/src/test/java/org/apache/metron/bundles/ExtensionClassInitializerTest.java
new file mode 100644
index 0000000..30d083b
--- /dev/null
+++ 
b/bundles-lib/src/test/java/org/apache/metron/bundles/ExtensionClassInitializerTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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.bundles;
+
+import org.apache.metron.bundles.util.BundleProperties;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class ExtensionClassInitializerTest {
+  @BeforeClass
+  public static void before(){
+    ExtensionManager.reset();
+  }
+
+  @Test(expected = NotInitializedException.class)
+  public void testNotInitializedExtensionManager() throws Exception{
+    ExtensionManager.getInstance().getInstanceClassLoader("org.junit.Test");
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/metron/blob/ffcb91ed/bundles-lib/src/test/java/org/apache/metron/bundles/ExtensionManagerTest.java
----------------------------------------------------------------------
diff --git 
a/bundles-lib/src/test/java/org/apache/metron/bundles/ExtensionManagerTest.java 
b/bundles-lib/src/test/java/org/apache/metron/bundles/ExtensionManagerTest.java
new file mode 100644
index 0000000..94a246b
--- /dev/null
+++ 
b/bundles-lib/src/test/java/org/apache/metron/bundles/ExtensionManagerTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.bundles;
+
+import static org.apache.metron.bundles.util.TestUtil.loadSpecifiedProperties;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSystemManager;
+import org.apache.metron.bundles.bundle.Bundle;
+import org.apache.metron.bundles.util.BundleProperties;
+import org.apache.metron.bundles.util.FileSystemManagerFactory;
+import org.apache.metron.bundles.util.ResourceCopier;
+import org.apache.metron.bundles.util.TestUtil;
+import org.apache.metron.parsers.interfaces.MessageParser;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class ExtensionManagerTest {
+  static final Map<String, String> EMPTY_MAP = new HashMap<String, String>();
+
+  @AfterClass
+  public static void after() {
+    BundleClassLoaders.reset();
+  }
+
+  @Test
+  public void testExtensionManagerFunctions() throws Exception{
+    BundleProperties properties = 
loadSpecifiedProperties("/BundleMapper/conf/bundle.properties",
+        EMPTY_MAP);
+
+    assertEquals("./target/BundleMapper/lib/",
+        properties.getProperty("bundle.library.directory"));
+    assertEquals("./target/BundleMapper/lib2/",
+        properties.getProperty("bundle.library.directory.alt"));
+
+    FileSystemManager fileSystemManager = FileSystemManagerFactory
+        .createFileSystemManager(new String[] 
{properties.getArchiveExtension()});
+    List<Class> classes = Arrays.asList(AbstractFoo.class);
+
+    BundleClassLoaders
+        .init(fileSystemManager, TestUtil.getExtensionLibs(fileSystemManager, 
properties),
+            properties);
+
+    Bundle systemBundle = 
ExtensionManager.createSystemBundle(fileSystemManager, properties);
+    ExtensionManager.init(classes, systemBundle, 
BundleClassLoaders.getInstance().getBundles());
+
+    List<Bundle> bundles = 
ExtensionManager.getInstance().getBundles(BundleThreadContextClassLoaderTest.WithPropertiesConstructor.class.getName());
+    Assert.assertTrue(bundles.size() == 1);
+
+    Assert.assertEquals(bundles.get(0), 
ExtensionManager.getInstance().getBundle(bundles.get(0).getClassLoader()));
+
+    Assert.assertEquals(bundles.get(0), 
ExtensionManager.getInstance().getBundle(bundles.get(0).getBundleDetails().getCoordinates()));
+
+  }
+}
\ No newline at end of file

Reply via email to