You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2016/10/28 17:45:52 UTC

[13/38] ambari git commit: AMBARI-18691. Improve and Update Workflow designer to support coordinators and bundles. (Belliraj HB via dipayanb)

AMBARI-18691. Improve and Update Workflow designer to support coordinators and bundles. (Belliraj HB via dipayanb)


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

Branch: refs/heads/branch-feature-AMBARI-18634
Commit: d1b0bb9ebf97313195d7e95ebb475bdc51534b8c
Parents: a936542
Author: Dipayan Bhowmick <di...@gmail.com>
Authored: Fri Oct 28 00:33:36 2016 +0530
Committer: Dipayan Bhowmick <di...@gmail.com>
Committed: Fri Oct 28 00:34:29 2016 +0530

----------------------------------------------------------------------
 .../apache/oozie/ambari/view/HDFSFileUtils.java |   87 +
 .../org/apache/oozie/ambari/view/JobType.java   |   22 +
 .../ambari/view/OozieProxyImpersonator.java     | 1042 ++++++------
 .../apache/oozie/ambari/view/OozieUtils.java    |   71 +
 .../org/apache/oozie/ambari/view/Utils.java     |  154 ++
 .../wfmanager/src/main/resources/ui/.jshintrc   |   38 +
 .../main/resources/ui/app/components/.gitkeep   |    0
 .../ui/app/components/archive-config.js         |    3 +-
 .../ui/app/components/bundle-config.js          |  262 +++
 .../ui/app/components/bundle-coord-config.js    |  108 ++
 .../ui/app/components/conditional-data-input.js |   78 +
 .../ui/app/components/confirmation-dialog.js    |   25 +
 .../resources/ui/app/components/coord-config.js |  521 ++++++
 .../ui/app/components/credentials-config.js     |  175 +-
 .../app/components/data-input-output-config.js  |   97 ++
 .../resources/ui/app/components/data-input.js   |   41 +
 .../ui/app/components/dataset-config.js         |  103 ++
 .../ui/app/components/date-with-expr.js         |   78 +
 .../ui/app/components/decision-add-branch.js    |   78 +-
 .../ui/app/components/decision-config.js        |   43 +-
 .../ui/app/components/designer-workspace.js     |  158 ++
 .../ui/app/components/distcp-action-info.js     |   26 +
 .../ui/app/components/distcp-action.js          |    6 +-
 .../ui/app/components/email-action-info.js      |   26 +
 .../resources/ui/app/components/email-action.js |   33 +-
 .../resources/ui/app/components/file-config.js  |    3 +-
 .../ui/app/components/flow-designer.js          |  728 +++++----
 .../ui/app/components/fs-action-info.js         |   26 +
 .../resources/ui/app/components/fs-action.js    |   64 +-
 .../ui/app/components/fsaction-info.js          |   21 +
 .../resources/ui/app/components/hdfs-browser.js |    5 +-
 .../ui/app/components/hive-action-info.js       |   26 +
 .../resources/ui/app/components/hive-action.js  |   38 +-
 .../ui/app/components/hive2-action-info.js      |   25 +
 .../resources/ui/app/components/hive2-action.js |   44 +-
 .../resources/ui/app/components/info-header.js  |   26 +
 .../ui/app/components/instance-list-config.js   |   54 +
 .../ui/app/components/java-action-info.js       |   25 +
 .../resources/ui/app/components/java-action.js  |   25 +-
 .../resources/ui/app/components/job-config.js   |  303 ++++
 .../resources/ui/app/components/job-details.js  |  391 ++++-
 .../ui/app/components/killnode-config.js        |   29 +
 .../ui/app/components/killnode-manager.js       |   62 +
 .../ui/app/components/map-red-action.js         |    6 +-
 .../ui/app/components/map-reduce-action-info.js |   25 +
 .../ui/app/components/name-value-config.js      |    7 +-
 .../ui/app/components/name-value-info.js        |   21 +
 .../ui/app/components/named-properties.js       |   25 +-
 .../ui/app/components/pig-action-info.js        |   25 +
 .../resources/ui/app/components/pig-action.js   |   16 +-
 .../ui/app/components/prepare-config-fs.js      |    7 +-
 .../ui/app/components/prepare-config-info.js    |   21 +
 .../ui/app/components/prepare-config.js         |    3 +-
 .../ui/app/components/preview-dialog.js         |   20 +
 .../ui/app/components/property-value-config.js  |   21 +
 .../main/resources/ui/app/components/save-wf.js |  170 ++
 .../ui/app/components/shell-action-info.js      |   25 +
 .../resources/ui/app/components/shell-action.js |   20 +-
 .../resources/ui/app/components/sla-info.js     |  148 +-
 .../ui/app/components/spark-action-info.js      |   25 +
 .../resources/ui/app/components/spark-action.js |   59 +-
 .../ui/app/components/sqoop-action-info.js      |   25 +
 .../resources/ui/app/components/sqoop-action.js |    5 +-
 .../ui/app/components/ssh-action-info.js        |   25 +
 .../resources/ui/app/components/ssh-action.js   |   24 +-
 .../app/components/sub-workflow-action-info.js  |   25 +
 .../resources/ui/app/components/sub-workflow.js |   17 +-
 .../ui/app/components/transition-config.js      |   44 +-
 .../ui/app/components/workflow-action-editor.js |   58 +-
 .../ui/app/components/workflow-actions.js       |    7 +
 .../ui/app/components/workflow-credentials.js   |   65 +-
 .../app/components/workflow-job-action-info.js  |   22 +
 .../ui/app/components/workflow-node.js          |    9 +
 .../ui/app/components/workflow-parameters.js    |   64 +-
 .../resources/ui/app/components/workflow-sla.js |   15 +-
 .../main/resources/ui/app/controllers/.gitkeep  |    0
 .../main/resources/ui/app/controllers/design.js |    5 -
 .../ui/app/domain/action-type-resolver.js       |   62 +
 .../ui/app/domain/actionjob_hanlder.js          |    1 +
 .../app/domain/bundle/bundle-xml-generator.js   |   55 +
 .../ui/app/domain/bundle/bundle-xml-importer.js |   87 +
 .../resources/ui/app/domain/bundle/bundle.js    |   22 +
 .../coordinator/coordinator-xml-generator.js    |  204 +++
 .../coordinator/coordinator-xml-importer.js     |  272 ++++
 .../ui/app/domain/coordinator/coordinator.js    |   22 +
 .../ui/app/domain/cytoscape-flow-renderer.js    |  348 ++++
 .../resources/ui/app/domain/cytoscape-style.js  |  123 ++
 .../ui/app/domain/default-layout-manager.js     |   10 +-
 .../resources/ui/app/domain/findnode-mixin.js   |  113 +-
 .../src/main/resources/ui/app/domain/id-gen.js  |    4 +
 .../ui/app/domain/jsplumb-flow-renderer.js      |  194 +++
 .../resources/ui/app/domain/mapping-utils.js    |   31 +-
 .../resources/ui/app/domain/node-factory.js     |   10 +-
 .../resources/ui/app/domain/node-handler.js     |   49 +-
 .../src/main/resources/ui/app/domain/node.js    |    3 +-
 .../main/resources/ui/app/domain/sla-info.js    |   38 +-
 .../main/resources/ui/app/domain/transition.js  |    5 +-
 .../ui/app/domain/workflow-importer.js          |    8 +-
 .../ui/app/domain/workflow-json-importer.js     |   92 ++
 .../ui/app/domain/workflow-path-util.js         |   73 +
 .../ui/app/domain/workflow-xml-generator.js     |    1 -
 .../main/resources/ui/app/domain/workflow.js    |  114 +-
 .../ui/app/domain/workflow_xml_mapper.js        |    5 +-
 .../src/main/resources/ui/app/helpers/.gitkeep  |    0
 .../src/main/resources/ui/app/index.html        |    9 +
 .../src/main/resources/ui/app/routes/.gitkeep   |    0
 .../main/resources/ui/app/routes/dashboard.js   |   10 +-
 .../src/main/resources/ui/app/routes/design.js  |   38 +-
 .../ui/app/services/workflow-clipboard.js       |   34 +
 .../ui/app/services/workspace-manager.js        |   62 +
 .../src/main/resources/ui/app/styles/app.less   | 1497 ++++++++++++++++++
 .../ui/app/templates/components/.gitkeep        |    0
 .../app/templates/components/bundle-config.hbs  |  129 ++
 .../components/bundle-coord-config.hbs          |   58 +
 .../templates/components/bundle-job-details.hbs |   17 +-
 .../components/conditional-data-input.hbs       |   64 +
 .../components/confirmation-dialog.hbs          |   34 +
 .../app/templates/components/coord-config.hbs   |  352 ++++
 .../templates/components/coord-job-details.hbs  |   17 +-
 .../templates/components/credentials-config.hbs |   33 +-
 .../components/data-input-output-config.hbs     |   68 +
 .../ui/app/templates/components/data-input.hbs  |   40 +
 .../app/templates/components/dataset-config.hbs |   70 +
 .../app/templates/components/date-with-expr.hbs |   41 +
 .../components/decision-add-branch.hbs          |    4 +-
 .../templates/components/decision-config.hbs    |    2 +-
 .../templates/components/designer-workspace.hbs |  106 ++
 .../templates/components/distcp-action-info.hbs |   35 +
 .../templates/components/email-action-info.hbs  |   28 +
 .../app/templates/components/email-action.hbs   |   10 +-
 .../ui/app/templates/components/field-error.hbs |    3 +
 .../app/templates/components/flow-designer.hbs  |  300 ++--
 .../app/templates/components/fs-action-info.hbs |   33 +
 .../ui/app/templates/components/fs-action.hbs   |    3 +-
 .../app/templates/components/fsaction-info.hbs  |   39 +
 .../app/templates/components/hdfs-browser.hbs   |    2 +-
 .../templates/components/hive-action-info.hbs   |   47 +
 .../ui/app/templates/components/hive-action.hbs |    6 +-
 .../templates/components/hive2-action-info.hbs  |   49 +
 .../app/templates/components/hive2-action.hbs   |    6 +-
 .../ui/app/templates/components/info-header.hbs |   18 +
 .../components/instance-list-config.hbs         |   35 +
 .../templates/components/java-action-info.hbs   |   52 +
 .../ui/app/templates/components/java-action.hbs |    4 +-
 .../ui/app/templates/components/job-config.hbs  |  126 ++
 .../ui/app/templates/components/job-details.hbs |    2 +-
 .../templates/components/killnode-config.hbs    |   67 +
 .../templates/components/killnode-manager.hbs   |   69 +
 .../components/map-reduce-action-info.hbs       |   41 +
 .../templates/components/name-value-info.hbs    |   22 +
 .../templates/components/named-properties.hbs   |    2 +-
 .../templates/components/pig-action-info.hbs    |   47 +
 .../ui/app/templates/components/pig-action.hbs  |    2 +-
 .../templates/components/prepare-config-fs.hbs  |   46 +-
 .../components/prepare-config-info.hbs          |   22 +
 .../app/templates/components/preview-dialog.hbs |   33 +
 .../components/property-value-config.hbs        |   22 +
 .../ui/app/templates/components/save-wf.hbs     |   79 +
 .../templates/components/shell-action-info.hbs  |   48 +
 .../app/templates/components/shell-action.hbs   |    4 +-
 .../ui/app/templates/components/sla-info.hbs    |   17 +-
 .../templates/components/spark-action-info.hbs  |   46 +
 .../app/templates/components/spark-action.hbs   |    6 +-
 .../templates/components/sqoop-action-info.hbs  |   41 +
 .../templates/components/ssh-action-info.hbs    |   32 +
 .../ui/app/templates/components/ssh-action.hbs  |    4 +-
 .../components/sub-workflow-action-info.hbs     |   29 +
 .../app/templates/components/sub-workflow.hbs   |    2 +-
 .../templates/components/transition-config.hbs  |   23 +-
 .../templates/components/version-settings.hbs   |    2 +-
 .../templates/components/workflow-actions.hbs   |    5 +
 .../templates/components/workflow-config.hbs    |    2 +-
 .../components/workflow-credentials.hbs         |   34 +-
 .../components/workflow-job-action-info.hbs     |   80 +
 .../components/workflow-job-details.hbs         |  158 +-
 .../app/templates/components/workflow-node.hbs  |    3 +-
 .../components/workflow-parameters.hbs          |   23 +-
 .../resources/ui/app/templates/dashboard.hbs    |    2 +-
 .../main/resources/ui/app/templates/design.hbs  |    2 +-
 .../main/resources/ui/app/utils/constants.js    |   43 +-
 .../app/validators/decission-node-validator.js  |   58 +
 .../app/validators/duplicate-data-node-name.js  |   60 +
 .../validators/duplicate-flattened-node-name.js |   66 +
 .../app/validators/duplicate-kill-node-name.js  |   58 +
 .../ui/app/validators/fs-action-validator.js    |   76 +
 .../ui/app/validators/job-params-validator.js   |   54 +
 .../ui/app/validators/operand-length.js         |   46 +
 .../resources/ui/app/validators/unique-name.js  |   59 +
 .../wfmanager/src/main/resources/ui/bower.json  |    5 +-
 .../src/main/resources/ui/ember-cli-build.js    |   10 +
 .../hdfs-directory-viewer/addon/.gitkeep        |    0
 .../hdfs-directory-viewer/app/.gitkeep          |    0
 .../tests/dummy/app/components/.gitkeep         |    0
 .../tests/dummy/app/controllers/.gitkeep        |    0
 .../tests/dummy/app/helpers/.gitkeep            |    0
 .../tests/dummy/app/models/.gitkeep             |    0
 .../tests/dummy/app/routes/.gitkeep             |    0
 .../dummy/app/templates/components/.gitkeep     |    0
 .../tests/integration/.gitkeep                  |    0
 .../hdfs-directory-viewer/tests/unit/.gitkeep   |    0
 .../hdfs-directory-viewer/vendor/.gitkeep       |    0
 .../resources/ui/mock-service/mock-server.js    |   52 +
 .../main/resources/ui/mock-service/mockData.js  |  316 ++++
 .../src/main/resources/ui/package.json          |   18 +-
 .../main/resources/ui/public/assets/favicon.ico |  Bin 0 -> 1150 bytes
 .../main/resources/ui/public/assets/join.png    |  Bin 0 -> 331 bytes
 .../main/resources/ui/public/assets/logo.png    |  Bin 0 -> 4568 bytes
 .../main/resources/ui/public/assets/play.png    |  Bin 0 -> 1164 bytes
 .../main/resources/ui/public/assets/sitemap.png |  Bin 0 -> 317 bytes
 .../main/resources/ui/public/assets/stop.png    |  Bin 0 -> 1164 bytes
 .../src/main/resources/ui/public/loader.gif     |  Bin 0 -> 42435 bytes
 .../resources/ui/public/sampledata/bundle.xml   |   32 +
 .../ui/public/sampledata/coordinator.xml        |  113 ++
 .../resources/ui/tests/integration/.gitkeep     |    0
 .../components/bundle-config-test.js            |   40 +
 .../components/bundle-coord-config-test.js      |   40 +
 .../components/conditional-data-input-test.js   |   40 +
 .../components/confirmation-dialog-test.js      |   40 +
 .../integration/components/coord-config-test.js |   40 +
 .../components/data-input-output-config-test.js |   40 +
 .../integration/components/data-input-test.js   |   40 +
 .../components/dataset-config-test.js           |   40 +
 .../components/date-with-expr-test.js           |   40 +
 .../components/designer-workspace-test.js       |   40 +
 .../components/distcp-action-info-test.js       |   41 +
 .../components/email-action-info-test.js        |   41 +
 .../components/fs-action-info-test.js           |   41 +
 .../components/fsaction-info-test.js            |   41 +
 .../components/hive-action-info-test.js         |   41 +
 .../components/hive2-action-info-test.js        |   41 +
 .../integration/components/info-header-test.js  |   41 +
 .../components/instance-list-config-test.js     |   41 +
 .../components/java-action-info-test.js         |   41 +
 .../integration/components/job-config-test.js   |   41 +
 .../components/killnode-config-test.js          |   41 +
 .../components/killnode-manager-test.js         |   41 +
 .../components/map-reduce-action-info-test.js   |   41 +
 .../components/name-value-info-test.js          |   41 +
 .../components/pig-action-info-test.js          |   41 +
 .../components/prepare-config-info-test.js      |   41 +
 .../components/preview-dialog-test.js           |   40 +
 .../components/property-value-config-test.js    |   41 +
 .../integration/components/save-wf-test.js      |   40 +
 .../components/shell-action-info-test.js        |   41 +
 .../components/spark-action-info-test.js        |   41 +
 .../components/sqoop-action-info-test.js        |   41 +
 .../components/ssh-action-info-test.js          |   41 +
 .../components/sub-workflow-action-info-test.js |   41 +
 .../src/main/resources/ui/tests/unit/.gitkeep   |    0
 .../unit/services/workflow-clipboard-test.js    |   29 +
 .../unit/services/workspace-manager-test.js     |   29 +
 .../validators/decission-node-validator-test.js |   26 +
 .../validators/duplicate-data-node-name-test.js |   27 +
 .../duplicate-flattened-node-name-test.js       |   27 +
 .../validators/duplicate-kill-node-name-test.js |   27 +
 .../unit/validators/fs-action-validator-test.js |   26 +
 .../validators/job-params-validator-test.js     |   26 +
 .../unit/validators/operand-length-test.js      |   27 +
 .../tests/unit/validators/unique-name-test.js   |   27 +
 259 files changed, 13407 insertions(+), 1980 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/HDFSFileUtils.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/HDFSFileUtils.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/HDFSFileUtils.java
