This is an automated email from the ASF dual-hosted git repository.

asalamon74 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/oozie.git


The following commit(s) were added to refs/heads/master by this push:
     new 7c2e80a  OOZIE-1624 Exclusion pattern for sharelib JARs (puru, matijhs 
via asalamon74, andras.piros)
7c2e80a is described below

commit 7c2e80afc552e5cafe38b70aabcb765bc28121a4
Author: Andras Salamon <[email protected]>
AuthorDate: Fri Mar 8 15:19:26 2019 +0100

    OOZIE-1624 Exclusion pattern for sharelib JARs (puru, matijhs via 
asalamon74, andras.piros)
---
 .../oozie/action/hadoop/JavaActionExecutor.java    |  78 +++-
 .../oozie/action/hadoop/ShareLibExcluder.java      | 102 +++++
 .../org/apache/oozie/service/ShareLibService.java  |  14 +
 .../action/hadoop/ActionExecutorTestCase.java      |  66 +++
 .../action/hadoop/TestJavaActionExecutor.java      | 425 +------------------
 .../hadoop/TestJavaActionExecutorLibAddition.java  | 448 +++++++++++++++++++++
 .../oozie/action/hadoop/TestShareLibExcluder.java  | 233 +++++++++++
 docs/src/site/markdown/WorkflowFunctionalSpec.md   |  54 +++
 release-log.txt                                    |   1 +
 9 files changed, 1002 insertions(+), 419 deletions(-)

diff --git 
a/core/src/main/java/org/apache/oozie/action/hadoop/JavaActionExecutor.java 
b/core/src/main/java/org/apache/oozie/action/hadoop/JavaActionExecutor.java
index 0e76a7b..e70e90b 100644
--- a/core/src/main/java/org/apache/oozie/action/hadoop/JavaActionExecutor.java
+++ b/core/src/main/java/org/apache/oozie/action/hadoop/JavaActionExecutor.java
@@ -171,8 +171,10 @@ public class JavaActionExecutor extends ActionExecutor {
             OozieClient.USER_NAME, MRJobConfig.USER_NAME, HADOOP_NAME_NODE, 
HADOOP_YARN_RM
     );
     private static final String OOZIE_ACTION_NAME = "oozie.action.name";
