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 <[email protected]>
Authored: Fri Oct 28 00:33:36 2016 +0530
Committer: Dipayan Bhowmick <[email protected]>
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));
+    }
+  }
+});

Reply via email to