OOZIE-3389 Getting input dependency list on the UI throws NPE (andras.piros via asalamon74, kmarton)
diff --git a/core/src/main/java/org/apache/oozie/command/coord/CoordActionMissingDependenciesXCommand.java b/core/src/main/java/org/apache/oozie/command/coord/CoordActionMissingDependenciesXCommand.java
index d37cfe5..f5d8782 100644
--- a/core/src/main/java/org/apache/oozie/command/coord/CoordActionMissingDependenciesXCommand.java
+++ b/core/src/main/java/org/apache/oozie/command/coord/CoordActionMissingDependenciesXCommand.java
@@ -107,19 +107,20 @@
     @Override
     protected List<Pair<CoordinatorActionBean, Map<String, ActionDependency>>> execute() throws CommandException {
 
-        List<Pair<CoordinatorActionBean, Map<String, ActionDependency>>> inputDependenciesListPair =
+        final List<Pair<CoordinatorActionBean, Map<String, ActionDependency>>> inputDependenciesListPair =
                 new ArrayList<Pair<CoordinatorActionBean, Map<String, ActionDependency>>>();
         try {
 
-            for (CoordinatorActionBean coordAction : coordActions) {
-                CoordInputDependency coordPullInputDependency = coordAction.getPullInputDependencies();
-                CoordInputDependency coordPushInputDependency = coordAction.getPushInputDependencies();
-                Map<String, ActionDependency> dependencyMap = new HashMap<String, ActionDependency>();
+            for (final CoordinatorActionBean coordAction : coordActions) {
+                final CoordInputDependency coordPullInputDependency = coordAction.getPullInputDependencies();
+                final CoordInputDependency coordPushInputDependency = coordAction.getPushInputDependencies();
+                final Map<String, ActionDependency> dependencyMap = new HashMap<>();
                 dependencyMap.putAll(coordPullInputDependency.getMissingDependencies(coordAction));
                 dependencyMap.putAll(coordPushInputDependency.getMissingDependencies(coordAction));
 
-                inputDependenciesListPair.add(
-                        new Pair<CoordinatorActionBean, Map<String, ActionDependency>>(coordAction, dependencyMap));
+                if (!dependencyMap.isEmpty()) {
+                    inputDependenciesListPair.add(new Pair<>(coordAction, dependencyMap));
+                }
             }
         }
         catch (Exception e) {
diff --git a/core/src/main/java/org/apache/oozie/coord/input/dependency/CoordOldInputDependency.java b/core/src/main/java/org/apache/oozie/coord/input/dependency/CoordOldInputDependency.java
index 56aef1c..af298b9 100644
--- a/core/src/main/java/org/apache/oozie/coord/input/dependency/CoordOldInputDependency.java
+++ b/core/src/main/java/org/apache/oozie/coord/input/dependency/CoordOldInputDependency.java
@@ -370,6 +370,11 @@
 
         Element eAction = XmlUtils.parseXml(coordAction.getActionXml());
         Element inputList = eAction.getChild("input-events", eAction.getNamespace());
+
+        if (inputList == null || inputList.getChildren().isEmpty()) {
+            return dependenciesMap;
+        }
+
         List<Element> eDataEvents = inputList.getChildren("data-in", eAction.getNamespace());
         for (Element event : eDataEvents) {
             Element uri = event.getChild("uris", event.getNamespace());
diff --git a/core/src/test/java/org/apache/oozie/coord/input/dependency/TestCoordOldInputDependency.java b/core/src/test/java/org/apache/oozie/coord/input/dependency/TestCoordOldInputDependency.java
new file mode 100644
index 0000000..c6bd3c0
--- /dev/null
+++ b/core/src/test/java/org/apache/oozie/coord/input/dependency/TestCoordOldInputDependency.java
@@ -0,0 +1,154 @@
+/**
+ * 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.coord.input.dependency;
+
+import org.apache.oozie.CoordinatorActionBean;
+import org.apache.oozie.client.CoordinatorAction;
+import org.apache.oozie.command.CommandException;
+import org.apache.oozie.service.Services;
+import org.apache.oozie.test.XHCatTestCase;
+import org.jdom.JDOMException;
+
+import java.io.IOException;
+
+public class TestCoordOldInputDependency extends XHCatTestCase {
+    private Services services;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        services = super.setupServicesForHCatalog();
+        services.init();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        services.destroy();
+        super.tearDown();
+    }
+
+    public void testNoMissingInputDependencies() throws JDOMException, IOException, CommandException {
+        final CoordinatorActionBean actionWithoutInputDependencies = createActionWithoutInputDependencies();
+
+        assertEquals("there should be no missing dependencies",
+                0,
+                actionWithoutInputDependencies
+                        .getPullInputDependencies()
+                        .getMissingDependencies(actionWithoutInputDependencies).size());
+    }
+
+    public void testOneMissingInputDependency() throws JDOMException, IOException, CommandException {
+        final CoordinatorActionBean actionWithInputDependencies = createActionWithInputDependencies();
+
+        assertEquals("there should be one missing dependency",
+                1,
+                actionWithInputDependencies
+                        .getPullInputDependencies()
+                        .getMissingDependencies(actionWithInputDependencies).size());
+    }
+
+    private CoordinatorActionBean createActionWithoutInputDependencies() {
+        final CoordinatorActionBean coordinatorAction = createAction();
+
+        coordinatorAction.setActionXml("<coordinator-app xmlns=\"uri:oozie:coordinator:0.2\" name=\"cron-coord\"" +
+                " frequency=\"0/10 * * * *\" timezone=\"UTC\" freq_timeunit=\"CRON\" end_of_duration=\"NONE\"" +
+                " instance-number=\"1\" action-nominal-time=\"2010-01-01T00:00Z\" action-actual-time=\"2018-11-29T12:55Z\">\n" +
+                "  <action>\n" +
+                "    <workflow>\n" +
+                "      <app-path>hdfs://localhost:9000/user/forsage/examples/apps/cron-schedule</app-path>\n" +
+                "      <configuration>\n" +
+                "        <property>\n" +
+                "          <name>resourceManager</name>\n" +
+                "          <value>localhost:8032</value>\n" +
+                "        </property>\n" +
+                "        <property>\n" +
+                "          <name>nameNode</name>\n" +
+                "          <value>hdfs://localhost:9000</value>\n" +
+                "        </property>\n" +
+                "        <property>\n" +
+                "          <name>queueName</name>\n" +
+                "          <value>default</value>\n" +
+                "        </property>\n" +
+                "      </configuration>\n" +
+                "    </workflow>\n" +
+                "  </action>\n" +
+                "</coordinator-app>");
+
+        return coordinatorAction;
+    }
+
+    private CoordinatorActionBean createAction() {
+        final CoordinatorActionBean coordinatorAction = new CoordinatorActionBean();
+
+        coordinatorAction.setId("0000001-181129135145907-oozie-fors-C@1");
+        coordinatorAction.setJobId("0000001-181129135145907-oozie-fors-C");
+        coordinatorAction.setStatus(CoordinatorAction.Status.SUCCEEDED);
+        coordinatorAction.setExternalId("0000002-181129135145907-oozie-fors-W");
+
+        return coordinatorAction;
+    }
+
+    private CoordinatorActionBean createActionWithInputDependencies() throws IOException {
+        final CoordinatorActionBean action = createAction();
+
+        action.setActionXml("<coordinator-app xmlns=\"uri:oozie:coordinator:0.2\" name=\"cron-coord\"" +
+                " frequency=\"0/10 * * * *\" timezone=\"UTC\" freq_timeunit=\"CRON\" end_of_duration=\"NONE\"" +
+                " instance-number=\"1\" action-nominal-time=\"2010-01-01T00:00Z\" action-actual-time=\"2018-11-29T12:55Z\">\n" +
+                "    <datasets>\n" +
+                "        <dataset name=\"data-1\" frequency=\"${coord:minutes(20)}\" initial-instance=\"2010-01-01T00:00Z\">\n" +
+                "            <uri-template>${nameNode}/${YEAR}/${MONTH}/${DAY}/${HOUR}/${MINUTE}</uri-template>\n" +
+                "        </dataset>\n" +
+                "    </datasets>\n" +
+                "    <input-events>\n" +
+                "        <data-in name=\"input-1\" dataset=\"data-1\">\n" +
+                "            <start-instance>${coord:current(-2)}</start-instance>\n" +
+                "            <end-instance>${coord:current(0)}</end-instance>\n" +
+                "        </data-in>\n" +
+                "    </input-events>\n" +
+                "  <action>\n" +
+                "    <workflow>\n" +
+                "      <app-path>hdfs://localhost:9000/user/forsage/examples/apps/cron-schedule</app-path>\n" +
+                "      <configuration>\n" +
+                "        <property>\n" +
+                "          <name>resourceManager</name>\n" +
+                "          <value>localhost:8032</value>\n" +
+                "        </property>\n" +
+                "        <property>\n" +
+                "          <name>nameNode</name>\n" +
+                "          <value>hdfs://localhost:9000</value>\n" +
+                "        </property>\n" +
+                "        <property>\n" +
+                "          <name>queueName</name>\n" +
+                "          <value>default</value>\n" +
+                "        </property>\n" +
+                "      </configuration>\n" +
+                "    </workflow>\n" +
+                "  </action>\n" +
+                "</coordinator-app>");
+
+        final CoordInputDependency coordPullInputDependency = CoordInputDependencyFactory
+                .createPullInputDependencies(true);
+        coordPullInputDependency.addUnResolvedList("data-1", "data-1");
+
+        action.setMissingDependencies(coordPullInputDependency.serialize());
+        action.setPullInputDependencies(coordPullInputDependency);
+
+        return action;
+    }
+}
\ No newline at end of file
diff --git a/core/src/test/java/org/apache/oozie/servlet/TestV2JobServlet.java b/core/src/test/java/org/apache/oozie/servlet/TestV2JobServlet.java
index bacfe89..b42421d 100644
--- a/core/src/test/java/org/apache/oozie/servlet/TestV2JobServlet.java
+++ b/core/src/test/java/org/apache/oozie/servlet/TestV2JobServlet.java
@@ -19,7 +19,6 @@
 package org.apache.oozie.servlet;
 
 import org.apache.oozie.client.CoordinatorWfAction;
-import org.apache.oozie.client.OozieClient;
 import org.apache.oozie.client.rest.RestConstants;
 import org.apache.oozie.client.rest.JsonTags;
 import org.apache.oozie.service.ConfigurationService;
@@ -117,13 +116,20 @@
                 url = createURL(MockCoordinatorEngineService.JOB_ID + (MockCoordinatorEngineService.coordJobs.size() + 1), params);
                 conn = (HttpURLConnection) url.openConnection();
                 conn.setRequestMethod("GET");
-                assertEquals(HttpServletResponse.SC_BAD_REQUEST, conn.getResponseCode());
+                assertBadRequestOrInternalServerError(conn.getResponseCode());
                 assertEquals(RestConstants.JOB_SHOW_INFO, MockCoordinatorEngineService.did);
                 return null;
             }
         });
     }
 
+    private void assertBadRequestOrInternalServerError(final int responseCode) {
+        assertTrue(String.format("HTTP response code [%d] is unexpected, should be one of [%d, %d]",
+                            responseCode, HttpServletResponse.SC_BAD_REQUEST, HttpServletResponse.SC_INTERNAL_SERVER_ERROR),
+                HttpServletResponse.SC_BAD_REQUEST == responseCode
+                || HttpServletResponse.SC_INTERNAL_SERVER_ERROR == responseCode);
+    }
+
     public void testGetCoordActionReruns() throws Exception {
         runTest("/v2/job/*", V1JobServlet.class, IS_SECURITY_ENABLED, new Callable<Void>() {
             @Override
@@ -180,7 +186,7 @@
                 conn.setRequestMethod("PUT");
                 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE);
                 conn.setDoOutput(true);
-                assertEquals(HttpServletResponse.SC_BAD_REQUEST, conn.getResponseCode());
+                assertBadRequestOrInternalServerError(conn.getResponseCode());
                 assertEquals(RestConstants.JOB_ACTION_CHANGE, MockCoordinatorEngineService.did);
 
                 return null;
@@ -219,7 +225,7 @@
                 conn.setRequestMethod("PUT");
                 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE);
                 conn.setDoOutput(true);
-                assertEquals(HttpServletResponse.SC_BAD_REQUEST, conn.getResponseCode());
+                assertBadRequestOrInternalServerError(conn.getResponseCode());
                 assertEquals(RestConstants.JOB_ACTION_IGNORE, MockCoordinatorEngineService.did);
 
                 return null;
@@ -313,7 +319,7 @@
                 URL url = createURL(MockCoordinatorEngineService.JOB_ID + 1, params);
                 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                 conn.setRequestMethod("GET");
-                assertEquals(HttpServletResponse.SC_BAD_REQUEST, conn.getResponseCode());
+                assertBadRequestOrInternalServerError(conn.getResponseCode());
 
                 return null;
             }
@@ -334,7 +340,7 @@
                 URL url = createURL(MockCoordinatorEngineService.JOB_ID + 1, params);
                 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                 conn.setRequestMethod("GET");
-                assertEquals(HttpServletResponse.SC_BAD_REQUEST, conn.getResponseCode());
+                assertBadRequestOrInternalServerError(conn.getResponseCode());
 
                 return null;
             }
@@ -355,7 +361,7 @@
                 URL url = createURL(MockCoordinatorEngineService.JOB_ID + 1, params);
                 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                 conn.setRequestMethod("GET");
-                assertEquals(HttpServletResponse.SC_BAD_REQUEST, conn.getResponseCode());
+                assertBadRequestOrInternalServerError(conn.getResponseCode());
 
                 return null;
             }
@@ -419,7 +425,7 @@
                 URL url = createURL(MockCoordinatorEngineService.JOB_ID + 1, params);
                 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                 conn.setRequestMethod("GET");
-                assertEquals(HttpServletResponse.SC_BAD_REQUEST, conn.getResponseCode());
+                assertBadRequestOrInternalServerError(conn.getResponseCode());
 
                 return null;
             }
@@ -440,7 +446,8 @@
                 URL url = createURL(MockCoordinatorEngineService.JOB_ID + 1, params);
                 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                 conn.setRequestMethod("GET");
-                assertEquals(HttpServletResponse.SC_BAD_REQUEST, conn.getResponseCode());
+                assertBadRequestOrInternalServerError(conn.getResponseCode());
+
                 return null;
             }
         });
diff --git a/release-log.txt b/release-log.txt
index 4c209f4..7d0dfe7 100644
--- a/release-log.txt
+++ b/release-log.txt
@@ -1,5 +1,6 @@
 -- Oozie 5.1.0 release
 
+OOZIE-3389 Getting input dependency list on the UI throws NPE (andras.piros via asalamon74, kmarton)
 OOZIE-3386 Misleading error message when workflow application does not exist (kmarton)
 OOZIE-3377 [docs] Remaining 5.1.0 documentation changes (andras.piros)
 OOZIE-3376 [tests] TestGraphGenerator should assume JDK8 minor version at least 1.8.0_u40 (andras.piros)