-    private final static String ACTION_SHARELIB_FOR = 
"oozie.action.sharelib.for.";
-    public static final String OOZIE_ACTION_DEPENDENCY_DEDUPLICATE = 
"oozie.action.dependency.deduplicate";
+    private static final String OOZIE_ACTION_DEPENDENCY_DEDUPLICATE = 
"oozie.action.dependency.deduplicate";
+
+    static final String ACTION_SHARELIB_FOR = "oozie.action.sharelib.for.";
+    static final String SHARELIB_EXCLUDE_SUFFIX = ".exclude";
 
     /**
      * Heap to physical memory ration for {@link LauncherAM}, in order its 
YARN container doesn't get killed before physical memory
@@ -209,6 +211,7 @@ public class JavaActionExecutor extends ActionExecutor {
     private static final String JAVA_TMP_DIR_SETTINGS = "-Djava.io.tmpdir=";
 
     private static DependencyDeduplicator dependencyDeduplicator = new 
DependencyDeduplicator();
+    private ShareLibExcluder shareLibExcluder = null;
 
     public XConfiguration workflowConf = null;
 
@@ -695,7 +698,7 @@ public class JavaActionExecutor extends ActionExecutor {
             if (FSUtils.isLocalFile(libPath.toString())) {
                 conf = ClasspathUtils.addToClasspathFromLocalShareLib(conf, 
libPath);
             }
-            else {
+            else if (!shareLibExcluder.shouldExclude(libPath.toUri())) {
                 if (isAddToCache) {
                     addToCache(conf, libPath, libPath.toUri().getPath(), 
false);
                 }
@@ -708,7 +711,16 @@ public class JavaActionExecutor extends ActionExecutor {
         }
     }
 
-    protected void addActionLibs(Path appPath, Configuration conf) throws 
ActionExecutorException {
+    private void addFilesToCacheIfNotExcluded(Path appPath, Configuration 
conf, FileStatus[] files) throws ActionExecutorException {
+        if (files == null) return;
+        for (FileStatus file : files) {
+            if (!shareLibExcluder.shouldExclude(file.getPath().toUri())) {
+                addToCache(conf, appPath, file.getPath().toUri().getPath(), 
false);
+            }
+        }
+    }
+
+    private void addActionLibs(Path appPath, Configuration conf) throws 
ActionExecutorException {
         String[] actionLibsStrArr = 
conf.getStrings("oozie.launcher.oozie.libpath");
         if (actionLibsStrArr != null) {
             try {
@@ -721,10 +733,7 @@ public class JavaActionExecutor extends ActionExecutor {
                         FileSystem fs = 
Services.get().get(HadoopAccessorService.class).createFileSystem(user,
                                 appPath.toUri(), conf);
                         if (fs.exists(actionLibsPath)) {
-                            FileStatus[] files = fs.listStatus(actionLibsPath);
-                            for (FileStatus file : files) {
-                                addToCache(conf, appPath, 
file.getPath().toUri().getPath(), false);
-                            }
+                            addFilesToCacheIfNotExcluded(appPath, conf, 
fs.listStatus(actionLibsPath));
                         }
                     }
                 }
@@ -740,22 +749,42 @@ public class JavaActionExecutor extends ActionExecutor {
         }
     }
 
+    private void initShareLibExcluder(Configuration conf, Context context) 
throws ActionExecutorException {
+        XConfiguration wfJobConf = null;
+        try {
+            wfJobConf = getWorkflowConf(context);
+        }
+        catch (IOException e) {
+            throw new 
ActionExecutorException(ActionExecutorException.ErrorType.FAILED,
+                    "Failed to acquire workflow configuration from context.", 
e.getMessage());
+        }
+        LOG.info("Initializing sharelib excluder for action if specified.");
+        shareLibExcluder = new ShareLibExcluder(conf, 
Services.get().getConf(), wfJobConf, getType(), getSharelibRoot());
+    }
+
     @SuppressWarnings("unchecked")
     public void setLibFilesArchives(Context context, Element actionXml, Path 
appPath, Configuration conf)
             throws ActionExecutorException {
-        Configuration proto = context.getProtoActionConf();
 
-        // Workflow lib/
+        addWfApplicationLibs(appPath, conf, context.getProtoActionConf());
+        addActionXmlFilesAndArchives(actionXml, appPath, conf);
+
+        initShareLibExcluder(conf, context);
+
+        addActionLibs(appPath, conf);
+        addAllShareLibs(appPath, conf, context, actionXml);
+    }
+
+    private void addWfApplicationLibs(Path appPath, Configuration conf, 
Configuration proto) throws ActionExecutorException {
         String[] paths = 
proto.getStrings(WorkflowAppService.APP_LIB_PATH_LIST);
         if (paths != null) {
             for (String path : paths) {
                 addToCache(conf, appPath, path, false);
             }
         }
+    }
 
-        // Action libs
-        addActionLibs(appPath, conf);
-
+    private void addActionXmlFilesAndArchives(Element actionXml, Path appPath, 
Configuration conf) throws ActionExecutorException {
         // files and archives defined in the action
         for (Element eProp : (List<Element>) actionXml.getChildren()) {
             if (eProp.getName().equals("file")) {
@@ -771,8 +800,6 @@ public class JavaActionExecutor extends ActionExecutor {
                 }
             }
         }
-
-        addAllShareLibs(appPath, conf, context, actionXml);
     }
 
     @VisibleForTesting
@@ -1131,6 +1158,27 @@ public class JavaActionExecutor extends ActionExecutor {
         }
     }
 
+    private URI getSharelibRoot() {
+        ShareLibService shareLibService = 
Services.get().get(ShareLibService.class);
+        if (shareLibService == null) {
+            LOG.warn("ShareLibService is not configured, no root can be 
found");
+            return null;
+        }
+        try {
+            Path shareLibRootPath = shareLibService.getShareLibRootPath();
+            if (shareLibRootPath != null) {
+                return shareLibRootPath.toUri();
+            }
+            else {
+                LOG.warn("ShareLib root not found");
+            }
+        }
+        catch (IOException e) {
+            LOG.warn("ShareLib root not found", e);
+        }
+        return null;
+    }
+
     private void addAppNameContext(final Context context, final WorkflowAction 
action) {
         final String oozieActionName = getYarnApplicationName(context, action, 
"oozie:launcher");
         context.setVar(OOZIE_ACTION_NAME, oozieActionName);
diff --git 
a/core/src/main/java/org/apache/oozie/action/hadoop/ShareLibExcluder.java 
b/core/src/main/java/org/apache/oozie/action/hadoop/ShareLibExcluder.java
new file mode 100644
index 0000000..9c45e53
--- /dev/null
+++ b/core/src/main/java/org/apache/oozie/action/hadoop/ShareLibExcluder.java
@@ -0,0 +1,102 @@
+/**
+ * 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.oozie.action.hadoop;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.oozie.util.XLog;
+
+import java.net.URI;
+import java.util.Optional;
+import java.util.regex.Pattern;
+import com.google.common.base.Preconditions;
+
+import static 
org.apache.oozie.action.hadoop.JavaActionExecutor.ACTION_SHARELIB_FOR;
+import static 
org.apache.oozie.action.hadoop.JavaActionExecutor.SHARELIB_EXCLUDE_SUFFIX;
+
+class ShareLibExcluder {
+
+    private final URI shareLibRoot;
+    private final Pattern configuredExcludePattern;
+    private static XLog LOG = XLog.getLog(ShareLibExcluder.class);
+    @VisibleForTesting
+    static final String VALUE_NULL_MSG = "The value of %s cannot be null.";
+
+    ShareLibExcluder(final Configuration actionConf, final Configuration 
servicesConf, final Configuration jobConf,
+                     final String executorType, final URI shareLibRoot) {
+        this.shareLibRoot = shareLibRoot;
+        this.configuredExcludePattern = loadAndBuildPattern(actionConf, 
servicesConf, jobConf, executorType);
+    }
+
+    private Pattern loadAndBuildPattern(final Configuration actionConf, final 
Configuration servicesConf,
+                                        final Configuration jobConf, final 
String executorType) {
+        if(shareLibRoot == null) {
+            return null;
+        }
+
+        Preconditions.checkNotNull(actionConf, VALUE_NULL_MSG, "actionConf");
+        Preconditions.checkNotNull(servicesConf, VALUE_NULL_MSG, 
"servicesConf");
+        Preconditions.checkNotNull(jobConf, VALUE_NULL_MSG, "jobConf");
+
+        final String excludeProperty = ACTION_SHARELIB_FOR + executorType + 
SHARELIB_EXCLUDE_SUFFIX;
+
+        final Optional<String> maybeExcludePattern = 
tryFindExcludePattern(actionConf, servicesConf, jobConf, excludeProperty);
+        if (maybeExcludePattern.isPresent()) {
+            final String excludePattern = maybeExcludePattern.get();
+            actionConf.set(excludeProperty, excludePattern);
+            LOG.debug("Setting action configuration property: {0}={1}", 
excludeProperty, excludePattern);
+            LOG.info("The following sharelib exclude pattern will be used: 
{0}", excludePattern);
+
+            return Pattern.compile(excludePattern);
+        }
+        return null;
+    }
+
+    private Optional<String> tryFindExcludePattern(final Configuration 
actionConf, final Configuration servicesConf,
+                                                   final Configuration 
jobConf, final String excludeProperty) {
+        String excludePattern = actionConf.get(excludeProperty);
+
+        if (excludePattern == null) {
+            excludePattern = jobConf.get(excludeProperty);
+        }
+
+        if (excludePattern == null) {
+            excludePattern = servicesConf.get(excludeProperty);
+        }
+
+        if (excludePattern == null) {
+            LOG.info("Sharelib exclude pattern not configured, skipping.");
+            return Optional.empty();
+        }
+        return Optional.of(excludePattern);
+    }
+
+    boolean shouldExclude(final URI actionLibURI) {
+        Preconditions.checkNotNull(actionLibURI, VALUE_NULL_MSG, 
"actionLibURI");
+
+        if (configuredExcludePattern != null && shareLibRoot != null) {
+            if 
(configuredExcludePattern.matcher(shareLibRoot.relativize(actionLibURI).getPath()).matches())
 {
+                LOG.info("Mark file for excluding from distributed cache: 
{0}", actionLibURI.getPath());
+                return true;
+            }
+        }
+        LOG.debug("Mark file for adding to distributed cache: {0}", 
actionLibURI.getPath());
+        return false;
+    }
+}
diff --git a/core/src/main/java/org/apache/oozie/service/ShareLibService.java 
b/core/src/main/java/org/apache/oozie/service/ShareLibService.java
index b88dab3..fc2c29b 100644
--- a/core/src/main/java/org/apache/oozie/service/ShareLibService.java
+++ b/core/src/main/java/org/apache/oozie/service/ShareLibService.java
@@ -618,6 +618,20 @@ public class ShareLibService implements Service, 
Instrumentable {
     }
 
     /**
+     * Get the latest share lib root path
+     *
+     * @return share lib root Path
+     * @throws IOException Signals that the Oozie share lib root path could 
not be reached.
+     */
+    public Path getShareLibRootPath() throws IOException {
+        Path shareLibpath = 
getLatestLibPath(Services.get().get(WorkflowAppService.class).getSystemLibPath(),
 SHARE_LIB_PREFIX);
+        if (shareLibpath == null){
+            LOG.info("No share lib directory found");
+        }
+        return shareLibpath;
+    }
+
+    /**
      * Update share lib cache. Parse the share lib directory and each sub 
directory is a action key
      *
      * @param shareLibMap the share lib jar map
diff --git 
a/core/src/test/java/org/apache/oozie/action/hadoop/ActionExecutorTestCase.java 
b/core/src/test/java/org/apache/oozie/action/hadoop/ActionExecutorTestCase.java
index 05511e4..eca4013 100644
--- 
a/core/src/test/java/org/apache/oozie/action/hadoop/ActionExecutorTestCase.java
+++ 
b/core/src/test/java/org/apache/oozie/action/hadoop/ActionExecutorTestCase.java
@@ -43,6 +43,7 @@ import org.apache.oozie.service.HadoopAccessorService;
 import org.apache.oozie.service.LiteWorkflowStoreService;
 import org.apache.oozie.service.Services;
 import org.apache.oozie.service.UUIDService;
+import org.apache.oozie.service.ShareLibService;
 import org.apache.oozie.service.WorkflowAppService;
 import org.apache.oozie.service.WorkflowStoreService;
 import org.apache.oozie.test.XHCatTestCase;
@@ -75,6 +76,12 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.Collection;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileInputStream;
+
+import java.text.SimpleDateFormat;
 
 public abstract class ActionExecutorTestCase extends XHCatTestCase {
     protected static final int JOB_TIMEOUT = 100_000;
@@ -495,4 +502,63 @@ public abstract class ActionExecutorTestCase extends 
XHCatTestCase {
     HadoopAccessorService getHadoopAccessorService() {
         return Services.get().get(HadoopAccessorService.class);
     }
+
+    void createFiles(Collection<Path> paths) throws Exception{
+        for(Path p : paths){
+            getFileSystem().create(p);
+        }
+    }
+
+    void makeDirs(Path... dirs) throws Exception{
+        for(Path p : dirs){
+            getFileSystem().mkdirs(p);
+        }
+    }
+
+    private void assertContainsJarsOrNot(boolean contains, String 
cacheFilesStr, Collection<Path> jars) {
+        for (Path jar : jars) {
+            assertEquals("Unexpected distributed cache file content", 
contains, cacheFilesStr.contains(jar.toString()));
+        }
+    }
+
+    void assertContainsJars(String cacheFilesStr, Collection<Path> jars) {
+        assertContainsJarsOrNot(true, cacheFilesStr, jars);
+    }
+
+    void assertNotContainsJars(String cacheFilesStr, Collection<Path> jars) {
+        assertContainsJarsOrNot(false, cacheFilesStr, jars);
+    }
+
+    protected Context createContext(String actionXml, String group) throws 
Exception {
+        JavaActionExecutor ae = new JavaActionExecutor();
+
+        Path appJarPath = new Path("lib/test.jar");
+        File jarFile = IOUtils.createJar(new File(getTestCaseDir()), 
"test.jar", LauncherMainTester.class);
+        InputStream is = new FileInputStream(jarFile);
+        OutputStream os = getFileSystem().create(new Path(getAppPath(), 
"lib/test.jar"));
+        IOUtils.copyStream(is, os);
+
+        Path appSoPath = new Path("lib/test.so");
+        getFileSystem().create(new Path(getAppPath(), appSoPath)).close();
+
+        XConfiguration protoConf = new XConfiguration();
+        protoConf.set(WorkflowAppService.HADOOP_USER, getTestUser());
+        protoConf.setStrings(WorkflowAppService.APP_LIB_PATH_LIST, 
appJarPath.toString(), appSoPath.toString());
+
+        WorkflowJobBean wf = createBaseWorkflow(protoConf, "action");
+        if(group != null) {
+            wf.setGroup(group);
+        }
+        WorkflowActionBean action = (WorkflowActionBean) 
wf.getActions().get(0);
+        action.setType(ae.getType());
+        action.setConf(actionXml);
+
+        return new Context(wf, action);
+    }
+
+    Path getNewSystemLibPath() {
+        WorkflowAppService wps = Services.get().get(WorkflowAppService.class);
+        return new Path(wps.getSystemLibPath(), 
ShareLibService.SHARE_LIB_PREFIX
+                + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
+    }
 }
diff --git 
a/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutor.java 
b/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutor.java
index 6383e81..4d3e3d7 100644
--- 
a/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutor.java
+++ 
b/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutor.java
@@ -18,6 +18,7 @@
 
 package org.apache.oozie.action.hadoop;
 
+import java.io.IOException;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -26,9 +27,6 @@ import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.StringReader;
 import java.io.Writer;
-import java.net.URI;
-import java.security.PrivilegedExceptionAction;
-import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
@@ -37,6 +35,11 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
+import java.net.URI;
+import java.security.PrivilegedExceptionAction;
+
+import org.jdom.Element;
+import org.junit.Assert;
 
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.examples.SleepJob;
@@ -82,12 +85,6 @@ import org.apache.oozie.workflow.WorkflowLib;
 import org.apache.oozie.workflow.lite.EndNodeDef;
 import org.apache.oozie.workflow.lite.LiteWorkflowApp;
 import org.apache.oozie.workflow.lite.StartNodeDef;
-import org.jdom.Element;
-import org.junit.Assert;
-import org.junit.Test;
-
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
 
 public class TestJavaActionExecutor extends ActionExecutorTestCase {
 
@@ -105,21 +102,27 @@ public class TestJavaActionExecutor extends 
ActionExecutorTestCase {
     public void setUp() throws Exception {
         super.setUp();
         helper = new TestWorkflowHelper(getJobTrackerUri(), getNameNodeUri(), 
getTestCaseDir());
-
     }
+
     @Override
     protected void setSystemProps() throws Exception {
         super.setSystemProps();
+        setHadoopSystemProps();
+        createActionConfDirFiles();
+    }
 
-        setSystemProperty("oozie.service.ActionService.executor.classes", 
JavaActionExecutor.class.getName());
-        
setSystemProperty("oozie.service.HadoopAccessorService.action.configurations",
-                          "*=hadoop-conf," + getJobTrackerUri() + 
"=action-conf");
-        setSystemProperty(WorkflowAppService.SYSTEM_LIB_PATH, 
getFsTestCaseDir().toUri().getPath() + "/systemlib");
+    private void createActionConfDirFiles() throws IOException {
         new File(getTestCaseConfDir(), "action-conf").mkdir();
         InputStream is = 
Thread.currentThread().getContextClassLoader().getResourceAsStream("test-action-config.xml");
         OutputStream os = new FileOutputStream(new File(getTestCaseConfDir() + 
"/action-conf", "java.xml"));
         IOUtils.copyStream(is, os);
+    }
 
+    private void setHadoopSystemProps() {
+        setSystemProperty("oozie.service.ActionService.executor.classes", 
JavaActionExecutor.class.getName());
+        
setSystemProperty("oozie.service.HadoopAccessorService.action.configurations",
+                          "*=hadoop-conf," + getJobTrackerUri() + 
"=action-conf");
+        setSystemProperty(WorkflowAppService.SYSTEM_LIB_PATH, 
getFsTestCaseDir().toUri().getPath() + "/systemlib");
     }
 
     public void testSetupMethods() throws Exception {
@@ -625,218 +628,6 @@ public class TestJavaActionExecutor extends 
ActionExecutorTestCase {
         assertEquals(WorkflowAction.Status.OK, 
context.getAction().getStatus());
     }
 
-    public void testLibFileArchives() throws Exception {
-        Path root = new Path(getFsTestCaseDir(), "root");
-
-        Path jar = new Path("jar.jar");
-        getFileSystem().create(new Path(getAppPath(), jar)).close();
-        Path rootJar = new Path(root, "rootJar.jar");
-        getFileSystem().create(rootJar).close();
-
-        Path file = new Path("file");
-        getFileSystem().create(new Path(getAppPath(), file)).close();
-        Path rootFile = new Path(root, "rootFile");
-        getFileSystem().create(rootFile).close();
-
-        Path so = new Path("soFile.so");
-        getFileSystem().create(new Path(getAppPath(), so)).close();
-        Path rootSo = new Path(root, "rootSoFile.so");
-        getFileSystem().create(rootSo).close();
-
-        Path so1 = new Path("soFile.so.1");
-        getFileSystem().create(new Path(getAppPath(), so1)).close();
-        Path rootSo1 = new Path(root, "rootSoFile.so.1");
-        getFileSystem().create(rootSo1).close();
-
-        Path archive = new Path("archive.tar");
-        getFileSystem().create(new Path(getAppPath(), archive)).close();
-        Path rootArchive = new Path(root, "rootArchive.tar");
-        getFileSystem().create(rootArchive).close();
-
-        String actionXml = "<java>" +
-                "      <job-tracker>" + getJobTrackerUri() + "</job-tracker>" +
-                "      <name-node>" + getNameNodeUri() + "</name-node>" +
-                "      <main-class>CLASS</main-class>" +
-                "      <file>" + jar.toString() + "</file>\n" +
-                "      <file>" + rootJar.toString() + "</file>\n" +
-                "      <file>" + file.toString() + "</file>\n" +
-                "      <file>" + rootFile.toString() + "</file>\n" +
-                "      <file>" + so.toString() + "</file>\n" +
-                "      <file>" + rootSo.toString() + "</file>\n" +
-                "      <file>" + so1.toString() + "</file>\n" +
-                "      <file>" + rootSo1.toString() + "</file>\n" +
-                "      <archive>" + archive.toString() + "</archive>\n" +
-                "      <archive>" + rootArchive.toString() + "</archive>\n" +
-                "</java>";
-
-        Element eActionXml = XmlUtils.parseXml(actionXml);
-
-        Context context = createContext(actionXml, null);
-
-        Path appPath = getAppPath();
-
-        JavaActionExecutor ae = new JavaActionExecutor();
-
-        Configuration jobConf = ae.createBaseHadoopConf(context, eActionXml);
-        ae.setupActionConf(jobConf, context, eActionXml, appPath);
-        ae.setLibFilesArchives(context, eActionXml, appPath, jobConf);
-
-
-        assertTrue(DistributedCache.getSymlink(jobConf));
-
-        Path[] filesInClasspath = DistributedCache.getFileClassPaths(jobConf);
-        for (Path p : new Path[]{new Path(getAppPath(), jar), rootJar}) {
-            boolean found = false;
-            for (Path c : filesInClasspath) {
-                if (!found && p.toUri().getPath().equals(c.toUri().getPath())) 
{
-                    found = true;
-                }
-            }
-            assertTrue("file " + p.toUri().getPath() + " not found in 
classpath", found);
-        }
-        for (Path p : new Path[]{new Path(getAppPath(), file), rootFile, new 
Path(getAppPath(), so), rootSo,
-                                 new Path(getAppPath(), so1), rootSo1}) {
-            boolean found = false;
-            for (Path c : filesInClasspath) {
-                if (!found && p.toUri().getPath().equals(c.toUri().getPath())) 
{
-                    found = true;
-                }
-            }
-            assertFalse("file " + p.toUri().getPath() + " found in classpath", 
found);
-        }
-
-        URI[] filesInCache = DistributedCache.getCacheFiles(jobConf);
-        for (Path p : new Path[]{new Path(getAppPath(), jar), rootJar, new 
Path(getAppPath(), file), rootFile,
-                                 new Path(getAppPath(), so), rootSo, new 
Path(getAppPath(), so1), rootSo1}) {
-            boolean found = false;
-            for (URI c : filesInCache) {
-                if (!found && p.toUri().getPath().equals(c.getPath())) {
-                    found = true;
-                }
-            }
-            assertTrue("file " + p.toUri().getPath() + " not found in cache", 
found);
-        }
-
-        URI[] archivesInCache = DistributedCache.getCacheArchives(jobConf);
-        for (Path p : new Path[]{new Path(getAppPath(), archive), 
rootArchive}) {
-            boolean found = false;
-            for (URI c : archivesInCache) {
-                if (!found && p.toUri().getPath().equals(c.getPath())) {
-                    found = true;
-                }
-            }
-            assertTrue("archive " + p.toUri().getPath() + " not found in 
cache", found);
-        }
-    }
-
-    /**
-     * https://issues.apache.org/jira/browse/OOZIE-87
-     * @throws Exception
-     */
-    public void testCommaSeparatedFilesAndArchives() throws Exception {
-        Path root = new Path(getFsTestCaseDir(), "root");
-
-        Path jar = new Path("jar.jar");
-        getFileSystem().create(new Path(getAppPath(), jar)).close();
-        Path rootJar = new Path(root, "rootJar.jar");
-        getFileSystem().create(rootJar).close();
-
-        Path file = new Path("file");
-        getFileSystem().create(new Path(getAppPath(), file)).close();
-        Path rootFile = new Path(root, "rootFile");
-        getFileSystem().create(rootFile).close();
-
-        Path so = new Path("soFile.so");
-        getFileSystem().create(new Path(getAppPath(), so)).close();
-        Path rootSo = new Path(root, "rootSoFile.so");
-        getFileSystem().create(rootSo).close();
-
-        Path so1 = new Path("soFile.so.1");
-        getFileSystem().create(new Path(getAppPath(), so1)).close();
-        Path rootSo1 = new Path(root, "rootSoFile.so.1");
-        getFileSystem().create(rootSo1).close();
-
-        Path archive = new Path("archive.tar");
-        getFileSystem().create(new Path(getAppPath(), archive)).close();
-        Path rootArchive = new Path(root, "rootArchive.tar");
-        getFileSystem().create(rootArchive).close();
-
-        String actionXml = "<java>" +
-                "      <job-tracker>" + getJobTrackerUri() + "</job-tracker>" +
-                "      <name-node>" + getNameNodeUri() + "</name-node>" +
-                "      <main-class>CLASS</main-class>" +
-                "      <file>" + jar.toString() +
-                            "," + rootJar.toString() +
-                            "," + file.toString() +
-                            ", " + rootFile.toString() + // with leading and 
trailing spaces
-                            "  ," + so.toString() +
-                            "," + rootSo.toString() +
-                            "," + so1.toString() +
-                            "," + rootSo1.toString() + "</file>\n" +
-                "      <archive>" + archive.toString() + ", "
-                            + rootArchive.toString() + " </archive>\n" + // 
with leading and trailing spaces
-                "</java>";
-
-        Element eActionXml = XmlUtils.parseXml(actionXml);
-
-        Context context = createContext(actionXml, null);
-
-        Path appPath = getAppPath();
-
-        JavaActionExecutor ae = new JavaActionExecutor();
-
-        Configuration jobConf = ae.createBaseHadoopConf(context, eActionXml);
-        ae.setupActionConf(jobConf, context, eActionXml, appPath);
-        ae.setLibFilesArchives(context, eActionXml, appPath, jobConf);
-
-
-        assertTrue(DistributedCache.getSymlink(jobConf));
-
-        Path[] filesInClasspath = DistributedCache.getFileClassPaths(jobConf);
-        for (Path p : new Path[]{new Path(getAppPath(), jar), rootJar}) {
-            boolean found = false;
-            for (Path c : filesInClasspath) {
-                if (!found && p.toUri().getPath().equals(c.toUri().getPath())) 
{
-                    found = true;
-                }
-            }
-            assertTrue("file " + p.toUri().getPath() + " not found in 
classpath", found);
-        }
-        for (Path p : new Path[]{new Path(getAppPath(), file), rootFile, new 
Path(getAppPath(), so), rootSo,
-                                new Path(getAppPath(), so1), rootSo1}) {
-            boolean found = false;
-            for (Path c : filesInClasspath) {
-                if (!found && p.toUri().getPath().equals(c.toUri().getPath())) 
{
-                    found = true;
-                }
-            }
-            assertFalse("file " + p.toUri().getPath() + " found in classpath", 
found);
-        }
-
-        URI[] filesInCache = DistributedCache.getCacheFiles(jobConf);
-        for (Path p : new Path[]{new Path(getAppPath(), jar), rootJar, new 
Path(getAppPath(), file), rootFile,
-                                new Path(getAppPath(), so), rootSo, new 
Path(getAppPath(), so1), rootSo1}) {
-            boolean found = false;
-            for (URI c : filesInCache) {
-                if (!found && p.toUri().getPath().equals(c.getPath())) {
-                    found = true;
-                }
-            }
-            assertTrue("file " + p.toUri().getPath() + " not found in cache", 
found);
-        }
-
-        URI[] archivesInCache = DistributedCache.getCacheArchives(jobConf);
-        for (Path p : new Path[]{new Path(getAppPath(), archive), 
rootArchive}) {
-            boolean found = false;
-            for (URI c : archivesInCache) {
-                if (!found && p.toUri().getPath().equals(c.getPath())) {
-                    found = true;
-                }
-            }
-            assertTrue("archive " + p.toUri().getPath() + " not found in 
cache", found);
-        }
-    }
-
     public void testPrepare() throws Exception {
         FileSystem fs = getFileSystem();
         Path mkdir = new Path(getFsTestCaseDir(), "mkdir");
@@ -1371,179 +1162,6 @@ public class TestJavaActionExecutor extends 
ActionExecutorTestCase {
         assertEquals("JAVA-OPT3 JAVA-OPT4 JAVA-OPT1 JAVA-OPT2", 
conf.get(MAPREDUCE_MAP_JAVA_OPTS));
     }
 
-    public void testActionLibsPath() throws Exception {
-        // Test adding a directory
-        Path actionLibPath = new Path(getFsTestCaseDir(), "actionlibs");
-        getFileSystem().mkdirs(actionLibPath);
-        Path jar1Path = new Path(actionLibPath, "jar1.jar");
-        getFileSystem().create(jar1Path).close();
-        Path jar2Path = new Path(actionLibPath, "jar2.jar");
-        getFileSystem().create(jar2Path).close();
-
-        String actionXml = "<java>" + "<job-tracker>" + getJobTrackerUri() + 
"</job-tracker>" +
-                "<name-node>" + getNameNodeUri() + "</name-node>" + 
"<configuration>" +
-                "<property><name>oozie.launcher.oozie.libpath</name><value>" + 
actionLibPath + "</value></property>" +
-                "</configuration>" + "<main-class>MAIN-CLASS</main-class>" +
-                "</java>";
-        Element eActionXml = XmlUtils.parseXml(actionXml);
-        Context context = createContext(actionXml, null);
-
-        JavaActionExecutor ae = new JavaActionExecutor();
-
-        Configuration jobConf = ae.createBaseHadoopConf(context, eActionXml);
-        ae.setupLauncherConf(jobConf, eActionXml, getAppPath(), context);
-        ae.setLibFilesArchives(context, eActionXml, getAppPath(), jobConf);
-
-        URI[] cacheFiles = DistributedCache.getCacheFiles(jobConf);
-        String cacheFilesStr = Arrays.toString(cacheFiles);
-        assertTrue(cacheFilesStr.contains(jar1Path.toString()));
-        assertTrue(cacheFilesStr.contains(jar2Path.toString()));
-
-        // Test adding a file
-        Path jar3Path = new Path(getFsTestCaseDir(), "jar3.jar");
-        getFileSystem().create(jar3Path).close();
-
-        actionXml = "<java>" + "<job-tracker>" + getJobTrackerUri() + 
"</job-tracker>" +
-                "<name-node>" + getNameNodeUri() + "</name-node>" + 
"<configuration>" +
-                "<property><name>oozie.launcher.oozie.libpath</name><value>" + 
jar3Path + "</value></property>" +
-                "</configuration>" + "<main-class>MAIN-CLASS</main-class>" +
-                "</java>";
-        eActionXml = XmlUtils.parseXml(actionXml);
-        context = createContext(actionXml, null);
-
-        ae = new JavaActionExecutor();
-
-        jobConf = ae.createBaseHadoopConf(context, eActionXml);
-        ae.setupLauncherConf(jobConf, eActionXml, getAppPath(), context);
-        ae.setLibFilesArchives(context, eActionXml, getAppPath(), jobConf);
-
-        cacheFiles = DistributedCache.getCacheFiles(jobConf);
-        cacheFilesStr = Arrays.toString(cacheFiles);
-        assertTrue(cacheFilesStr.contains(jar3Path.toString()));
-
-        // Test adding a directory and a file (comma separated)
-        actionXml = "<java>" + "<job-tracker>" + getJobTrackerUri() + 
"</job-tracker>" +
-                "<name-node>" + getNameNodeUri() + "</name-node>" + 
"<configuration>" +
-                "<property><name>oozie.launcher.oozie.libpath</name><value>" + 
actionLibPath + "," + jar3Path +
-                "</value></property>" +
-                "</configuration>" + "<main-class>MAIN-CLASS</main-class>" +
-                "</java>";
-        eActionXml = XmlUtils.parseXml(actionXml);
-        context = createContext(actionXml, null);
-
-        ae = new JavaActionExecutor();
-
-        jobConf = ae.createBaseHadoopConf(context, eActionXml);
-        ae.setupLauncherConf(jobConf, eActionXml, getAppPath(), context);
-        ae.setLibFilesArchives(context, eActionXml, getAppPath(), jobConf);
-
-        cacheFiles = DistributedCache.getCacheFiles(jobConf);
-        cacheFilesStr = Arrays.toString(cacheFiles);
-        assertTrue(cacheFilesStr.contains(jar1Path.toString()));
-        assertTrue(cacheFilesStr.contains(jar2Path.toString()));
-        assertTrue(cacheFilesStr.contains(jar3Path.toString()));
-    }
-
-    @Test
-    public void testAddActionShareLib() throws Exception {
-
-        WorkflowAppService wps = Services.get().get(WorkflowAppService.class);
-
-        Path systemLibPath = new Path(wps.getSystemLibPath(), 
ShareLibService.SHARE_LIB_PREFIX
-                + new SimpleDateFormat("yyyyMMddHHmmss").format(new 
Date()).toString());
-
-        Path javaShareLibPath = new Path(systemLibPath, "java");
-        getFileSystem().mkdirs(javaShareLibPath);
-        Path jar1Path = new Path(javaShareLibPath, "jar1.jar");
-        getFileSystem().create(jar1Path).close();
-        Path jar2Path = new Path(javaShareLibPath, "jar2.jar");
-        getFileSystem().create(jar2Path).close();
-
-        Path hcatShareLibPath = new Path(systemLibPath, "hcat");
-        getFileSystem().mkdirs(hcatShareLibPath);
-        Path jar3Path = new Path(hcatShareLibPath, "jar3.jar");
-        getFileSystem().create(jar3Path).close();
-        Path jar4Path = new Path(hcatShareLibPath, "jar4.jar");
-        getFileSystem().create(jar4Path).close();
-
-        Path otherShareLibPath = new Path(systemLibPath, "other");
-        getFileSystem().mkdirs(otherShareLibPath);
-        Path jar5Path = new Path(otherShareLibPath, "jar5.jar");
-        getFileSystem().create(jar5Path).close();
-
-        String actionXml = "<java>" + "<job-tracker>" + getJobTrackerUri() + 
"</job-tracker>" +
-                "<name-node>" + getNameNodeUri() + "</name-node>" +
-                "<main-class>MAIN-CLASS</main-class>" +
-                "</java>";
-        Element eActionXml = XmlUtils.parseXml(actionXml);
-        Context context = createContext(actionXml, null);
-
-        Services.get().setService(ShareLibService.class);
-
-        // Test oozie server action sharelib setting
-        WorkflowJobBean workflow = (WorkflowJobBean) context.getWorkflow();
-        XConfiguration wfConf = new XConfiguration();
-        wfConf.set(WorkflowAppService.HADOOP_USER, getTestUser());
-        wfConf.set(OozieClient.APP_PATH, new Path(getAppPath(), 
"workflow.xml").toString());
-        wfConf.setBoolean(OozieClient.USE_SYSTEM_LIBPATH, true);
-        workflow.setConf(XmlUtils.prettyPrint(wfConf).toString());
-
-        ConfigurationService.set("oozie.action.sharelib.for.java", 
"java,hcat");
-
-        JavaActionExecutor ae = new JavaActionExecutor();
-
-        Configuration jobConf = ae.createBaseHadoopConf(context, eActionXml);
-        ae.setupLauncherConf(jobConf, eActionXml, getAppPath(), context);
-        try {
-            ae.setLibFilesArchives(context, eActionXml, getAppPath(), jobConf);
-            fail();
-        } catch (ActionExecutorException aee) {
-            assertEquals("EJ001", aee.getErrorCode());
-            assertEquals("Could not locate Oozie sharelib", aee.getMessage());
-        }
-        Path launcherPath = new Path(systemLibPath, "oozie");
-        getFileSystem().mkdirs(launcherPath);
-        Path jar6Path = new Path(launcherPath, "jar6.jar");
-        getFileSystem().create(jar6Path).close();
-        Services.get().get(ShareLibService.class).updateShareLib();
-        ae.setLibFilesArchives(context, eActionXml, getAppPath(), jobConf);
-
-        URI[] cacheFiles = DistributedCache.getCacheFiles(jobConf);
-        String cacheFilesStr = Arrays.toString(cacheFiles);
-        assertTrue(cacheFilesStr.contains(jar1Path.toString()));
-        assertTrue(cacheFilesStr.contains(jar2Path.toString()));
-        assertTrue(cacheFilesStr.contains(jar3Path.toString()));
-        assertTrue(cacheFilesStr.contains(jar4Path.toString()));
-        assertFalse(cacheFilesStr.contains(jar5Path.toString()));
-        assertTrue(cacheFilesStr.contains(jar6Path.toString()));
-
-        // Test per workflow action sharelib setting
-        workflow = (WorkflowJobBean) context.getWorkflow();
-        wfConf = new XConfiguration();
-        wfConf.set(WorkflowAppService.HADOOP_USER, getTestUser());
-        wfConf.set(OozieClient.APP_PATH, new Path(getAppPath(), 
"workflow.xml").toString());
-        wfConf.setBoolean(OozieClient.USE_SYSTEM_LIBPATH, true);
-        wfConf.set("oozie.action.sharelib.for.java", "other,hcat");
-        workflow.setConf(XmlUtils.prettyPrint(wfConf).toString());
-
-        ConfigurationService.set("oozie.action.sharelib.for.java", "java");
-        ae = new JavaActionExecutor();
-
-        jobConf = ae.createBaseHadoopConf(context, eActionXml);
-        ae.setupLauncherConf(jobConf, eActionXml, getAppPath(), context);
-        ae.setLibFilesArchives(context, eActionXml, getAppPath(), jobConf);
-
-        cacheFiles = DistributedCache.getCacheFiles(jobConf);
-        cacheFilesStr = Arrays.toString(cacheFiles);
-        // The oozie server setting should have been overridden by workflow 
setting
-        assertFalse(cacheFilesStr.contains(jar1Path.toString()));
-        assertFalse(cacheFilesStr.contains(jar2Path.toString()));
-        assertTrue(cacheFilesStr.contains(jar3Path.toString()));
-        assertTrue(cacheFilesStr.contains(jar4Path.toString()));
-        assertTrue(cacheFilesStr.contains(jar5Path.toString()));
-        assertTrue(cacheFilesStr.contains(jar6Path.toString()));
-    }
-
     public void testAddShareLibSchemeAndAuthority() throws Exception {
         JavaActionExecutor ae = new JavaActionExecutor() {
             @Override
@@ -1563,8 +1181,7 @@ public class TestJavaActionExecutor extends 
ActionExecutorTestCase {
         new Services().init();
         // Create the dir
         WorkflowAppService wps = Services.get().get(WorkflowAppService.class);
-        Path systemLibPath = new Path(wps.getSystemLibPath(), 
ShareLibService.SHARE_LIB_PREFIX
-                + new SimpleDateFormat("yyyyMMddHHmmss").format(new 
Date()).toString());
+        Path systemLibPath = getNewSystemLibPath();
         Path javaShareLibPath = new Path(systemLibPath, 
"java-action-executor");
         getFileSystem().mkdirs(javaShareLibPath);
         Services.get().setService(ShareLibService.class);
@@ -1851,7 +1468,8 @@ public class TestJavaActionExecutor extends 
ActionExecutorTestCase {
 
         // Test when server side setting is not enabled
         Configuration launcherConf = ae.createLauncherConf(getFileSystem(), 
context, action, actionXml, actionConf);
-        assertEquals("false", 
launcherConf.get(JavaActionExecutor.HADOOP_YARN_TIMELINE_SERVICE_ENABLED)); // 
disabled by default
+        // disabled by default
+        assertEquals("false", 
launcherConf.get(JavaActionExecutor.HADOOP_YARN_TIMELINE_SERVICE_ENABLED));
 
         ConfigurationService.set("oozie.action.launcher." + 
JavaActionExecutor.HADOOP_YARN_TIMELINE_SERVICE_ENABLED, "true");
 
@@ -2129,8 +1747,7 @@ public class TestJavaActionExecutor extends 
ActionExecutorTestCase {
 
         WorkflowAppService wps = Services.get().get(WorkflowAppService.class);
 
-        Path systemLibPath = new Path(wps.getSystemLibPath(), 
ShareLibService.SHARE_LIB_PREFIX
-                + new SimpleDateFormat("yyyyMMddHHmmss").format(new 
Date()).toString());
+        Path systemLibPath = getNewSystemLibPath();
 
         File jarFile = IOUtils.createJar(new File(getTestCaseDir()), 
"sourcejar.jar", LauncherMainTester.class);
         InputStream is = new FileInputStream(jarFile);
diff --git 
a/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutorLibAddition.java
 
b/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutorLibAddition.java
new file mode 100644
index 0000000..00e7777
--- /dev/null
+++ 
b/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutorLibAddition.java
@@ -0,0 +1,448 @@
+/**
+ * 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.oozie.action.hadoop;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.filecache.DistributedCache;
+import org.apache.hadoop.fs.Path;
+import org.apache.oozie.WorkflowJobBean;
+import org.apache.oozie.action.ActionExecutorException;
+import org.apache.oozie.client.OozieClient;
+import org.apache.oozie.service.ConfigurationService;
+import org.apache.oozie.service.Services;
+import org.apache.oozie.service.ShareLibService;
+import org.apache.oozie.service.WorkflowAppService;
+import org.apache.oozie.util.IOUtils;
+import org.apache.oozie.util.XConfiguration;
+import org.apache.oozie.util.XmlUtils;
+import org.jdom.Element;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+
+import static 
org.apache.oozie.action.hadoop.JavaActionExecutor.ACTION_SHARELIB_FOR;
+import static 
org.apache.oozie.action.hadoop.JavaActionExecutor.SHARELIB_EXCLUDE_SUFFIX;
+
+public class TestJavaActionExecutorLibAddition extends ActionExecutorTestCase {
+
+    private static final String[] TEST_SHARELIB_OOZIE_FILES = {
+            "jackson-core-2.3.jar",
+            "jackson-databind-2.3.jar",
+            "other-lib.jar",
+            "oozie-library.jar",
+    };
+
+    private static final String[] TEST_SHARELIB_JAVA_FILES = {
+            "jackson-core-2.6.5.jar",
+            "jackson-databind-2.6.5.jar",
+            "some-lib.jar",
+            "another-lib.jar",
+    };
+
+    private static final String[] TEST_SHARELIB_PIG_FILES = {
+            "jackson-pig-0.3.3.jar",
+            "jackson-datapig-0.3.5.jar",
+            "pig_data.txt",
+    };
+
+    private static final String[] TEST_SHARELIB_USER_FILES = {
+            "jackson-user-3.3.jar",
+            "jackson-workflow-app.jar",
+            "user-job-utils.jar",
+            "jackson-files.zip"
+    };
+
+    private static final String[] TEST_SHARELIB_FILES = {
+            "soFile.so",
+            "soFile.so.1",
+            "file",
+            "jar.jar"
+    };
+
+    private static final String[] TEST_SHARELIB_ROOT_FILES = {
+            "rootSoFile.so",
+            "rootSoFile.so.1",
+            "rootFile",
+            "rootJar.jar"
+    };
+
+    private static final String[] TEST_SHARELIB_ARCHIVES = {
+            "archive.tar",
+            "rootArchive.tar",
+    };
+
+    @Override
+    protected void setSystemProps() throws Exception {
+        super.setSystemProps();
+        setHadoopSystemProps();
+        createActionConfDirFiles();
+    }
+
+    private void createActionConfDirFiles() throws IOException {
+        new File(getTestCaseConfDir(), "action-conf").mkdir();
+        InputStream is = 
Thread.currentThread().getContextClassLoader().getResourceAsStream("test-action-config.xml");
+        OutputStream os = new FileOutputStream(new File(getTestCaseConfDir() + 
"/action-conf", "java.xml"));
+        IOUtils.copyStream(is, os);
+    }
+
+    private void setHadoopSystemProps() {
+        setSystemProperty("oozie.service.ActionService.executor.classes", 
JavaActionExecutor.class.getName());
+        
setSystemProperty("oozie.service.HadoopAccessorService.action.configurations",
+                "*=hadoop-conf," + getJobTrackerUri() + "=action-conf");
+        setSystemProperty(WorkflowAppService.SYSTEM_LIB_PATH, 
getFsTestCaseDir().toUri().getPath() + "/systemlib");
+    }
+
+    private Map<String, Path> setupTestShareLibExcludeTestJars(final Path 
systemLibPath) throws Exception {
+        final Path oozieShareLibPath = new Path(systemLibPath, "oozie");
+        final Path javaShareLibPath = new Path(systemLibPath, "java");
+        final Path pigShareLibPath = new Path(systemLibPath, new Path("pig", 
"lib"));
+        final Path actionLibPath = new Path(getAppPath(), "lib");
+        makeDirs(oozieShareLibPath, javaShareLibPath, pigShareLibPath, 
actionLibPath);
+
+        final Map<String, Path> libs = new LinkedHashMap<>();
+        loadLibPathsToMap(libs, oozieShareLibPath, TEST_SHARELIB_OOZIE_FILES);
+        loadLibPathsToMap(libs, javaShareLibPath, TEST_SHARELIB_JAVA_FILES);
+        loadLibPathsToMap(libs, pigShareLibPath, TEST_SHARELIB_PIG_FILES);
+        loadLibPathsToMap(libs, actionLibPath, TEST_SHARELIB_USER_FILES);
+        createFiles(libs.values());
+
+        return libs;
+    }
+
+    private void loadLibPathsToMap(Map<String, Path> libMap, Path root, 
String... files) {
+        for (String f : files) {
+            libMap.put(f, new Path(root, f));
+        }
+    }
+
+    private void checkLibExclude(final String... libsToBeExcluded) throws 
Exception {
+        final int LIBS_ADDED_BY_TESTS = 6;
+        final Map<String, Path> libs = 
setupTestShareLibExcludeTestJars(getNewSystemLibPath());
+        final Path actionLibPath = new Path(getAppPath(), "lib");
+        final Context context = createContextUsingSharelib(actionLibPath);
+
+        createWorkflowJobUsingSharelib(context);
+        setSharelibForActionInConfiguration("java,pig");
+
+        final Configuration jobConf = 
createActionExecutorAndSetupServices(context);
+        final URI[] cacheFiles = DistributedCache.getCacheFiles(jobConf);
+        final String cacheFilesStr = getDistributedCacheFilesStr(jobConf);
+
+        for (final String lib : libsToBeExcluded) {
+            assertFalse(lib + " should have been excluded from distributed 
cache",
+                    cacheFilesStr.contains(libs.get(lib).toString()));
+        }
+        assertEquals("The number of files on distributed cache is not what 
expected.",
+                libs.size() - libsToBeExcluded.length + LIBS_ADDED_BY_TESTS, 
cacheFiles.length);
+    }
+
+    private Context createContextUsingSharelib(final Path actionLibPath) 
throws Exception {
+        final String actionXml = String.format("<java>" +
+                "<job-tracker>%s</job-tracker>" +
+                "<name-node>%s</name-node>" +
+                "<configuration>" +
+                "<property>" +
+                "<name>oozie.launcher.oozie.libpath</name>" +
+                "<value>%s</value>" +
+                "</property>" +
+                "</configuration>" +
+                "<main-class>MAIN-CLASS</main-class>" +
+                "</java>", getJobTrackerUri(), getNameNodeUri(), 
actionLibPath);
+
+        return createContext(actionXml, null);
+    }
+
+    private void createWorkflowJobUsingSharelib(final Context context, final 
XConfiguration wfConf) {
+        final WorkflowJobBean workflow = (WorkflowJobBean) 
context.getWorkflow();
+        wfConf.set(WorkflowAppService.HADOOP_USER, getTestUser());
+        wfConf.set(OozieClient.APP_PATH, new Path(getAppPath(), 
"workflow.xml").toString());
+        wfConf.setBoolean(OozieClient.USE_SYSTEM_LIBPATH, true);
+        workflow.setConf(XmlUtils.prettyPrint(wfConf).toString());
+    }
+
+    private void createWorkflowJobUsingSharelib(final Context context) {
+        createWorkflowJobUsingSharelib(context, new XConfiguration());
+    }
+
+    private Configuration createActionExecutorAndSetupServices(final Context 
context) throws Exception {
+        Services.get().setService(ShareLibService.class);
+        final Element eActionXml = 
XmlUtils.parseXml(context.getAction().getConf());
+        final JavaActionExecutor ae = new JavaActionExecutor();
+        final Configuration jobConf = ae.createBaseHadoopConf(context, 
eActionXml);
+        ae.setupLauncherConf(jobConf, eActionXml, getAppPath(), context);
+        Services.get().get(ShareLibService.class).updateShareLib();
+        ae.setLibFilesArchives(context, eActionXml, getAppPath(), jobConf);
+        return jobConf;
+    }
+
+    private Configuration createActionExecutorAndSetLibFilesArchives(final 
Context context) throws Exception {
+        final Element eActionXml = 
XmlUtils.parseXml(context.getAction().getConf());
+        final JavaActionExecutor ae = new JavaActionExecutor();
+        final Configuration jobConf = ae.createBaseHadoopConf(context, 
eActionXml);
+        ae.setupLauncherConf(jobConf, eActionXml, getAppPath(), context);
+        ae.setLibFilesArchives(context, eActionXml, getAppPath(), jobConf);
+        return jobConf;
+    }
+
+    private void setExcludePatternInConfiguration(String pattern) {
+        ConfigurationService.set(ACTION_SHARELIB_FOR + "java" + 
SHARELIB_EXCLUDE_SUFFIX, pattern);
+    }
+
+    private void setSharelibForActionInConfiguration(String libs) {
+        ConfigurationService.set(ACTION_SHARELIB_FOR + "java", libs);
+    }
+
+    public void testExcludeFilesFromAllSharelibLocation() throws Exception {
+        setExcludePatternInConfiguration(".*jackson.*");
+        checkLibExclude(TEST_SHARELIB_OOZIE_FILES[0], 
TEST_SHARELIB_OOZIE_FILES[1],
+                TEST_SHARELIB_JAVA_FILES[0], TEST_SHARELIB_JAVA_FILES[1],
+                TEST_SHARELIB_PIG_FILES[0], TEST_SHARELIB_PIG_FILES[1],
+                TEST_SHARELIB_USER_FILES[0], TEST_SHARELIB_USER_FILES[1], 
TEST_SHARELIB_USER_FILES[3]);
+    }
+
+    public void testExcludeFilesFromAllOozieSharelibFolder() throws Exception {
+        setExcludePatternInConfiguration("oozie/jackson.*");
+        checkLibExclude(TEST_SHARELIB_OOZIE_FILES[0], 
TEST_SHARELIB_OOZIE_FILES[1]);
+    }
+
+    public void testExcludeFilesFromMultipleLocations() throws Exception {
+        
setExcludePatternInConfiguration("pig/lib/jackson.*|java/jackson.*|oozie/jackson.*");
+        checkLibExclude(TEST_SHARELIB_OOZIE_FILES[0], 
TEST_SHARELIB_OOZIE_FILES[1],
+                TEST_SHARELIB_JAVA_FILES[0], TEST_SHARELIB_JAVA_FILES[1],
+                TEST_SHARELIB_PIG_FILES[0], TEST_SHARELIB_PIG_FILES[1]);
+    }
+
+    public void testExcludeUserProvidedFiles() throws Exception {
+        setExcludePatternInConfiguration(".*/app/lib/jackson.*");
+        checkLibExclude(TEST_SHARELIB_USER_FILES[0], 
TEST_SHARELIB_USER_FILES[1], TEST_SHARELIB_USER_FILES[3]);
+    }
+
+    public void testAddActionShareLib() throws Exception {
+        final Path systemLibPath = getNewSystemLibPath();
+        final Path actionLibPath = new Path(getAppPath(), "lib");
+
+        final Path javaShareLibPath = new Path(systemLibPath, "java");
+        final Path jar1Path = new Path(javaShareLibPath, "jar1.jar");
+        final Path jar2Path = new Path(javaShareLibPath, "jar2.jar");
+
+        final Path hcatShareLibPath = new Path(systemLibPath, "hcat");
+        final Path jar3Path = new Path(hcatShareLibPath, "jar3.jar");
+        final Path jar4Path = new Path(hcatShareLibPath, "jar4.jar");
+
+        final Path otherShareLibPath = new Path(systemLibPath, "other");
+        final Path jar5Path = new Path(otherShareLibPath, "jar5.jar");
+
+        makeDirs(javaShareLibPath, hcatShareLibPath, otherShareLibPath);
+        createFiles(Arrays.asList(jar1Path, jar2Path, jar3Path, jar4Path, 
jar5Path));
+
+        final Context context = createContextUsingSharelib(actionLibPath);
+        createWorkflowJobUsingSharelib(context);
+        setSharelibForActionInConfiguration("java,hcat");
+
+        try {
+            createActionExecutorAndSetupServices(context);
+            fail("Expected ActionExecutorException to be thrown, but got 
nothing.");
+        }
+        catch (ActionExecutorException aee) {
+            assertEquals("Unexpected error code. Message: " + 
aee.getMessage(), "EJ001", aee.getErrorCode());
+            assertEquals("Unexpected error message","Could not locate Oozie 
sharelib", aee.getMessage());
+        }
+
+        final Path launcherPath = new Path(systemLibPath, "oozie");
+        final Path jar6Path = new Path(launcherPath, "jar6.jar");
+        makeDirs(launcherPath);
+        getFileSystem().create(jar6Path).close();
+
+        Configuration jobConf = createActionExecutorAndSetupServices(context);
+        String cacheFilesStr = getDistributedCacheFilesStr(jobConf);
+
+        assertContainsJars( cacheFilesStr, Arrays.asList(jar1Path, jar2Path, 
jar3Path, jar4Path, jar6Path));
+        assertNotContainsJars( cacheFilesStr, 
Collections.singletonList(jar5Path));
+
+        final XConfiguration wfConf = new XConfiguration();
+        wfConf.set(ACTION_SHARELIB_FOR + "java", "other,hcat");
+        createWorkflowJobUsingSharelib(context, wfConf);
+        setSharelibForActionInConfiguration("java");
+        jobConf = createActionExecutorAndSetupServices(context);
+
+        // The oozie server setting should have been overridden by workflow 
setting
+        cacheFilesStr = getDistributedCacheFilesStr(jobConf);
+        assertContainsJars(cacheFilesStr, Arrays.asList(jar3Path, jar4Path, 
jar5Path, jar6Path));
+        assertNotContainsJars(cacheFilesStr, Arrays.asList(jar1Path, 
jar2Path));
+    }
+
+    private Path getActionLibPath() throws Exception {
+        Path actionLibPath = new Path(getFsTestCaseDir(), "actionlibs");
+        makeDirs(actionLibPath);
+        return actionLibPath;
+    }
+
+    private List<Path> createTestActionLibPaths(Path... paths) throws 
Exception{
+        final Path actionLibPath = new Path(getFsTestCaseDir(), "actionlibs");
+        makeDirs(actionLibPath);
+        createFiles(Arrays.asList(paths));
+        return Arrays.asList(paths);
+    }
+
+    public void testAddingActionLibDir() throws Exception{
+        makeDirs(getActionLibPath());
+        List<Path> expectedJars = createTestActionLibPaths(
+                new Path(getActionLibPath(), "jar1.jar"),
+                new Path(getActionLibPath(), "jar2.jar"));
+
+        Context context = createContextUsingSharelib(getActionLibPath());
+        Configuration jobConf = 
createActionExecutorAndSetLibFilesArchives(context);
+        assertContainsJars(getDistributedCacheFilesStr(jobConf), expectedJars);
+    }
+
+    public void testAddingActionLibFile() throws Exception{
+        List<Path> expectedJars = createTestActionLibPaths(new 
Path(getFsTestCaseDir(), "jar3.jar"));
+
+        String actionXml = "<java>" + "<job-tracker>" + getJobTrackerUri() + 
"</job-tracker>" +
+                "<name-node>" + getNameNodeUri() + "</name-node>" + 
"<configuration>" +
+                "<property><name>oozie.launcher.oozie.libpath</name><value>" + 
expectedJars.get(0) + "</value></property>" +
+                "</configuration>" + "<main-class>MAIN-CLASS</main-class>" +
+                "</java>";
+        Context context = createContext(actionXml, null);
+        Configuration jobConf = 
createActionExecutorAndSetLibFilesArchives(context);
+        assertContainsJars(getDistributedCacheFilesStr(jobConf), expectedJars);
+    }
+
+    public void testActionLibFileAndDir() throws Exception {
+        makeDirs(getActionLibPath());
+        List<Path> expectedJars = createTestActionLibPaths(
+                new Path(getActionLibPath(), "jar1.jar"),
+                new Path(getActionLibPath(), "jar2.jar"),
+                new Path(getFsTestCaseDir(), "jar3.jar"));
+
+        String actionXml = "<java>" + "<job-tracker>" + getJobTrackerUri() + 
"</job-tracker>" +
+                "<name-node>" + getNameNodeUri() + "</name-node>" + 
"<configuration>" +
+                "<property><name>oozie.launcher.oozie.libpath</name><value>" + 
getActionLibPath() + "," + expectedJars.get(2) +
+                "</value></property>" +
+                "</configuration>" + "<main-class>MAIN-CLASS</main-class>" +
+                "</java>";
+        Context context = createContext(actionXml, null);
+        Configuration jobConf = 
createActionExecutorAndSetLibFilesArchives(context);
+        assertContainsJars(getDistributedCacheFilesStr(jobConf), expectedJars);
+    }
+
+    private String getDistributedCacheFilesStr(final Configuration jobConf) 
throws IOException {
+        return Arrays.toString(DistributedCache.getCacheFiles(jobConf));
+    }
+
+    private Map<String, Path> createAndGetSharelibTestFiles() throws Exception 
{
+        Path rootPath = new Path(getFsTestCaseDir(), "root");
+        Map<String, Path> libs = new LinkedHashMap<>();
+        loadLibPathsToMap(libs, getAppPath(), TEST_SHARELIB_FILES);
+        loadLibPathsToMap(libs, rootPath, TEST_SHARELIB_ROOT_FILES);
+        loadLibPathsToMap(libs, getAppPath(), TEST_SHARELIB_ARCHIVES[0]);
+        loadLibPathsToMap(libs, rootPath, TEST_SHARELIB_ARCHIVES[1]);
+        createFiles(libs.values());
+        return libs;
+    }
+
+    public void testLibFileArchives() throws Exception {
+        Map<String, Path> libs = createAndGetSharelibTestFiles();
+
+        final String actionXml = "<java>" +
+                "      <job-tracker>" + getJobTrackerUri() + "</job-tracker>" +
+                "      <name-node>" + getNameNodeUri() + "</name-node>" +
+                "      <main-class>CLASS</main-class>" +
+                "      <file>" + libs.get(TEST_SHARELIB_FILES[0]).toString() + 
"</file>\n" +
+                "      <file>" + libs.get(TEST_SHARELIB_FILES[1]).toString() + 
"</file>\n" +
+                "      <file>" + libs.get(TEST_SHARELIB_FILES[2]).toString() + 
"</file>\n" +
+                "      <file>" + libs.get(TEST_SHARELIB_FILES[3]).toString() + 
"</file>\n" +
+                "      <file>" + 
libs.get(TEST_SHARELIB_ROOT_FILES[0]).toString() + "</file>\n" +
+                "      <file>" + 
libs.get(TEST_SHARELIB_ROOT_FILES[1]).toString() + "</file>\n" +
+                "      <file>" + 
libs.get(TEST_SHARELIB_ROOT_FILES[2]).toString() + "</file>\n" +
+                "      <file>" + 
libs.get(TEST_SHARELIB_ROOT_FILES[3]).toString() + "</file>\n" +
+                "      <archive>" + 
libs.get(TEST_SHARELIB_ARCHIVES[0]).toString() + "</archive>\n" +
+                "      <archive>" + 
libs.get(TEST_SHARELIB_ARCHIVES[1]).toString() + "</archive>\n" +
+                "</java>";
+
+        final Configuration jobConf = 
createActionExecutorAndSetLibFilesArchives(createContext(actionXml, null));
+        verifyFilesInDistributedCache(libs, jobConf);
+    }
+
+    public void testCommaSeparatedFilesAndArchives() throws Exception {
+        Map<String, Path> libs = createAndGetSharelibTestFiles();
+
+        final String actionXml = "<java>" +
+                "      <job-tracker>" + getJobTrackerUri() + "</job-tracker>" +
+                "      <name-node>" + getNameNodeUri() + "</name-node>" +
+                "      <main-class>CLASS</main-class>" +
+                "      <file>" + libs.get(TEST_SHARELIB_FILES[3]).toString() +
+                "," + libs.get(TEST_SHARELIB_ROOT_FILES[3]).toString() +
+                "," + libs.get(TEST_SHARELIB_FILES[2]).toString() +
+                ", " + libs.get(TEST_SHARELIB_ROOT_FILES[2]).toString() + // 
with leading and trailing spaces
+                "  ," + libs.get(TEST_SHARELIB_FILES[0]).toString() +
+                "," + libs.get(TEST_SHARELIB_ROOT_FILES[0]).toString() +
+                "," + libs.get(TEST_SHARELIB_FILES[1]).toString() +
+                "," + libs.get(TEST_SHARELIB_ROOT_FILES[1]).toString() + 
"</file>\n" +
+                "      <archive>" + 
libs.get(TEST_SHARELIB_ARCHIVES[0]).toString() + ", "
+                + libs.get(TEST_SHARELIB_ARCHIVES[1]).toString() + " 
</archive>\n" + // with leading and trailing spaces
+                "</java>";
+
+        final Configuration jobConf = 
createActionExecutorAndSetLibFilesArchives(createContext(actionXml, null));
+        verifyFilesInDistributedCache(libs, jobConf);
+    }
+
+    private void verifyFilesInDistributedCache(Map<String, Path> libs, final 
Configuration jobConf) throws Exception {
+        assertTrue(DistributedCache.getSymlink(jobConf));
+
+        String filesInClassPathString = 
Arrays.toString(DistributedCache.getFileClassPaths(jobConf));
+        assertContainsJars(filesInClassPathString, Arrays.asList(
+                libs.get(TEST_SHARELIB_FILES[3]),
+                libs.get(TEST_SHARELIB_ROOT_FILES[3])));
+
+        assertNotContainsJars(filesInClassPathString, Arrays.asList(
+                libs.get(TEST_SHARELIB_FILES[0]),
+                libs.get(TEST_SHARELIB_FILES[1]),
+                libs.get(TEST_SHARELIB_FILES[2]),
+                libs.get(TEST_SHARELIB_ROOT_FILES[0]),
+                libs.get(TEST_SHARELIB_ROOT_FILES[1]),
+                libs.get(TEST_SHARELIB_ROOT_FILES[2])));
+
+        filesInClassPathString = 
Arrays.toString(DistributedCache.getCacheFiles(jobConf));
+        assertContainsJars(filesInClassPathString, Arrays.asList(
+                libs.get(TEST_SHARELIB_FILES[0]),
+                libs.get(TEST_SHARELIB_FILES[1]),
+                libs.get(TEST_SHARELIB_FILES[2]),
+                libs.get(TEST_SHARELIB_FILES[3]),
+                libs.get(TEST_SHARELIB_ROOT_FILES[0]),
+                libs.get(TEST_SHARELIB_ROOT_FILES[1]),
+                libs.get(TEST_SHARELIB_ROOT_FILES[2]),
+                libs.get(TEST_SHARELIB_ROOT_FILES[3])));
+
+        filesInClassPathString = 
Arrays.toString(DistributedCache.getCacheArchives(jobConf));
+        assertContainsJars(filesInClassPathString,  Arrays.asList(
+                libs.get(TEST_SHARELIB_ARCHIVES[0]),
+                libs.get(TEST_SHARELIB_ARCHIVES[1])));
+    }
+}
diff --git 
a/core/src/test/java/org/apache/oozie/action/hadoop/TestShareLibExcluder.java 
b/core/src/test/java/org/apache/oozie/action/hadoop/TestShareLibExcluder.java
new file mode 100644
index 0000000..e92bd3f
--- /dev/null
+++ 
b/core/src/test/java/org/apache/oozie/action/hadoop/TestShareLibExcluder.java
@@ -0,0 +1,233 @@
+/**
+ * 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.oozie.action.hadoop;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.oozie.util.XConfiguration;
+
+import static 
org.apache.oozie.action.hadoop.JavaActionExecutor.ACTION_SHARELIB_FOR;
+import static 
org.apache.oozie.action.hadoop.JavaActionExecutor.SHARELIB_EXCLUDE_SUFFIX;
+import static org.apache.oozie.action.hadoop.ShareLibExcluder.VALUE_NULL_MSG;
+
+public class TestShareLibExcluder {
+
+    private static final String[] EMPTY_ARRAY = {};
+    private ShareLibExcluder shareLibExcluder;
+    private Configuration actionConf;
+    private Configuration servicesConf;
+    private XConfiguration jobConf;
+    private static final String executorType = "spark";
+    private static final String excludeProperty = ACTION_SHARELIB_FOR + 
executorType + SHARELIB_EXCLUDE_SUFFIX;
+    private static URI sharelibRootURI;
+
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    private static final String SHARELIB_ROOT = 
"/user/oozie/share/lib/lib20180612/";
+    private static final String[] OOZIE_SHARELIB_JARS = {
+            SHARELIB_ROOT + "oozie/jackson-core-2.3.jar",
+            SHARELIB_ROOT + "oozie/jackson-databind-2.3.jar",
+            SHARELIB_ROOT + "oozie/other-lib.jar",
+            SHARELIB_ROOT + "oozie/oozie-library.jar"
+    };
+    private static final String[] SPARK_SHARELIB_JARS = {
+            SHARELIB_ROOT + "spark/jackson-core-2.6.5.jar",
+            SHARELIB_ROOT + "spark/jackson-databind-2.6.5.jar",
+            SHARELIB_ROOT + "spark/spark-lib.jar",
+            SHARELIB_ROOT + "spark/lib/another-lib.jar"
+    };
+    private static final String[] PIG_SHARELIB_JARS = {
+            SHARELIB_ROOT + "pig/lib/jackson-pig-0.3.3.jar",
+            SHARELIB_ROOT + "pig/lib/jackson-datapig-0.3.5.jar",
+            SHARELIB_ROOT + "pig/temp/pig_data.txt"
+    };
+
+    private List<String> libs;
+
+    private static final String PIG_LIB_PATTERN = "pig/lib.*";
+    private static final String ALL_JARS_PATTERN = ".*";
+    private static final String ALL_JACKSON_PATTERN = ".*jackson.*";
+    private static final String OOZIE_JACKSON_PATTERN = "oozie/jackson.*";
+    private static final String SPARK_JACKSON_PATTERN = "spark/jackson.*";
+    private static final String PIG_LIB_JACKSON_SPARK_JACKSON_PATTERN = 
"pig/lib/jackson.*|spark/jackson.*";
+    private static final String ALL_EXCEPT_OOZIE_PATTERN = "^(?!.*oozie).*$";
+
+    @Before
+    public void setUp() {
+        libs = new LinkedList<>();
+        libs.addAll(Arrays.asList(OOZIE_SHARELIB_JARS));
+        libs.addAll(Arrays.asList(SPARK_SHARELIB_JARS));
+        libs.addAll(Arrays.asList(PIG_SHARELIB_JARS));
+
+        sharelibRootURI = URI.create(SHARELIB_ROOT);
+        actionConf = new Configuration();
+        servicesConf = new Configuration();
+        jobConf = new XConfiguration();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        shareLibExcluder = null;
+    }
+
+    private void doShareLibExclude(final String excludePattern, final 
String... libsExpectedToExclude) {
+        doShareLibExclude(excludePattern, sharelibRootURI, 
libsExpectedToExclude);
+    }
+
+    private void doShareLibExclude(final String excludePattern, URI rootURI, 
final String... libsExpectedToExclude) {
+        jobConf.set(excludeProperty, excludePattern);
+        shareLibExcluder = new ShareLibExcluder(actionConf, servicesConf, 
jobConf, executorType, rootURI);
+        checkShareLibExclude(libsExpectedToExclude);
+    }
+
+    private void checkShareLibExclude(final String... libsExpectedToExclude) {
+        libs.removeAll(Arrays.asList(libsExpectedToExclude));
+
+        for (String excludeLibPath : libsExpectedToExclude) {
+            Assert.assertTrue("Lib path is not excluded, but should be",
+                    
shareLibExcluder.shouldExclude(URI.create(excludeLibPath)));
+        }
+
+        for (String dontExcludeLibPath : libs) {
+            Assert.assertFalse("Lib path is excluded, but should not be",
+                    
shareLibExcluder.shouldExclude(URI.create(dontExcludeLibPath)));
+        }
+    }
+
+    @Test
+    public void testExcludeLibsFromEverywhere() {
+        doShareLibExclude(ALL_JACKSON_PATTERN,
+                OOZIE_SHARELIB_JARS[0], OOZIE_SHARELIB_JARS[1],
+                SPARK_SHARELIB_JARS[0], SPARK_SHARELIB_JARS[1],
+                PIG_SHARELIB_JARS[0], PIG_SHARELIB_JARS[1]);
+    }
+
+    @Test
+    public void testExcludeLibsFromOozieDirOnly() {
+        doShareLibExclude(OOZIE_JACKSON_PATTERN, OOZIE_SHARELIB_JARS[0], 
OOZIE_SHARELIB_JARS[1]);
+    }
+
+    @Test
+    public void testExcludeLibsFromSparkDirOnly() {
+        doShareLibExclude(SPARK_JACKSON_PATTERN, SPARK_SHARELIB_JARS[0], 
SPARK_SHARELIB_JARS[1]);
+    }
+
+    @Test
+    public void testExcludeLibsFromPigAndSparkDirOnly() {
+        doShareLibExclude(PIG_LIB_JACKSON_SPARK_JACKSON_PATTERN,
+                PIG_SHARELIB_JARS[0], PIG_SHARELIB_JARS[1],
+                SPARK_SHARELIB_JARS[0], SPARK_SHARELIB_JARS[1]);
+    }
+
+    @Test
+    public void testDontExcludeSharelibRoot() {
+        doShareLibExclude(SHARELIB_ROOT + PIG_LIB_PATTERN, EMPTY_ARRAY);
+    }
+
+    @Test
+    public void testDontExcludeWithNotSetExcludeConfiguration() {
+        shareLibExcluder = new ShareLibExcluder(actionConf, servicesConf, 
jobConf, executorType, sharelibRootURI);
+        checkShareLibExclude(EMPTY_ARRAY);
+    }
+
+    @Test
+    public void testDontExcludeWithNullRootURIValue() {
+        doShareLibExclude(PIG_LIB_PATTERN, null, EMPTY_ARRAY);
+    }
+
+    @Test
+    public void testDontExcludeWithNullExecutorType() {
+        jobConf.set(excludeProperty, PIG_LIB_PATTERN);
+        shareLibExcluder = new ShareLibExcluder(actionConf, servicesConf, 
jobConf, null, sharelibRootURI);
+        checkShareLibExclude(EMPTY_ARRAY);
+    }
+
+    @Test
+    public void testForExceptionsWhenIllegalActionConfParameterPassed() {
+        thrown.expect(NullPointerException.class);
+        thrown.expectMessage(String.format(VALUE_NULL_MSG, "actionConf"));
+        shareLibExcluder = new ShareLibExcluder(null, servicesConf, jobConf, 
executorType, sharelibRootURI);
+    }
+
+    @Test
+    public void testForExceptionsWhenIllegalServicesConfParameterPassed() {
+        thrown.expect(NullPointerException.class);
+        thrown.expectMessage(String.format(VALUE_NULL_MSG, "servicesConf"));
+        shareLibExcluder = new ShareLibExcluder(actionConf, null, jobConf, 
executorType, sharelibRootURI);
+    }
+
+    @Test
+    public void testForExceptionsWhenIllegalJobConfParameterPassed() {
+        thrown.expect(NullPointerException.class);
+        thrown.expectMessage(String.format(VALUE_NULL_MSG, "jobConf"));
+        shareLibExcluder = new ShareLibExcluder(actionConf, servicesConf, 
null, executorType, sharelibRootURI);
+    }
+
+    @Test
+    public void testGetExcludePropertyFromConfigurations() {
+        actionConf.set(excludeProperty, ALL_JARS_PATTERN);
+        jobConf.set(excludeProperty, ALL_JARS_PATTERN);
+
+        shareLibExcluder = new ShareLibExcluder(actionConf, servicesConf, 
jobConf, executorType, sharelibRootURI);
+        jobConf.unset(excludeProperty);
+        Assert.assertNotNull(actionConf.get(excludeProperty, null));
+
+        actionConf.unset(excludeProperty);
+        servicesConf.set(excludeProperty, ALL_JARS_PATTERN);
+        shareLibExcluder = new ShareLibExcluder(actionConf, servicesConf, 
jobConf, executorType, sharelibRootURI);
+        Assert.assertNotNull(actionConf.get(excludeProperty, null));
+    }
+
+    @Test
+    public void testExcludeAllExceptOozie() {
+        doShareLibExclude(ALL_EXCEPT_OOZIE_PATTERN,
+                SPARK_SHARELIB_JARS[0], SPARK_SHARELIB_JARS[1], 
SPARK_SHARELIB_JARS[2], SPARK_SHARELIB_JARS[3],
+                PIG_SHARELIB_JARS[0], PIG_SHARELIB_JARS[1],  
PIG_SHARELIB_JARS[2]);
+    }
+
+    @Test
+    public void testExcludeAll() {
+        String[] libArray = new String[libs.size()];
+        doShareLibExclude(ALL_JARS_PATTERN, libs.toArray(libArray));
+    }
+
+    @Test
+    public void testWithNullLibPathArgShouldThrowException() {
+        servicesConf.set(excludeProperty, ALL_JACKSON_PATTERN);
+        shareLibExcluder = new ShareLibExcluder(actionConf, servicesConf, 
jobConf, executorType, sharelibRootURI);
+
+        // expect exception when illegal parameters passed
+        thrown.expect(NullPointerException.class);
+        thrown.expectMessage(String.format(VALUE_NULL_MSG, "actionLibURI"));
+        shareLibExcluder.shouldExclude(null);
+    }
+}
diff --git a/docs/src/site/markdown/WorkflowFunctionalSpec.md 
b/docs/src/site/markdown/WorkflowFunctionalSpec.md
index 7d6a31b..0eae0b5 100644
--- a/docs/src/site/markdown/WorkflowFunctionalSpec.md
+++ b/docs/src/site/markdown/WorkflowFunctionalSpec.md
@@ -2633,6 +2633,60 @@ For example: When using HCatLoader and HCatStorer in 
pig, `oozie.action.sharelib
 both pig and hcatalog jars.
 
 <a name="UserRetryWFActions"></a>
+
+### 17.2 Action Share Library Exclude (since Oozie 5.2)
+
+Oozie allows to exclude files on its share library directory from being added 
to the Distributed Cache. This feature is useful to
+prevent the submitted applications from runtime jar conflict issues.
+
+The unwanted files can be left out by setting 
`oozie.action.sharelib.for.#ACTIONTYPE#.exclude` configuration to a regex 
pattern.
+Libraries matching the pattern will not be added to the Distributed Cache.
+
+The configuration is supported on action, job, and oozie server configuration 
level.
+The precedence order is the same as in the previous 17.1 paragraph.
+
+*One should be very careful as it is easy to exclude very basic oozie jars 
with a wrongly set exclude pattern.*
+
+Examples for using sharelib exclude on a java action:
+Actual share library content:
+
+```
+   /user/oozie/share/lib/lib20180701/oozie/lib-one-1.5.jar
+   /user/oozie/share/lib/lib20180701/oozie/lib-two-1.5.jar
+   /user/oozie/share/lib/lib20180701/java/lib-one-2.6.jar
+   /user/oozie/share/lib/lib20180701/java/lib-two-2.6.jar
+   /user/oozie/share/lib/lib20180701/java/component-connector.jar
+```
+
+If not setting `oozie.action.sharelib.for.java.exclude`, none of the jars will 
be excluded.
+
+By setting `oozie.action.sharelib.for.java.exclude` to `oozie/lib-one.*` the 
expected Distributed Cache content is:
+
+```
+   /user/oozie/share/lib/lib20180701/oozie/lib-two-1.5.jar
+   /user/oozie/share/lib/lib20180701/java/lib-one-2.6.jar
+   /user/oozie/share/lib/lib20180701/java/lib-two-2.6.jar
+   /user/oozie/share/lib/lib20180701/java/component-connector.jar
+```
+
+By setting `oozie.action.sharelib.for.java.exclude` to 
`oozie/lib-one.*|component-connector.jar`
+the expected Distributed Cache content is:
+
+```
+   /user/oozie/share/lib/lib20180701/oozie/lib-two-1.5.jar
+   /user/oozie/share/lib/lib20180701/java/lib-one-2.6.jar
+   /user/oozie/share/lib/lib20180701/java/lib-two-2.6.jar
+```
+
+By setting `oozie.action.sharelib.for.java.exclude` to `oozie/lib-*2.6.*`
+the expected Distributed Cache content is:
+
+```
+   /user/oozie/share/lib/lib20180701/oozie/lib-one-1.5.jar
+   /user/oozie/share/lib/lib20180701/oozie/lib-two-1.5.jar
+   /user/oozie/share/lib/lib20180701/java/component-connector.jar
+```
+
 ## 18 User-Retry for Workflow Actions (since Oozie 3.1)
 
 Oozie provides User-Retry capabilities when an action is in `ERROR` or 
`FAILED` state.
diff --git a/release-log.txt b/release-log.txt
index cc8bffc..2302a02 100644
--- a/release-log.txt
+++ b/release-log.txt
@@ -1,5 +1,6 @@
 -- Oozie 5.2.0 release (trunk - unreleased)
 
+OOZIE-1624 Exclusion pattern for sharelib JARs (puru, matijhs via asalamon74, 
andras.piros)
 OOZIE-2693 SimpleHCatDependencyCache.removeMissingDependency can throw NPE 
(puru via asalamon74)
 OOZIE-3442 Check and eliminate builds/runHudsonCIBuild.sh (nobigo via 
asalamon74)
 OOZIE-1702 [build] Fix Javadoc warnings (dionusos via kmarton)

Reply via email to