new file mode 100644
index 0000000..58c3980
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/HDFSFileUtils.java
@@ -0,0 +1,87 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.ambari.view;
+
+import java.io.IOException;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.ambari.view.utils.hdfs.HdfsUtil;
+import org.apache.hadoop.fs.FSDataInputStream;
+import org.apache.hadoop.fs.FSDataOutputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HDFSFileUtils {
+	private final static Logger LOGGER = LoggerFactory
+			.getLogger(HDFSFileUtils.class);
+	private ViewContext viewContext;
+
+	public HDFSFileUtils(ViewContext viewContext) {
+		super();
+		this.viewContext = viewContext;
+	}
+	public boolean fileExists(String path) {
+		boolean fileExists;
+		try {
+			fileExists = getHdfsgetApi().exists(path);
+		} catch (IOException e) {
+			LOGGER.error(e.getMessage(), e);
+			throw new RuntimeException(e);
+		} catch (InterruptedException e) {
+			LOGGER.error(e.getMessage(), e);
+			throw new RuntimeException(e);
+		}
+		LOGGER.info("FILE exists for [" + path + "] returned [" + fileExists
+				+ "]");
+		return fileExists;
+	}
+	public FSDataInputStream read(String filePath)throws IOException{
+		FSDataInputStream is;
+		try {
+			is = getHdfsgetApi().open(filePath);
+		} catch (InterruptedException e) {
+			throw new RuntimeException(e);
+		}
+		return is;
+	}
+	public String createWorkflowFile( String workflowFile,String postBody,
+			boolean overwrite) throws IOException {
+		FSDataOutputStream fsOut;
+		try {
+			fsOut = getHdfsgetApi().create(workflowFile,
+					overwrite);
+		} catch (InterruptedException e) {
+			throw new RuntimeException(e);
+		}
+		fsOut.write(postBody.getBytes());
+		fsOut.close();
+		return workflowFile;
+	}
+	private HdfsApi getHdfsgetApi() {
+		try {
+			return HdfsUtil.connectToHDFSApi(viewContext);
+		} catch (Exception ex) {
+			LOGGER.error("Error in getting HDFS Api", ex);
+			throw new RuntimeException(
+					"HdfsApi connection failed. Check \"webhdfs.url\" property",
+					ex);
+		}
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/JobType.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/JobType.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/JobType.java
new file mode 100644
index 0000000..5a47b68
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/JobType.java
@@ -0,0 +1,22 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.ambari.view;
+
+public enum JobType {
+	WORKFLOW, COORDINATOR, BUNDLE
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java
index 3ed6352..0533f04 100644
--- a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java
@@ -20,14 +20,10 @@ package org.apache.oozie.ambari.view;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.StringReader;
-import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
 
 import javax.inject.Inject;
 import javax.ws.rs.Consumes;
@@ -48,522 +44,550 @@ import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.StreamingOutput;
 import javax.ws.rs.core.UriInfo;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.TransformerFactoryConfigurationError;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
 
 import org.apache.ambari.view.URLStreamProvider;
 import org.apache.ambari.view.ViewContext;
-import org.apache.ambari.view.utils.ambari.AmbariApi;
-import org.apache.ambari.view.utils.hdfs.HdfsApi;
-import org.apache.ambari.view.utils.hdfs.HdfsUtil;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.exception.ExceptionUtils;
 import org.apache.hadoop.fs.FSDataInputStream;
-import org.apache.hadoop.fs.FSDataOutputStream;
+import org.apache.hadoop.security.AccessControlException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
+
+import com.google.inject.Singleton;
 
 /**
  * This is a class used to bridge the communication between the and the Oozie
  * API executing inside ambari.
  */
+@Singleton
 public class OozieProxyImpersonator {
-
-  private static final String OOZIE_WF_APPLICATION_PATH_CONF_KEY = "oozie.wf.application.path";
-  private static final String OOZIE_WF_RERUN_FAILNODES_CONF_KEY = "oozie.wf.rerun.failnodes";
-  private static final String OOZIE_USE_SYSTEM_LIBPATH_CONF_KEY = "oozie.use.system.libpath";
-  private static final String XML_INDENT_SPACES = "4";
-  private static final String XML_INDENT_AMT_PROP_NAME = "{http://xml.apache.org/xslt}indent-amount";
-  private ViewContext viewContext;
-  private AmbariApi ambariApi;
-  private HdfsApi _hdfsApi = null;
-
-  private static final String USER_NAME_HEADER = "user.name";
-  private static final String USER_OOZIE_SUPER = "oozie";
-  private static final String DO_AS_HEADER = "doAs";
-
-  private static final String SERVICE_URI_PROP = "oozie.service.uri";
-  private static final String DEFAULT_SERVICE_URI = "http://sandbox.hortonworks.com:11000/oozie";
-
-  private final static Logger LOGGER = LoggerFactory
-    .getLogger(OozieProxyImpersonator.class);
-
-  @Inject
-  public OozieProxyImpersonator(ViewContext viewContext) {
-    this.viewContext = viewContext;
-    this.ambariApi = new AmbariApi(viewContext);
-    LOGGER.info(String.format(
-      "OozieProxyImpersonator initialized for instance: %s",
-      viewContext.getInstanceName()));
-  }
-
-  @Path("/fileServices")
-  public FileServices fileServices() {
-    return new FileServices(viewContext);
-  }
-
-  @POST
-  @Path("/submitWorkflow")
-  @Consumes({MediaType.TEXT_PLAIN + "," + MediaType.TEXT_XML})
-  public Response submitWorkflow(String postBody, @Context HttpHeaders headers,
-                                 @Context UriInfo ui, @QueryParam("app.path") String appPath,
-                                 @DefaultValue("false") @QueryParam("overwrite") Boolean overwrite) {
-    LOGGER.info("submit workflow job called");
-    try {
-      if (StringUtils.isEmpty(appPath)) {
-        throw new RuntimeException("app path can't be empty.");
-      }
-      appPath = appPath.trim();
-      if (!overwrite) {
-        boolean fileExists = getHdfsgetApi().exists(appPath);
-        LOGGER.info("FILE exists for [" + appPath + "] returned [" + fileExists
-          + "]");
-        if (fileExists) {
-          HashMap<String, String> resp = new HashMap<String, String>();
-          resp.put("status", "workflow.folder.exists");
-          resp.put("message", "Workflow Folder exists");
-          return Response.status(Response.Status.BAD_REQUEST).entity(resp)
-            .build();
-        }
-      }
-      String workflowFile = null;
-      if (appPath.endsWith(".xml")) {
-        workflowFile = appPath;
-      } else {
-        workflowFile = appPath + (appPath.endsWith("/") ? "" : "/")
-          + "workflow.xml";
-      }
-      postBody = formatXml(postBody);
-      try {
-        String filePath = createWorkflowFile(postBody, workflowFile, overwrite);
-        LOGGER.info(String.format("submit workflow job done. filePath=[%s]",
-          filePath));
-      } catch (org.apache.hadoop.security.AccessControlException ace) {
-        HashMap<String, String> resp = new HashMap<String, String>();
-        resp.put("status", "workflow.oozie.error");
-        resp.put("message", "You dont seem to have access to folder path.");
-        return Response.status(Response.Status.BAD_REQUEST).entity(resp)
-          .build();
-      }
-
-      String response = submitWorkflowJobToOozie(headers, appPath,
-        ui.getQueryParameters());
-      if (response != null && response.trim().startsWith("{")) {
-        // dealing with oozie giving error but with 200 response.
-        return Response.status(Response.Status.OK).entity(response).build();
-      } else {
-        HashMap<String, String> resp = new HashMap<String, String>();
-        resp.put("status", "workflow.oozie.error");
-        resp.put("message", response);
-        return Response.status(Response.Status.BAD_REQUEST).entity(resp)
-          .build();
-      }
-    } catch (InterruptedException e) {
-      throw new RuntimeException(e);
-    } catch (Exception e) {
-      LOGGER.error("Error in submit workflow", e);
-      throw new RuntimeException(e);
-    }
-  }
-
-  @GET
-  @Path("/readWorkflowXml")
-  public Response readWorkflowXxml(
-      @QueryParam("workflowXmlPath") String workflowPath) {
-    if (StringUtils.isEmpty(workflowPath)) {
-      throw new RuntimeException("workflowXmlPath can't be empty.");
-    }
-    try {
-      final FSDataInputStream is = getHdfsgetApi().open(workflowPath);
-      StreamingOutput streamer = new StreamingOutput() {
-
-        @Override
-        public void write(OutputStream os) throws IOException,
-            WebApplicationException {
-          IOUtils.copy(is, os);
-          is.close();
-          os.close();
-        }
-      };
-      return Response.ok(streamer).status(200).build();
-    } catch (org.apache.hadoop.security.AccessControlException ace) {
-      HashMap<String, String> resp = new HashMap<String, String>();
-      resp.put("status", "workflow.oozie.error");
-      resp.put("message", "Access denied to file path");
-      return Response.status(Response.Status.FORBIDDEN).entity(resp).build();
-    } catch (IOException e) {
-      LOGGER.error("Error in read worfklow file", e);
-      throw new RuntimeException(e);
-    } catch (InterruptedException e) {
-      LOGGER.error("Error in read worfklow file", e);
-      throw new RuntimeException(e);
-    }
-  }
-
-  @GET
-  @Path("/getDag")
-  @Produces("image/png")
-  public Response submitWorkflow(@Context HttpHeaders headers,
-                                 @Context UriInfo ui, @QueryParam("jobid") String jobid) {
-    String imgUrl = getServiceUri() + "/v2/job/" + jobid + "?show=graph";
-    Map<String, String> newHeaders = getHeaders(headers);
-    final InputStream is = readFromOozie(headers, imgUrl, HttpMethod.GET, null,
-      newHeaders);
-    StreamingOutput streamer = new StreamingOutput() {
-
-      @Override
-      public void write(OutputStream os) throws IOException,
-        WebApplicationException {
-        IOUtils.copy(is, os);
-        is.close();
-        os.close();
-      }
-
-    };
-    return Response.ok(streamer).status(200).build();
-  }
-
-  @GET
-  @Path("/{path: .*}")
-  public Response handleGet(@Context HttpHeaders headers, @Context UriInfo ui) {
-    try {
-      String serviceURI = buildURI(ui);
-      return consumeService(headers, serviceURI, HttpMethod.GET, null);
-    } catch (Exception ex) {
-      LOGGER.error("Error in GET proxy", ex);
-      return Response.status(Response.Status.BAD_REQUEST).entity(ex.toString())
-        .build();
-    }
-  }
-
-  @POST
-  @Path("/{path: .*}")
-  public Response handlePost(String xml, @Context HttpHeaders headers, @Context UriInfo ui) {
-    try {
-      String serviceURI = buildURI(ui);
-      return consumeService(headers, serviceURI, HttpMethod.POST, xml);
-    } catch (Exception ex) {
-      LOGGER.error("Error in POST proxy", ex);
-      return Response.status(Response.Status.BAD_REQUEST).entity(ex.toString())
-        .build();
-    }
-  }
-
-  @DELETE
-  @Path("/{path: .*}")
-  public Response handleDelete(@Context HttpHeaders headers, @Context UriInfo ui) {
-    try {
-      String serviceURI = buildURI(ui);
-      return consumeService(headers, serviceURI, HttpMethod.POST, null);
-    } catch (Exception ex) {
-      LOGGER.error("Error in DELETE proxy", ex);
-      return Response.status(Response.Status.BAD_REQUEST).entity(ex.toString())
-        .build();
-    }
-  }
-
-  @PUT
-  @Path("/{path: .*}")
-  public Response handlePut(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
-
-    try {
-      String serviceURI = buildURI(ui);
-      return consumeService(headers, serviceURI, HttpMethod.PUT, body);
-    } catch (Exception ex) {
-      LOGGER.error("Error in PUT proxy", ex);
-      return Response.status(Response.Status.BAD_REQUEST).entity(ex.toString())
-        .build();
-    }
-  }
-
-  private String submitWorkflowJobToOozie(HttpHeaders headers, String filePath,
-                                          MultivaluedMap<String, String> queryParams) {
-    String nameNode = "hdfs://" + viewContext.getCluster().getConfigurationValue("hdfs-site", "dfs.namenode.rpc-address");
-
-    if (!queryParams.containsKey("config.nameNode")) {
-      ArrayList<String> nameNodes = new ArrayList<String>();
-      LOGGER.info("Namenode===" + nameNode);
-      nameNodes.add(nameNode);
-      queryParams.put("config.nameNode", nameNodes);
-    }
-
-    HashMap<String, String> workflowConigs = new HashMap<String, String>();
-    if (queryParams.containsKey("resourceManager")
-      && "useDefault".equals(queryParams.getFirst("resourceManager"))) {
-      String jobTrackerNode = viewContext.getCluster().getConfigurationValue(
-        "yarn-site", "yarn.resourcemanager.address");
-      LOGGER.info("jobTrackerNode===" + jobTrackerNode);
-      workflowConigs.put("resourceManager", jobTrackerNode);
-      workflowConigs.put("jobTracker", jobTrackerNode);
-    }
-    if (queryParams != null) {
-      for (Map.Entry<String, List<String>> entry : queryParams.entrySet()) {
-        if (entry.getKey().startsWith("config.")) {
-          if (entry.getValue() != null && entry.getValue().size() > 0) {
-            workflowConigs.put(entry.getKey().substring(7), entry.getValue()
-              .get(0));
-          }
-        }
-      }
-    }
-
-    if (queryParams.containsKey("oozieconfig.useSystemLibPath")) {
-      String useSystemLibPath = queryParams
-        .getFirst("oozieconfig.useSystemLibPath");
-      workflowConigs.put(OOZIE_USE_SYSTEM_LIBPATH_CONF_KEY, useSystemLibPath);
-    } else {
-      workflowConigs.put(OOZIE_USE_SYSTEM_LIBPATH_CONF_KEY, "true");
-    }
-    if (queryParams.containsKey("oozieconfig.rerunOnFailure")) {
-      String rerunFailnodes = queryParams
-        .getFirst("oozieconfig.rerunOnFailure");
-      workflowConigs.put(OOZIE_WF_RERUN_FAILNODES_CONF_KEY, rerunFailnodes);
-    } else {
-      workflowConigs.put(OOZIE_WF_RERUN_FAILNODES_CONF_KEY, "true");
-    }
-
-    workflowConigs.put("user.name", viewContext.getUsername());
-    workflowConigs.put(OOZIE_WF_APPLICATION_PATH_CONF_KEY, nameNode + filePath);
-    String configXMl = generateConigXml(workflowConigs);
-    LOGGER.info("Config xml==" + configXMl);
-    HashMap<String, String> customHeaders = new HashMap<String, String>();
-    customHeaders.put("Content-Type", "application/xml;charset=UTF-8");
-    Response serviceResponse = consumeService(headers, getServiceUri()
-      + "/v2/jobs", HttpMethod.POST, configXMl, customHeaders);
-
-    LOGGER
-      .info("REsp from oozie status entity==" + serviceResponse.getEntity());
-    if (serviceResponse.getEntity() instanceof String) {
-      return (String) serviceResponse.getEntity();
-    } else {
-      return "success";
-    }
-
-  }
-
-  private String createWorkflowFile(String postBody, String workflowFile, boolean overwrite) throws IOException, InterruptedException {
-    FSDataOutputStream fsOut = getHdfsgetApi().create(workflowFile, overwrite);
-    fsOut.write(postBody.getBytes());
-    fsOut.close();
-    return workflowFile;
-  }
-
-  private String buildURI(UriInfo ui) {
-    String uiURI = ui.getAbsolutePath().getPath();
-    int index = uiURI.indexOf("proxy/") + 5;
-    uiURI = uiURI.substring(index);
-    String serviceURI = getServiceUri();
-    serviceURI += uiURI;
-
-    MultivaluedMap<String, String> parameters = ui.getQueryParameters();
-    StringBuilder urlBuilder = new StringBuilder(serviceURI);
-    boolean firstEntry = true;
-    for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
-      if ("user.name".equals(entry.getKey())) {
-        ArrayList<String> vals = new ArrayList<String>();
-        vals.add(viewContext.getUsername());
-        entry.setValue(vals);
-      }
-      if (firstEntry) {
-        urlBuilder.append("?");
-      } else {
-        urlBuilder.append("&");
-      }
-      boolean firstVal = true;
-      for (String val : entry.getValue()) {
-        urlBuilder.append(firstVal ? "" : "&").append(entry.getKey())
-          .append("=").append(val);
-        firstVal = false;
-      }
-      firstEntry = false;
-    }
-    return urlBuilder.toString();
-  }
-
-  private String getServiceUri() {
-    String serviceURI = viewContext.getProperties().get(SERVICE_URI_PROP) != null ? viewContext
-      .getProperties().get(SERVICE_URI_PROP) : DEFAULT_SERVICE_URI;
-    return serviceURI;
-  }
-
-  public Response consumeService(HttpHeaders headers, String urlToRead,
-                                 String method, String body, Map<String, String> customHeaders) {
-    Response response = null;
-    InputStream stream = readFromOozie(headers, urlToRead, method, body,
-      customHeaders);
-    String stringResponse = null;
-    try {
-      stringResponse = IOUtils.toString(stream);
-    } catch (IOException e) {
-      LOGGER.error("Error while converting stream to string", e);
-      throw new RuntimeException(e);
-    }
-    if (stringResponse.contains(Response.Status.BAD_REQUEST.name())) {
-      response = Response.status(Response.Status.BAD_REQUEST)
-        .entity(stringResponse).type(MediaType.TEXT_PLAIN).build();
-    } else {
-      response = Response.status(Response.Status.OK).entity(stringResponse)
-        .type(deduceType(stringResponse)).build();
-    }
-    return response;
-  }
-
-  private InputStream readFromOozie(HttpHeaders headers, String urlToRead,
-                                    String method, String body, Map<String, String> customHeaders) {
-    URLStreamProvider streamProvider = viewContext.getURLStreamProvider();
-    Map<String, String> newHeaders = getHeaders(headers);
-    newHeaders.put(USER_NAME_HEADER, USER_OOZIE_SUPER);
-
-    newHeaders.put(DO_AS_HEADER, viewContext.getUsername());
-    newHeaders.put("Accept", MediaType.APPLICATION_JSON);
-    if (customHeaders != null) {
-      newHeaders.putAll(customHeaders);
-    }
-    LOGGER.info(String.format("Proxy request for url: [%s] %s", method,
-      urlToRead));
-    boolean securityEnabled = isSecurityEnabled();
-    LOGGER.debug(String.format("IS security enabled:[%b]", securityEnabled));
-    InputStream stream = null;
-    try {
-      if (securityEnabled) {
-        stream = streamProvider.readAsCurrent(urlToRead, method, body, newHeaders);
-
-      } else {
-        stream = streamProvider.readFrom(urlToRead, method, body, newHeaders);
-      }
-    } catch (IOException e) {
-      LOGGER.error("error talking to oozie", e);
-      throw new RuntimeException(e);
-    }
-    return stream;
-  }
-
-  public Response consumeService(HttpHeaders headers, String urlToRead,
-                                 String method, String body) throws Exception {
-    return consumeService(headers, urlToRead, method, body, null);
-  }
-
-  public Map<String, String> getHeaders(HttpHeaders headers) {
-    MultivaluedMap<String, String> requestHeaders = headers.getRequestHeaders();
-    Set<Entry<String, List<String>>> headerEntrySet = requestHeaders.entrySet();
-    HashMap<String, String> headersMap = new HashMap<String, String>();
-    for (Entry<String, List<String>> headerEntry : headerEntrySet) {
-      String key = headerEntry.getKey();
-      List<String> values = headerEntry.getValue();
-      headersMap.put(key, strJoin(values, ","));
-    }
-    return headersMap;
-  }
-
-  public String strJoin(List<String> strings, String separator) {
-    StringBuilder stringBuilder = new StringBuilder();
-    for (int i = 0, il = strings.size(); i < il; i++) {
-      if (i > 0) {
-        stringBuilder.append(separator);
-      }
-      stringBuilder.append(strings.get(i));
-    }
-    return stringBuilder.toString();
-  }
-
-  private MediaType deduceType(String stringResponse) {
-    if (stringResponse.startsWith("{")) {
-      return MediaType.APPLICATION_JSON_TYPE;
-    } else if (stringResponse.startsWith("<")) {
-      return MediaType.TEXT_XML_TYPE;
-    } else {
-      return MediaType.APPLICATION_JSON_TYPE;
-    }
-  }
-
-  private HdfsApi getHdfsgetApi() {
-    if (_hdfsApi == null) {
-      try {
-        _hdfsApi = HdfsUtil.connectToHDFSApi(viewContext);
-      } catch (Exception ex) {
-        LOGGER.error("Error in getting HDFS Api", ex);
-        throw new RuntimeException("HdfsApi connection failed. Check \"webhdfs.url\" property", ex);
-      }
-    }
-    return _hdfsApi;
-  }
-
-  private String generateConigXml(Map<String, String> map) {
-    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-    DocumentBuilder db;
-    try {
-      db = dbf.newDocumentBuilder();
-      Document doc = db.newDocument();
-      Element configElement = doc.createElement("configuration");
-      doc.appendChild(configElement);
-      for (Map.Entry<String, String> entry : map.entrySet()) {
-        Element propElement = doc.createElement("property");
-        configElement.appendChild(propElement);
-        Element nameElem = doc.createElement("name");
-        nameElem.setTextContent(entry.getKey());
-        Element valueElem = doc.createElement("value");
-        valueElem.setTextContent(entry.getValue());
-        propElement.appendChild(nameElem);
-        propElement.appendChild(valueElem);
-      }
-      DOMSource domSource = new DOMSource(doc);
-      StringWriter writer = new StringWriter();
-      StreamResult result = new StreamResult(writer);
-      TransformerFactory tf = TransformerFactory.newInstance();
-      Transformer transformer = tf.newTransformer();
-      transformer.setOutputProperty(OutputKeys.INDENT, "yes");
-      transformer
-        .setOutputProperty(XML_INDENT_AMT_PROP_NAME, XML_INDENT_SPACES);
-      transformer.transform(domSource, result);
-      return writer.toString();
-    } catch (ParserConfigurationException | TransformerException e) {
-      LOGGER.error("error in generating config xml", e);
-      throw new RuntimeException(e);
-    }
-
-  }
-
-  private String formatXml(String xml) {
-    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-    try {
-      DocumentBuilder db = dbf.newDocumentBuilder();
-      StreamResult result = new StreamResult(new StringWriter());
-      Document document = db.parse(new InputSource(new StringReader(xml)));
-      Transformer transformer = TransformerFactory.newInstance()
-        .newTransformer();
-      transformer.setOutputProperty(OutputKeys.INDENT, "yes");
-      transformer
-        .setOutputProperty(XML_INDENT_AMT_PROP_NAME, XML_INDENT_SPACES);
-      DOMSource source = new DOMSource(document);
-      transformer.transform(source, result);
-      return result.getWriter().toString();
-    } catch (ParserConfigurationException | SAXException | IOException
-      | TransformerFactoryConfigurationError | TransformerException e) {
-      LOGGER.error("Error in formatting xml", e);
-      throw new RuntimeException(e);
-    }
-  }
-
-  private boolean isSecurityEnabled() {
-    boolean securityEnabled = Boolean.valueOf(getHadoopConfigs().get(
-      "security_enabled"));
-    return securityEnabled;
-  }
-
-  private Map<String, String> getHadoopConfigs() {
-    return viewContext.getInstanceData();
-  }
-
-}
+	private final static Logger LOGGER = LoggerFactory
+			.getLogger(OozieProxyImpersonator.class);
+
+	private static final String OOZIEPARAM_PREFIX = "oozieparam.";
+	private static final int OOZIEPARAM_PREFIX_LENGTH = OOZIEPARAM_PREFIX
+			.length();
+	private static final String EQUAL_SYMBOL = "=";
+	private static final String OOZIE_WF_RERUN_FAILNODES_CONF_KEY = "oozie.wf.rerun.failnodes";
+	private static final String OOZIE_USE_SYSTEM_LIBPATH_CONF_KEY = "oozie.use.system.libpath";
+
+	private ViewContext viewContext;
+
+	private static final String USER_NAME_HEADER = "user.name";
+	private static final String USER_OOZIE_SUPER = "oozie";
+	private static final String DO_AS_HEADER = "doAs";
+
+	private static final String SERVICE_URI_PROP = "oozie.service.uri";
+	private static final String DEFAULT_SERVICE_URI = "http://sandbox.hortonworks.com:11000/oozie";
+	private Utils utils=new Utils();
+	private OozieUtils oozieUtils=new OozieUtils();
+	private HDFSFileUtils hdfsFileUtils;
+	private static enum ErrorCodes {
+		OOZIE_SUBMIT_ERROR("error.oozie.submit", "Oozie Submit error"), OOZIE_IO_ERROR(
+				"error.oozie.io", "Oozie I/O error"), FILE_ACCESS_ACL_ERROR(
+				"error.file.access.control",
+				"Access Error to file due to access control"), FILE_ACCESS_UNKNOWN_ERROR(
+				"error.file.access", "Error accessing file"), WORKFLOW_PATH_EXISTS(
+				"error.workflow.path.exists", "Worfklow path exists");
+		private String errorCode;
+		private String description;
+
+		ErrorCodes(String errorCode, String description) {
+			this.errorCode = errorCode;
+			this.description = description;
+		}
+
+		public String getErrorCode() {
+			return errorCode;
+		}
+
+		public String getDescription() {
+			return description;
+		}
+	}
+
+	@Inject
+	public OozieProxyImpersonator(ViewContext viewContext) {
+		this.viewContext = viewContext;
+		hdfsFileUtils=new HDFSFileUtils(viewContext);
+		LOGGER.info(String.format(
+				"OozieProxyImpersonator initialized for instance: %s",
+				viewContext.getInstanceName()));
+	}
+
+	@Path("/fileServices")
+	public FileServices fileServices() {
+		return new FileServices(viewContext);
+	}
+
+	@GET
+	@Path("/getCurrentUserName")
+	public Response getCurrentUserName() {
+		return Response.ok(viewContext.getUsername()).build();
+	}
+
+	@POST
+	@Path("/submitJob")
+	@Consumes({ MediaType.TEXT_PLAIN + "," + MediaType.TEXT_XML })
+	public Response submitJob(String postBody, @Context HttpHeaders headers,
+			@Context UriInfo ui, @QueryParam("app.path") String appPath,
+			@DefaultValue("false") @QueryParam("overwrite") Boolean overwrite,
+			@QueryParam("jobType") String jobType) {
+		LOGGER.info("submit workflow job called");
+		return submitJobInternal(postBody, headers, ui, appPath, overwrite,
+				JobType.valueOf(jobType));
+	}
+
+	@POST
+	@Path("/submitWorkflow")
+	@Consumes({ MediaType.TEXT_PLAIN + "," + MediaType.TEXT_XML })
+	public Response submitWorkflow(String postBody,
+			@Context HttpHeaders headers, @Context UriInfo ui,
+			@QueryParam("app.path") String appPath,
+			@DefaultValue("false") @QueryParam("overwrite") Boolean overwrite) {
+		LOGGER.info("submit workflow job called");
+		return submitJobInternal(postBody, headers, ui, appPath, overwrite,
+				JobType.WORKFLOW);
+	}
+
+	@POST
+	@Path("/saveWorkflow")
+	@Consumes({ MediaType.TEXT_PLAIN + "," + MediaType.TEXT_XML })
+	public Response saveWorkflow(String postBody, @Context HttpHeaders headers,
+			@Context UriInfo ui, @QueryParam("app.path") String appPath,
+			@DefaultValue("false") @QueryParam("overwrite") Boolean overwrite) {
+		LOGGER.info("save workflow  called");
+		if (StringUtils.isEmpty(appPath)) {
+			throw new RuntimeException("app path can't be empty.");
+		}
+		appPath = appPath.trim();
+		if (!overwrite) {
+			boolean fileExists = hdfsFileUtils.fileExists(appPath);
+			if (fileExists) {
+				return getFileExistsResponse();
+			}
+		}
+		postBody = utils.formatXml(postBody);
+		try {
+			String filePath = hdfsFileUtils.createWorkflowFile(getWorkflowFileName(appPath),postBody, overwrite);
+			LOGGER.info(String.format(
+					"submit workflow job done. filePath=[%s]", filePath));
+			return Response.ok().build();
+		} catch (Exception ex) {
+			LOGGER.error(ex.getMessage(), ex);
+			return getRespCodeForException(ex);
+
+		}
+	}
+
+	private Response submitJobInternal(String postBody, HttpHeaders headers,
+			UriInfo ui, String appPath, Boolean overwrite, JobType jobType) {
+		if (StringUtils.isEmpty(appPath)) {
+			throw new RuntimeException("app path can't be empty.");
+		}
+		appPath = appPath.trim();
+		if (!overwrite) {
+			boolean fileExists = hdfsFileUtils.fileExists(appPath);
+			if (fileExists) {
+				return getFileExistsResponse();
+			}
+		}
+		postBody = utils.formatXml(postBody);
+		try {
+			String filePath = hdfsFileUtils.createWorkflowFile(getWorkflowFileName(appPath),postBody,overwrite);
+			LOGGER.info(String.format(
+					"submit workflow job done. filePath=[%s]", filePath));
+		} catch (Exception ex) {
+			LOGGER.error(ex.getMessage(), ex);
+			return getRespCodeForException(ex);
+
+		}
+		String response = submitWorkflowJobToOozie(headers, appPath,
+				ui.getQueryParameters(), jobType);
+		if (response != null && response.trim().startsWith("{")) {
+			// dealing with oozie giving error but with 200 response.
+			return Response.status(Response.Status.OK).entity(response).build();
+		} else {
+			HashMap<String, String> resp = new HashMap<String, String>();
+			resp.put("status", ErrorCodes.OOZIE_SUBMIT_ERROR.getErrorCode());
+			resp.put("message", response);
+			return Response.status(Response.Status.BAD_REQUEST).entity(resp)
+					.build();
+		}
+
+	}
+
+	private Response getRespCodeForException(Exception ex) {
+		if (ex instanceof AccessControlException) {
+			HashMap<String, String> errorDetails = getErrorDetails(
+					ErrorCodes.FILE_ACCESS_ACL_ERROR.getErrorCode(),
+					ErrorCodes.FILE_ACCESS_ACL_ERROR.getDescription(), ex);
+			return Response.status(Response.Status.BAD_REQUEST)
+					.entity(errorDetails).build();
+		}else if (ex instanceof IOException){
+			HashMap<String, String> errorDetails = getErrorDetails(
+					ErrorCodes.FILE_ACCESS_UNKNOWN_ERROR.getErrorCode(),
+					ErrorCodes.FILE_ACCESS_UNKNOWN_ERROR.getDescription(), ex);
+			return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+					.entity(errorDetails).build();
+		}else {
+			HashMap<String, String> errorDetails = getErrorDetails(
+					ErrorCodes.FILE_ACCESS_UNKNOWN_ERROR.getErrorCode(),
+					ErrorCodes.FILE_ACCESS_UNKNOWN_ERROR.getDescription(), ex);
+			return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+					.entity(errorDetails).build();
+		}
+		
+		
+	}
+
+	private Response getFileExistsResponse() {
+		HashMap<String, String> resp = new HashMap<String, String>();
+		resp.put("status", ErrorCodes.WORKFLOW_PATH_EXISTS.getErrorCode());
+		resp.put("message", ErrorCodes.WORKFLOW_PATH_EXISTS.getDescription());
+		return Response.status(Response.Status.BAD_REQUEST).entity(resp)
+				.build();
+	}
+
+	private String getWorkflowFileName(String appPath) {
+		String workflowFile = null;
+		if (appPath.endsWith(".xml")) {
+			workflowFile = appPath;
+		} else {
+			workflowFile = appPath + (appPath.endsWith("/") ? "" : "/")
+					+ "workflow.xml";
+		}
+		return workflowFile;
+	}
+
+	@GET
+	@Path("/readWorkflowXml")
+	public Response readWorkflowXxml(
+			@QueryParam("workflowXmlPath") String workflowPath) {
+		if (StringUtils.isEmpty(workflowPath)) {
+			throw new RuntimeException("workflowXmlPath can't be empty.");
+		}
+		try {
+			final FSDataInputStream is = hdfsFileUtils.read(workflowPath);
+			StreamingOutput streamer = new StreamingOutput() {
+				@Override
+				public void write(OutputStream os) throws IOException,
+						WebApplicationException {
+					IOUtils.copy(is, os);
+					is.close();
+					os.close();
+				}
+			};
+			return Response.ok(streamer).status(200).build();
+		} catch(IOException e){
+			return getRespCodeForException(e);
+		}
+	}
+
+	private HashMap<String, String> getErrorDetails(String status,
+			String message, Exception ex) {
+		HashMap<String, String> resp = new HashMap<String, String>();
+		resp.put("status", status);
+		if (message != null) {
+			resp.put("message", message);
+		}
+		if (ex != null) {
+			resp.put("stackTrace", ExceptionUtils.getFullStackTrace(ex));
+		}
+		return resp;
+	}
+
+	@GET
+	@Path("/getDag")
+	@Produces("image/png")
+	public Response submitWorkflow(@Context HttpHeaders headers,
+			@Context UriInfo ui, @QueryParam("jobid") String jobid) {
+		String imgUrl = getServiceUri() + "/v2/job/" + jobid + "?show=graph";
+		Map<String, String> newHeaders = utils.getHeaders(headers);
+		final InputStream is = readFromOozie(headers, imgUrl, HttpMethod.GET,
+				null, newHeaders);
+		StreamingOutput streamer = new StreamingOutput() {
+
+			@Override
+			public void write(OutputStream os) throws IOException,
+					WebApplicationException {
+				IOUtils.copy(is, os);
+				is.close();
+				os.close();
+			}
+
+		};
+		return Response.ok(streamer).status(200).build();
+	}
+
+	@GET
+	@Path("/{path: .*}")
+	public Response handleGet(@Context HttpHeaders headers, @Context UriInfo ui) {
+		try {
+			String serviceURI = buildURI(ui);
+			return consumeService(headers, serviceURI, HttpMethod.GET, null);
+		} catch (Exception ex) {
+			LOGGER.error("Error in GET proxy", ex);
+			return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+					.entity(getErrorDetailsForException("Oozie", ex)).build();
+		}
+	}
+
+	@POST
+	@Path("/{path: .*}")
+	public Response handlePost(String xml, @Context HttpHeaders headers,
+			@Context UriInfo ui) {
+		try {
+			String serviceURI = buildURI(ui);
+			return consumeService(headers, serviceURI, HttpMethod.POST, xml);
+		} catch (Exception ex) {
+			LOGGER.error("Error in POST proxy", ex);
+			return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+					.entity(getErrorDetailsForException("Oozie", ex)).build();
+		}
+	}
+
+	@DELETE
+	@Path("/{path: .*}")
+	public Response handleDelete(@Context HttpHeaders headers,
+			@Context UriInfo ui) {
+		try {
+			String serviceURI = buildURI(ui);
+			return consumeService(headers, serviceURI, HttpMethod.POST, null);
+		} catch (Exception ex) {
+			LOGGER.error("Error in DELETE proxy", ex);
+			return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+					.entity(getErrorDetailsForException("Oozie", ex)).build();
+		}
+	}
+
+	@PUT
+	@Path("/{path: .*}")
+	public Response handlePut(String body, @Context HttpHeaders headers,
+			@Context UriInfo ui) {
+		try {
+			String serviceURI = buildURI(ui);
+			return consumeService(headers, serviceURI, HttpMethod.PUT, body);
+		} catch (Exception ex) {
+			LOGGER.error("Error in PUT proxy", ex);
+			return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+					.entity(getErrorDetailsForException("Oozie", ex)).build();
+		}
+	}
+
+	private Map<String, String> getErrorDetailsForException(String component,
+			Exception ex) {
+		String errorCode = component + "exception";
+		String errorMessage = component + " Exception";
+		if (ex instanceof RuntimeException) {
+			Throwable cause = ex.getCause();
+			if (cause instanceof IOException) {
+				errorCode = component + "io.exception";
+				errorMessage = component + "IO Exception";
+			}
+		}
+		return getErrorDetails(errorCode, errorMessage, ex);
+	}
+
+	private String submitWorkflowJobToOozie(HttpHeaders headers,
+			String filePath, MultivaluedMap<String, String> queryParams,
+			JobType jobType) {
+		String nameNode = "hdfs://"
+				+ viewContext.getCluster().getConfigurationValue("hdfs-site",
+						"dfs.namenode.rpc-address");
+
+		if (!queryParams.containsKey("config.nameNode")) {
+			ArrayList<String> nameNodes = new ArrayList<String>();
+			LOGGER.info("Namenode===" + nameNode);
+			nameNodes.add(nameNode);
+			queryParams.put("config.nameNode", nameNodes);
+		}
+
+		HashMap<String, String> workflowConigs = getWorkflowConfigs(filePath,
+				queryParams, jobType, nameNode);
+		String configXMl = oozieUtils.generateConfigXml(workflowConigs);
+		LOGGER.info("Config xml==" + configXMl);
+		HashMap<String, String> customHeaders = new HashMap<String, String>();
+		customHeaders.put("Content-Type", "application/xml;charset=UTF-8");
+		Response serviceResponse = consumeService(headers, getServiceUri()
+				+ "/v2/jobs?" + getJobSumbitOozieParams(queryParams),
+				HttpMethod.POST, configXMl, customHeaders);
+
+		LOGGER.info("REsp from oozie status entity=="
+				+ serviceResponse.getEntity());
+		if (serviceResponse.getEntity() instanceof String) {
+			return (String) serviceResponse.getEntity();
+		} else {
+			return "success";
+		}
+
+	}
+
+	private HashMap<String, String> getWorkflowConfigs(String filePath,
+			MultivaluedMap<String, String> queryParams, JobType jobType,
+			String nameNode) {
+		HashMap<String, String> workflowConigs = new HashMap<String, String>();
+		if (queryParams.containsKey("resourceManager")
+				&& "useDefault".equals(queryParams.getFirst("resourceManager"))) {
+			String jobTrackerNode = viewContext.getCluster()
+					.getConfigurationValue("yarn-site",
+							"yarn.resourcemanager.address");
+			LOGGER.info("jobTrackerNode===" + jobTrackerNode);
+			workflowConigs.put("resourceManager", jobTrackerNode);
+			workflowConigs.put("jobTracker", jobTrackerNode);
+		}
+		if (queryParams != null) {
+			for (Map.Entry<String, List<String>> entry : queryParams.entrySet()) {
+				if (entry.getKey().startsWith("config.")) {
+					if (entry.getValue() != null && entry.getValue().size() > 0) {
+						workflowConigs.put(entry.getKey().substring(7), entry
+								.getValue().get(0));
+					}
+				}
+			}
+		}
+
+		if (queryParams.containsKey("oozieconfig.useSystemLibPath")) {
+			String useSystemLibPath = queryParams
+					.getFirst("oozieconfig.useSystemLibPath");
+			workflowConigs.put(OOZIE_USE_SYSTEM_LIBPATH_CONF_KEY,
+					useSystemLibPath);
+		} else {
+			workflowConigs.put(OOZIE_USE_SYSTEM_LIBPATH_CONF_KEY, "true");
+		}
+		if (queryParams.containsKey("oozieconfig.rerunOnFailure")) {
+			String rerunFailnodes = queryParams
+					.getFirst("oozieconfig.rerunOnFailure");
+			workflowConigs.put(OOZIE_WF_RERUN_FAILNODES_CONF_KEY,
+					rerunFailnodes);
+		} else {
+			workflowConigs.put(OOZIE_WF_RERUN_FAILNODES_CONF_KEY, "true");
+		}
+		workflowConigs.put("user.name", viewContext.getUsername());
+		workflowConigs.put(oozieUtils.getJobPathPropertyKey(jobType), nameNode + filePath);
+		return workflowConigs;
+	}
+
+	private String getJobSumbitOozieParams(
+			MultivaluedMap<String, String> queryParams) {
+		StringBuilder query = new StringBuilder();
+		if (queryParams != null) {
+			for (Map.Entry<String, List<String>> entry : queryParams.entrySet()) {
+				if (entry.getKey().startsWith(OOZIEPARAM_PREFIX)) {
+					if (entry.getValue() != null && entry.getValue().size() > 0) {
+						for (String val : entry.getValue()) {
+							query.append(
+									entry.getKey().substring(
+											OOZIEPARAM_PREFIX_LENGTH))
+									.append(EQUAL_SYMBOL).append(val)
+									.append("&");
+						}
+					}
+				}
+			}
+		}
+		return query.toString();
+	}
+
+	private String buildURI(UriInfo ui) {
+		String uiURI = ui.getAbsolutePath().getPath();
+		int index = uiURI.indexOf("proxy/") + 5;
+		uiURI = uiURI.substring(index);
+		String serviceURI = getServiceUri();
+		serviceURI += uiURI;
+		MultivaluedMap<String, String> params = addOrReplaceUserName(ui.getQueryParameters());
+		return serviceURI+utils.convertParamsToUrl(params);
+	}
+	private MultivaluedMap<String, String> addOrReplaceUserName(MultivaluedMap<String, String> parameters){
+		for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
+			if ("user.name".equals(entry.getKey())) {
+				ArrayList<String> vals = new ArrayList<String>(1);
+				vals.add(viewContext.getUsername());
+				entry.setValue(vals);
+			}
+		}
+		return parameters;
+	}
+
+	private String getServiceUri() {
+		String serviceURI = viewContext.getProperties().get(SERVICE_URI_PROP) != null ? viewContext
+				.getProperties().get(SERVICE_URI_PROP) : DEFAULT_SERVICE_URI;
+		return serviceURI;
+	}
+
+	private Response consumeService(HttpHeaders headers, String urlToRead,
+			String method, String body) throws Exception {
+		return consumeService(headers, urlToRead, method, body, null);
+	}
+	
+	private Response consumeService(HttpHeaders headers, String urlToRead,
+			String method, String body, Map<String, String> customHeaders) {
+		Response response = null;
+		InputStream stream = readFromOozie(headers, urlToRead, method, body,
+				customHeaders);
+		String stringResponse = null;
+		try {
+			stringResponse = IOUtils.toString(stream);
+		} catch (IOException e) {
+			LOGGER.error("Error while converting stream to string", e);
+			throw new RuntimeException(e);
+		}
+		if (stringResponse.contains(Response.Status.BAD_REQUEST.name())) {
+			response = Response.status(Response.Status.BAD_REQUEST)
+					.entity(stringResponse).type(MediaType.TEXT_PLAIN).build();
+		} else {
+			response = Response.status(Response.Status.OK)
+					.entity(stringResponse).type(utils.deduceType(stringResponse))
+					.build();
+		}
+		return response;
+	}
+
+	private InputStream readFromOozie(HttpHeaders headers, String urlToRead,
+			String method, String body, Map<String, String> customHeaders) {
+
+		Map<String, String> newHeaders = utils.getHeaders(headers);
+		newHeaders.put(USER_NAME_HEADER, USER_OOZIE_SUPER);
+
+		newHeaders.put(DO_AS_HEADER, viewContext.getUsername());
+		newHeaders.put("Accept", MediaType.APPLICATION_JSON);
+		if (customHeaders != null) {
+			newHeaders.putAll(customHeaders);
+		}
+		LOGGER.info(String.format("Proxy request for url: [%s] %s", method,
+				urlToRead));
+		
+		return readFromUrl(urlToRead, method, body, newHeaders);
+	}
+
+	private InputStream readFromUrl(String urlToRead, String method, String body,
+			Map<String, String> newHeaders) {
+		URLStreamProvider streamProvider = viewContext.getURLStreamProvider();
+		InputStream stream = null;
+		try {
+			if (isSecurityEnabled()) {
+				stream = streamProvider.readAsCurrent(urlToRead, method, body,
+						newHeaders);
+
+			} else {
+				stream = streamProvider.readFrom(urlToRead, method, body,
+						newHeaders);
+			}
+		} catch (IOException e) {
+			LOGGER.error("error talking to oozie", e);
+			throw new RuntimeException(e);
+		}
+		return stream;
+	}
+
+	
+	private boolean isSecurityEnabled() {
+		String authType = viewContext.getCluster().getConfigurationValue(
+				"core-site", "hadoop.security.authentication");
+		LOGGER.info("Auth Type=" + authType);
+		return !"simple".equalsIgnoreCase(authType);
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java
new file mode 100644
index 0000000..170132f
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java
@@ -0,0 +1,71 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.ambari.view;
+
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class OozieUtils {
+	private final static Logger LOGGER = LoggerFactory
+			.getLogger(OozieUtils.class);
+	private Utils utils = new Utils();
+
+	public String generateConfigXml(Map<String, String> map) {
+		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+		DocumentBuilder db;
+		try {
+			db = dbf.newDocumentBuilder();
+			Document doc = db.newDocument();
+			Element configElement = doc.createElement("configuration");
+			doc.appendChild(configElement);
+			for (Map.Entry<String, String> entry : map.entrySet()) {
+				Element propElement = doc.createElement("property");
+				configElement.appendChild(propElement);
+				Element nameElem = doc.createElement("name");
+				nameElem.setTextContent(entry.getKey());
+				Element valueElem = doc.createElement("value");
+				valueElem.setTextContent(entry.getValue());
+				propElement.appendChild(nameElem);
+				propElement.appendChild(valueElem);
+			}
+			return utils.generateXml(doc);
+		} catch (ParserConfigurationException e) {
+			LOGGER.error("error in generating config xml", e);
+			throw new RuntimeException(e);
+		}
+	}
+	public String getJobPathPropertyKey(JobType jobType) {
+		switch (jobType) {
+		case WORKFLOW:
+			return "oozie.wf.application.path";
+		case COORDINATOR:
+			return "oozie.coord.application.path";
+		case BUNDLE:
+			return "oozie.bundle.application.path";
+		}
+		throw new RuntimeException("Unknown Job Type");
+	}
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/Utils.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/Utils.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/Utils.java
new file mode 100644
index 0000000..61d878e
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/Utils.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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.ambari.view;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public class Utils {
+	private static final String XML_INDENT_SPACES = "4";
+	private static final String XML_INDENT_AMT_PROP_NAME = "{http://xml.apache.org/xslt}indent-amount";
+	private final static Logger LOGGER = LoggerFactory
+			.getLogger(Utils.class);
+	public String formatXml(String xml) {
+		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+		try {
+			DocumentBuilder db = dbf.newDocumentBuilder();
+			StreamResult result = new StreamResult(new StringWriter());
+			Document document = db
+					.parse(new InputSource(new StringReader(xml)));
+			Transformer transformer = TransformerFactory.newInstance()
+					.newTransformer();
+			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+			transformer.setOutputProperty(XML_INDENT_AMT_PROP_NAME,
+					XML_INDENT_SPACES);
+			DOMSource source = new DOMSource(document);
+			transformer.transform(source, result);
+			return result.getWriter().toString();
+		} catch (ParserConfigurationException | SAXException | IOException
+				| TransformerFactoryConfigurationError | TransformerException e) {
+			LOGGER.error("Error in formatting xml", e);
+			throw new RuntimeException(e);
+		}
+	}
+	public String generateXml(Document doc){
+		DOMSource domSource = new DOMSource(doc);
+		StringWriter writer = new StringWriter();
+		StreamResult result = new StreamResult(writer);
+		TransformerFactory tf = TransformerFactory.newInstance();
+		Transformer transformer;
+		try {
+			transformer = tf.newTransformer();
+			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+			transformer.setOutputProperty(XML_INDENT_AMT_PROP_NAME,
+					XML_INDENT_SPACES);
+			try {
+				transformer.transform(domSource, result);
+			} catch (TransformerException e) {
+				throw new RuntimeException(e);
+			}
+			return writer.toString();
+		} catch (TransformerConfigurationException tce) {
+			throw new RuntimeException(tce);
+		}
+		
+	}
+
+	public Map<String, String> getHeaders(HttpHeaders headers) {
+		MultivaluedMap<String, String> requestHeaders = headers
+				.getRequestHeaders();
+		Set<Entry<String, List<String>>> headerEntrySet = requestHeaders
+				.entrySet();
+		HashMap<String, String> headersMap = new HashMap<String, String>();
+		for (Entry<String, List<String>> headerEntry : headerEntrySet) {
+			String key = headerEntry.getKey();
+			List<String> values = headerEntry.getValue();
+			headersMap.put(key, strJoin(values, ","));
+		}
+		return headersMap;
+	}
+
+	public String strJoin(List<String> strings, String separator) {
+		StringBuilder stringBuilder = new StringBuilder();
+		for (int i = 0, il = strings.size(); i < il; i++) {
+			if (i > 0) {
+				stringBuilder.append(separator);
+			}
+			stringBuilder.append(strings.get(i));
+		}
+		return stringBuilder.toString();
+	}
+	public MediaType deduceType(String stringResponse) {
+		if (stringResponse.startsWith("{")) {
+			return MediaType.APPLICATION_JSON_TYPE;
+		} else if (stringResponse.startsWith("<")) {
+			return MediaType.TEXT_XML_TYPE;
+		} else {
+			return MediaType.APPLICATION_JSON_TYPE;
+		}
+	}
+
+	public String convertParamsToUrl(MultivaluedMap<String, String> parameters) {
+		StringBuilder urlBuilder = new StringBuilder();
+		boolean firstEntry = true;
+		for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
+			if (firstEntry) {
+				urlBuilder.append("?");
+			} else {
+				urlBuilder.append("&");
+			}
+			boolean firstVal = true;
+			for (String val : entry.getValue()) {
+				urlBuilder.append(firstVal ? "" : "&").append(entry.getKey())
+						.append("=").append(val);
+				firstVal = false;
+			}
+			firstEntry = false;
+		}
+		return urlBuilder.toString();
+	}
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/.jshintrc
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/.jshintrc b/contrib/views/wfmanager/src/main/resources/ui/.jshintrc
new file mode 100644
index 0000000..ed9a144
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/.jshintrc
@@ -0,0 +1,38 @@
+{
+  "predef": [
+    "document",
+    "window",
+    "-Promise",
+	"vkbeautify",
+	"moment",
+	"X2JS",
+	"jsPlumb",
+	"cytoscape",
+	"dagre"
+  ],
+  "browser": true,
+  "boss": true,
+  "curly": true,
+  "debug": false,
+  "devel": true,
+  "eqeqeq": true,
+  "evil": true,
+  "forin": false,
+  "immed": false,
+  "laxbreak": false,
+  "newcap": true,
+  "noarg": true,
+  "noempty": false,
+  "nonew": false,
+  "nomen": false,
+  "onevar": false,
+  "plusplus": false,
+  "regexp": false,
+  "undef": true,
+  "sub": true,
+  "strict": false,
+  "white": false,
+  "eqnull": true,
+  "esnext": true,
+  "unused": true
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/app/components/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/archive-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/archive-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/archive-config.js
index d53b459..7ea46c4 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/archive-config.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/archive-config.js
@@ -16,9 +16,8 @@
 */
 
 import Ember from 'ember';
-import EmberValidations from 'ember-validations';
 
-export default Ember.Component.extend(EmberValidations,{
+export default Ember.Component.extend({
   fileBrowser : Ember.inject.service('file-browser'),
   initialize : function(){
     this.on('fileSelected',function(fileName){

http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
new file mode 100644
index 0000000..2799db5
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
@@ -0,0 +1,262 @@
+/*
+*    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.
+*/
+import Ember from 'ember';
+import {Bundle} from '../domain/bundle/bundle';
+import {BundleGenerator} from '../domain/bundle/bundle-xml-generator';
+import {BundleXmlImporter} from '../domain/bundle/bundle-xml-importer';
+import { validator, buildValidations } from 'ember-cp-validations';
+import Constants from '../utils/constants';
+
+const Validations = buildValidations({
+  'bundle.name': validator('presence', {
+    presence : true
+  }),
+  'bundle.coordinators': {
+    validators: [
+      validator('operand-length', {
+        min : 1,
+        dependentKeys: ['bundle','bundle.coordinators.[]'],
+        message : 'Alteast one coordinator is required',
+        disabled(model, attribute) {
+          return !model.get('bundle');
+        }
+      })
+    ]
+  }
+});
+
+export default Ember.Component.extend(Ember.Evented, Validations, {
+  bundle : null,
+  propertyExtractor : Ember.inject.service('property-extractor'),
+  fileBrowser : Ember.inject.service('file-browser'),
+  workspaceManager : Ember.inject.service('workspace-manager'),
+  initialize : function(){
+    var draftBundle = this.get('workspaceManager').restoreWorkInProgress(this.get('tabInfo.id'));
+    if(draftBundle){
+      this.set('bundle', JSON.parse(draftBundle));
+    }else{
+      this.set('bundle', this.createBundle());
+    }
+    this.get('fileBrowser').on('fileBrowserOpened',function(context){
+      this.get('fileBrowser').setContext(context);
+    }.bind(this));
+    this.on('fileSelected',function(fileName){
+      this.set(this.get('filePathModel'), fileName);
+    }.bind(this));
+    if(Ember.isBlank(this.get('bundle.name'))){
+      this.set('bundle.name', Ember.copy(this.get('tabInfo.name')));
+    }
+    this.set('showErrorMessage', false);
+    this.schedulePersistWorkInProgress();
+  }.on('init'),
+  onDestroy : function(){
+    Ember.run.cancel(this.schedulePersistWorkInProgress);
+    this.persistWorkInProgress();
+  }.on('willDestroyElement'),
+  observeFilePath : Ember.observer('bundleFilePath', function(){
+    if(!this.get('bundleFilePath') || null === this.get('bundleFilePath')){
+      return;
+    }else{
+      this.sendAction('changeFilePath', this.get('tabInfo'), this.get('bundleFilePath'));
+    }
+  }),
+  nameObserver : Ember.observer('bundle.name', function(){
+    if(!this.get('bundle')){
+      return;
+    }else if(this.get('bundle') && Ember.isBlank(this.get('bundle.name'))){
+      if(!this.get('clonedTabInfo')){
+        this.set('clonedTabInfo', Ember.copy(this.get('tabInfo')));
+      }
+      this.sendAction('changeTabName', this.get('tabInfo'), this.get('clonedTabInfo.name'));
+    }else{
+      this.sendAction('changeTabName', this.get('tabInfo'), this.get('bundle.name'));
+    }
+  }),
+  schedulePersistWorkInProgress (){
+    Ember.run.later(function(){
+      this.persistWorkInProgress();
+      this.schedulePersistWorkInProgress();
+    }.bind(this), Constants.persistWorkInProgressInterval);
+  },
+  persistWorkInProgress (){
+    if(!this.get('bundle')){
+      return;
+    }
+    var json = JSON.stringify(this.get("bundle"));
+    this.get('workspaceManager').saveWorkInProgress(this.get('tabInfo.id'), json);
+  },
+  createBundle (){
+    return Bundle.create({
+      name : '',
+      kickOffTime : {
+        value : '',
+        displayValue : '',
+        type : 'date'
+      },
+      coordinators : null
+    });
+  },
+  importSampleBundle (){
+    var deferred = Ember.RSVP.defer();
+    Ember.$.ajax({
+      url: "/sampledata/bundle.xml",
+      dataType: "text",
+      cache:false,
+      success: function(data) {
+        deferred.resolve(data);
+      }.bind(this),
+      failure : function(data){
+        deferred.reject(data);
+      }
+    });
+    return deferred;
+  },
+  importBundle (filePath){
+    this.set("bundleFilePath", filePath);
+    this.set("isImporting", false);
+    var deferred = this.getBundleFromHdfs(filePath);
+    deferred.promise.then(function(data){
+      this.getBundleFromXml(data);
+      this.set("isImporting", false);
+    }.bind(this)).catch(function(){
+      this.set("isImporting", false);
+      this.set("isImportingSuccess", false);
+    }.bind(this));
+  },
+  getBundleFromHdfs(filePath){
+    var url =  Ember.ENV.API_URL + "/readWorkflowXml?workflowXmlPath="+filePath;
+    var deferred = Ember.RSVP.defer();
+    Ember.$.ajax({
+      url: url,
+      method: 'GET',
+      dataType: "text",
+      beforeSend: function (xhr) {
+        xhr.setRequestHeader("X-XSRF-HEADER", Math.round(Math.random()*100000));
+        xhr.setRequestHeader("X-Requested-By", "Ambari");
+      }
+    }).done(function(data){
+      deferred.resolve(data);
+    }).fail(function(){
+      deferred.reject();
+    });
+    return deferred;
+  },
+  getBundleFromXml(bundleXml){
+    var bundleXmlImporter = BundleXmlImporter.create({});
+    var bundle = bundleXmlImporter.importBundle(bundleXml);
+    this.set("bundle", bundle);
+  },
+  actions : {
+    closeFileBrowser(){
+      this.set("showingFileBrowser", false);
+      this.get('fileBrowser').getContext().trigger('fileSelected', this.get('filePath'));
+      if(this.get('bundleFilePath')){
+        this.importBundle(Ember.copy(this.get('bundleFilePath')));
+        this.set('bundleFilePath', null);
+      }
+    },
+    openFileBrowser(model, context){
+      if(!context){
+        context = this;
+      }
+      this.get('fileBrowser').trigger('fileBrowserOpened',context);
+      this.set('filePathModel', model);
+      this.set('showingFileBrowser', true);
+    },
+    createCoordinator(){
+      this.set('coordinatorEditMode', false);
+      this.set('coordinatorCreateMode', true);
+      this.set('currentCoordinator',{
+        name : undefined,
+        appPath : undefined,
+        configuration : {
+          property : Ember.A([])
+        }
+      });
+    },
+    editCoordinator(index){
+      this.set('coordinatorEditMode', true);
+      this.set('coordinatorCreateMode', false);
+      this.set('currentCoordinatorIndex', index);
+      this.set('currentCoordinator', Ember.copy(this.get('bundle.coordinators').objectAt(index)));
+    },
+    addCoordinator(){
+      if(!this.get('bundle.coordinators')){
+        this.set('bundle.coordinators', Ember.A([]));
+      }
+      this.get('bundle.coordinators').pushObject(Ember.copy(this.get('currentCoordinator')));
+      this.set('coordinatorCreateMode', false);
+    },
+    updateCoordinator(){
+      this.get('bundle.coordinators').replace(this.get('currentCoordinatorIndex'), 1, Ember.copy(this.get('currentCoordinator')));
+      this.set('coordinatorEditMode', false);
+    },
+    deleteCoordinator(index){
+      this.get('bundle.coordinators').removeAt(index);
+      if(index === this.get('currentCoordinatorIndex')){
+        this.set('coordinatorEditMode', false);
+      }
+    },
+    cancelCoordinatorOperation(){
+      this.set('coordinatorCreateMode', false);
+      this.set('coordinatorEditMode', false);
+    },
+    confirmReset(){
+      this.set('showingResetConfirmation', true);
+    },
+    resetBundle(){
+      this.set('bundle', this.createBundle());
+    },
+    closeBundleSubmitConfig(){
+      this.set("showingJobConfig", false);
+    },
+    submitBundle(){
+      if(this.get('validations.isInvalid')) {
+        this.set('showErrorMessage', true);
+        return;
+      }
+      var bundleGenerator = BundleGenerator.create({bundle:this.get("bundle")});
+      var bundleXml = bundleGenerator.process();
+      var dynamicProperties = this.get('propertyExtractor').getDynamicProperties(bundleXml);
+      var configForSubmit = {props : dynamicProperties, xml : bundleXml, params : this.get('bundle.parameters')};
+      this.set("bundleConfigs", configForSubmit);
+      this.set("showingJobConfig", true);
+    },
+    preview(){
+      if(this.get('validations.isInvalid')) {
+        this.set('showErrorMessage', true);
+        return;
+      }
+      this.set("showingPreview", false);
+      var bundleGenerator = BundleGenerator.create({bundle:this.get("bundle")});
+      var bundleXml = bundleGenerator.process();
+      this.set("previewXml", vkbeautify.xml(bundleXml));
+      this.set("showingPreview", true);
+    },
+    importBundleTest(){
+      var deferred = this.importSampleBundle();
+      deferred.promise.then(function(data){
+        this.getBundleFromXml(data);
+      }.bind(this)).catch(function(e){
+        throw new Error(e);
+      });
+    },
+    openTab(type, path){
+      this.sendAction('openTab', type, path);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-coord-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-coord-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-coord-config.js
new file mode 100644
index 0000000..229b2cc
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-coord-config.js
@@ -0,0 +1,108 @@
+/*
+*    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.
+*/
+import Ember from 'ember';
+import { validator, buildValidations } from 'ember-cp-validations';
+
+const Validations = buildValidations({
+  'coordinator.name': validator('presence', {
+    presence : true
+  }),
+  'coordinator.appPath': validator('presence', {
+    presence : true
+  })
+});
+export default Ember.Component.extend(Validations, {
+  initialize : function(){
+    this.on('fileSelected',function(fileName){
+      this.set(this.get('filePathModel'), fileName);
+    }.bind(this));
+    this.set('showErrorMessage', false);
+  }.on('init'),
+  isValid(){
+      if(this.get('validations.isInvalid')) {
+        this.set('showErrorMessage', true);
+        return false;
+      }
+      return true;
+  },
+  readFromHdfs(filePath){
+    var url =  Ember.ENV.API_URL + "/readWorkflowXml?workflowXmlPath="+filePath;
+    var deferred = Ember.RSVP.defer();
+    Ember.$.ajax({
+      url: url,
+      method: 'GET',
+      dataType: "text",
+      beforeSend: function (xhr) {
+        xhr.setRequestHeader("X-XSRF-HEADER", Math.round(Math.random()*100000));
+        xhr.setRequestHeader("X-Requested-By", "Ambari");
+      }
+    }).done(function(data){
+      deferred.resolve(data);
+    }).fail(function(){
+      deferred.reject();
+    });
+    return deferred;
+  },
+  importSampleCoordinator (){
+    var deferred = Ember.RSVP.defer();
+    Ember.$.ajax({
+      url: "/sampledata/coordinator.xml",
+      dataType: "text",
+      cache:false,
+      success: function(data) {
+        deferred.resolve(data);
+      }.bind(this),
+      failure : function(data){
+        deferred.reject(data);
+      }
+    });
+    return deferred;
+  },
+  actions : {
+    openFileBrowser(model){
+      this.set('filePathModel', model);
+      this.sendAction("openFileBrowser", model, this);
+    },
+    addCoordinator(){
+      if(this.isValid()){
+        this.sendAction('add');
+      }
+    },
+    updateCoordinator(){
+      if(this.isValid()){
+        this.sendAction('update');
+      }
+    },
+    cancelCoordinatorOperation(){
+      this.sendAction('cancel');
+    },
+    openTab(type, path){
+      this.sendAction('openTab', type, path);
+    },
+    showCoordinatorName(){
+      this.set('coordinatorName', null);
+      var deferred = this.readFromHdfs(this.get('coordinator.appPath'));
+      deferred.promise.then(function(data){
+        var x2js = new X2JS();
+        var coordJson = x2js.xml_str2json(data);
+        this.set('coordinatorName', coordJson["coordinator-app"]._name);
+      }.bind(this)).catch(function(){
+        this.set('coordinatorName', null);
+      }.bind(this));
+    }
+  }
+});