OOZIE-3526 Global job-xml not being overwritten by job-xml specified for an action (mgogineni via rohini)
diff --git a/core/src/main/java/org/apache/oozie/workflow/lite/LiteWorkflowAppParser.java b/core/src/main/java/org/apache/oozie/workflow/lite/LiteWorkflowAppParser.java
index ae0cc76..1f121c5 100644
--- a/core/src/main/java/org/apache/oozie/workflow/lite/LiteWorkflowAppParser.java
+++ b/core/src/main/java/org/apache/oozie/workflow/lite/LiteWorkflowAppParser.java
@@ -532,6 +532,7 @@
             @SuppressWarnings("unchecked")
             List<Element> actionJobXmls = actionElement.getChildren(JOB_XML, actionNs);
             if (gData != null && gData.jobXmls != null) {
+                int i = 0;
                 for(String gJobXml : gData.jobXmls) {
                     boolean alreadyExists = false;
                     for (Element actionXml : actionJobXmls) {
@@ -543,7 +544,8 @@
                     if (!alreadyExists) {
                         Element ejobXml = new Element(JOB_XML, actionNs);
                         ejobXml.setText(gJobXml);
-                        actionElement.addContent(ejobXml);
+                        actionElement.addContent(i, ejobXml);
+                        i++;
                     }
                 }
             }
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 8b893b8..6f118bd 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
@@ -267,11 +267,16 @@
      * @throws Exception
      */
     protected WorkflowJobBean createBaseWorkflow(XConfiguration protoConf, String actionName) throws Exception {
-        Path appUri = new Path(getAppPath(), "workflow.xml");
-
         String content = "<workflow-app xmlns='uri:oozie:workflow:1.0'  xmlns:sla='uri:oozie:sla:0.1' name='no-op-wf'>";
         content += "<start to='end' />";
         content += "<end name='end' /></workflow-app>";
+
+        return createBaseWorkflow(protoConf, actionName, content);
+    }
+
+    protected WorkflowJobBean createBaseWorkflow(XConfiguration protoConf, String actionName, String content) throws Exception {
+        Path appUri = new Path(getAppPath(), "workflow.xml");
+
         writeToFile(content, getAppPath(), "workflow.xml");
 
         WorkflowApp app = new LiteWorkflowApp("testApp", "<workflow-app/>",
diff --git a/release-log.txt b/release-log.txt
index 86693cc..bd927d4 100644
--- a/release-log.txt
+++ b/release-log.txt
@@ -1,5 +1,6 @@
 -- Oozie 5.2.0 release (trunk - unreleased)
 
+OOZIE-3526 Global job-xml not being overwritten by job-xml specified for an action (mgogineni via rohini)
 OOZIE-2755 Oozie HA: ZKJobsConcurrencyService throws runtime exception when numOozies is zero(asalamon74 via kmarton)
 OOZIE-3527 Oozie stuck in waiting state if CoordPushDependencyCheckXCommand is not requeued (mgogineni via rohini)
 OOZIE-3524 fs:fileSize() does not work correctly for files with extra slash in path (mgogineni via asalamon74)
diff --git a/sharelib/streaming/src/test/java/org/apache/oozie/action/hadoop/TestMapReduceActionExecutor.java b/sharelib/streaming/src/test/java/org/apache/oozie/action/hadoop/TestMapReduceActionExecutor.java
index 476c9fd..75b94d1 100644
--- a/sharelib/streaming/src/test/java/org/apache/oozie/action/hadoop/TestMapReduceActionExecutor.java
+++ b/sharelib/streaming/src/test/java/org/apache/oozie/action/hadoop/TestMapReduceActionExecutor.java
@@ -22,6 +22,7 @@
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -227,6 +228,100 @@
          assertEquals("global-output-dir", actionConf.get("outputDir"));
     }
 
+    public void testGlobalOverrideJobXml() throws Exception {
+        FileSystem fs = getFileSystem();
+
+        String jobXml1 = createJobXml("aa", "from_jobXml1", "bb", "from_jobXml1", "jobXml1", fs);
+        String jobXml2 = createJobXml("bb", "from_jobXml2", "cc", "from_jobXml2", "jobXml2", fs);
+        String jobXml3 = createJobXml("cc", "from_jobXml3", "dd", "from_jobXml3", "jobXml3", fs);
+        String jobXml4 = createJobXml("dd", "from_jobXml4", "ee", "from_jobXml4", "jobXml4", fs);
+
+        String actionXml = "<map-reduce>"
+                + "        <prepare>"
+                + "          <delete path=\"${nameNode}/user/${wf:user()}/mr/${outputDir}\"/>"
+                + "        </prepare>"
+                + "        <job-xml>" + jobXml3 + "</job-xml>"
+                + "        <job-xml>" + jobXml4 + "</job-xml>"
+                + "        <configuration>"
+                + "        <property><name>ee</name><value>from_action_config</value></property>"
+                + "        </configuration>"
+                + "      </map-reduce>";
+        String wfXml = "<workflow-app xmlns=\"uri:oozie:workflow:0.5\" name=\"map-reduce-wf\">"
+                + "<global>"
+                + "<job-tracker>${jobTracker}</job-tracker>"
+                + "<name-node>${nameNode}</name-node>"
+                + "<job-xml>" + jobXml1 + "</job-xml>"
+                + "<job-xml>" + jobXml2 + "</job-xml>"
+                + "<configuration>"
+                + "<property><name>aa</name><value>from_global_config</value></property>"
+                + "<property><name>ee</name><value>from_global_config</value></property>"
+                + "</configuration>"
+                + "</global>"
+                + "    <start to=\"mr-node\"/>"
+                + "    <action name=\"mr-node\">"
+                + actionXml
+                + "    <ok to=\"end\"/>"
+                + "    <error to=\"fail\"/>"
+                + "</action>"
+                + "<kill name=\"fail\">"
+                + "    <message>Map/Reduce failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message>"
+                + "</kill>"
+                + "<end name=\"end\"/>"
+                + "</workflow-app>";
+
+        Writer writer = new FileWriter(getTestCaseDir() + "/workflow.xml");
+        IOUtils.copyCharStream(new StringReader(wfXml), writer);
+
+        Configuration conf = new XConfiguration();
+        conf.set("nameNode", getNameNodeUri());
+        conf.set("jobTracker", getJobTrackerUri());
+        conf.set(OozieClient.USER_NAME, getTestUser());
+        conf.set(OozieClient.APP_PATH, "file://" + getTestCaseDir() + File.separator + "workflow.xml");
+
+        OutputStream os = new FileOutputStream(getTestCaseDir() + "/config-default.xml");
+        XConfiguration defaultConf = new XConfiguration();
+        defaultConf.set("aa", "from_config_default");
+        defaultConf.set("ff", "from_config_default");
+        defaultConf.writeXml(os);
+        os.close();
+        defaultConf.set(WorkflowAppService.HADOOP_USER, getTestUser());
+
+        String wfId = new SubmitXCommand(conf).call();
+        new StartXCommand(wfId).call();
+        waitForWorkflowAction(wfId + "@mr-node");
+        WorkflowActionBean mrAction = WorkflowActionQueryExecutor.getInstance().get(WorkflowActionQuery.GET_ACTION,
+                wfId + "@mr-node");
+
+        JavaActionExecutor ae = new JavaActionExecutor();
+        WorkflowJobBean wf = createBaseWorkflow(defaultConf, "mr-action", wfXml);
+        Context context = new Context(wf, mrAction);
+        Element mrActionXml = XmlUtils.parseXml(mrAction.getConf());
+        Configuration actionConfig = ae.setupActionConf(conf, context, mrActionXml, getAppPath());
+
+        // Check attribute values
+        assertEquals("from_global_config", actionConfig.get("aa"));
+        assertEquals("from_jobXml2", actionConfig.get("bb"));
+        assertEquals("from_jobXml3", actionConfig.get("cc"));
+        assertEquals("from_jobXml4", actionConfig.get("dd"));
+        assertEquals("from_action_config", actionConfig.get("ee"));
+        assertEquals("from_config_default", actionConfig.get("ff"));
+    }
+
+    protected String createJobXml(String key1, String value1, String key2, String value2, String filename, FileSystem fs)
+            throws Exception {
+        String content = "<configuration>"
+                + "<property><name>" + key1 + "</name><value>" + value1 + "</value></property>"
+                + "<property><name>" + key2 + "</name><value>" + value2 + "</value></property>"
+                + "</configuration>";
+
+        Path path = new Path(getAppPath(), filename);
+        Writer writer = new OutputStreamWriter(fs.create(path, true));
+        writer.write(content);
+        writer.close();
+
+        return path.toString();
+    }
+
     public void testSetupMethods() throws Exception {
         MapReduceActionExecutor ae = new MapReduceActionExecutor();
         List<Class<?>> classes = Arrays.<Class<?>>asList(StreamingMain.class);