AMBARI-19031: UI Enhancements, import/export assets and smart version 
configuration (Padma Priya via nitirajrathore)


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

Branch: refs/heads/branch-2.5
Commit: 9bc0b99609e8c746d055dafc5c42eea60a6b80ed
Parents: c63d692
Author: Nitiraj Rathore <[email protected]>
Authored: Fri Dec 16 15:01:36 2016 +0530
Committer: Nitiraj Rathore <[email protected]>
Committed: Fri Dec 16 15:01:36 2016 +0530

----------------------------------------------------------------------
 contrib/views/wfmanager/pom.xml                 |   9 +-
 .../apache/oozie/ambari/view/AmbariIOUtil.java  |  65 +++
 .../apache/oozie/ambari/view/HDFSFileUtils.java |  46 +-
 .../ambari/view/OozieProxyImpersonator.java     | 236 +++++++---
 .../apache/oozie/ambari/view/OozieUtils.java    |  52 +++
 .../oozie/ambari/view/WorkflowFileInfo.java     |  64 +++
 .../oozie/ambari/view/WorkflowFilesService.java | 116 +++++
 .../oozie/ambari/view/assets/AssetRepo.java     |  42 ++
 .../oozie/ambari/view/assets/AssetService.java  |  51 +++
 .../ambari/view/assets/model/ActionAsset.java   |  60 +++
 .../oozie/ambari/view/model/BaseModel.java      |  48 ++
 .../workflowmanager/WorkflowManagerService.java |  76 ++++
 .../WorkflowsManagerResource.java               |  51 +++
 .../view/workflowmanager/WorkflowsRepo.java     |  69 +++
 .../view/workflowmanager/model/Workflow.java    |  88 ++++
 .../ui/app/components/bundle-config.js          |  18 +-
 .../ui/app/components/bundle-coord-config.js    |   2 +-
 .../app/components/bundle-version-settings.js   |  49 +++
 .../resources/ui/app/components/coord-config.js |  30 +-
 .../ui/app/components/coord-version-settings.js |  49 +++
 .../ui/app/components/date-with-expr.js         |   1 -
 .../ui/app/components/designer-workspace.js     |  63 ++-
 .../ui/app/components/flow-designer.js          | 433 +++++++++++++++++--
 .../resources/ui/app/components/hdfs-browser.js |   3 +-
 .../ui/app/components/import-from-stream.js     |  67 +++
 .../resources/ui/app/components/job-config.js   |   2 +-
 .../resources/ui/app/components/job-details.js  |  28 +-
 .../main/resources/ui/app/components/job-row.js |   4 +
 .../ui/app/components/name-value-config.js      |   1 -
 .../ui/app/components/preview-dialog.js         |   7 +
 .../main/resources/ui/app/components/save-wf.js |  49 +--
 .../ui/app/components/search-create-new-bar.js  |  17 +-
 .../ui/app/components/workflow-actions.js       |   8 +
 .../ui/app/components/workflow-icon.js          |  21 +
 .../ui/app/controllers/design/dashboardtab.js   |  81 ++++
 .../ui/app/controllers/design/jobtab.js         |  59 +++
 .../main/resources/ui/app/controllers/job.js    |  30 +-
 .../app/domain/bundle/bundle-xml-generator.js   |   2 +-
 .../ui/app/domain/bundle/bundle-xml-importer.js |  20 +-
 .../coordinator/coordinator-xml-generator.js    |   2 +-
 .../coordinator/coordinator-xml-importer.js     |  22 +-
 .../ui/app/domain/cytoscape-flow-renderer.js    |  13 +-
 .../resources/ui/app/domain/mapping-utils.js    |   2 +-
 .../resources/ui/app/domain/schema-versions.js  | 165 ++++++-
 .../ui/app/domain/workflow-importer.js          |  35 +-
 .../ui/app/domain/workflow-xml-generator.js     |  15 +
 .../src/main/resources/ui/app/router.js         |   5 +-
 .../main/resources/ui/app/routes/dashboard.js   |   4 +-
 .../src/main/resources/ui/app/routes/design.js  |  15 +-
 .../ui/app/routes/design/dashboardtab.js        | 154 +++++++
 .../resources/ui/app/routes/design/jobtab.js    |  94 ++++
 .../src/main/resources/ui/app/routes/index.js   |   2 +-
 .../src/main/resources/ui/app/routes/job.js     |  29 +-
 .../ui/app/services/dashboard-context.js        |  38 ++
 .../main/resources/ui/app/services/save-job.js  |  42 ++
 .../src/main/resources/ui/app/styles/app.less   |  72 ++-
 .../app/templates/components/bundle-config.hbs  |  42 +-
 .../components/bundle-coord-config.hbs          |  17 +-
 .../templates/components/bundle-job-details.hbs |  12 +-
 .../components/bundle-version-settings.hbs      |  45 ++
 .../app/templates/components/coord-config.hbs   | 359 +++++++--------
 .../templates/components/coord-job-details.hbs  |   6 +-
 .../components/coord-version-settings.hbs       |  45 ++
 .../templates/components/designer-workspace.hbs | 119 ++---
 .../app/templates/components/flow-designer.hbs  | 154 +++++--
 .../app/templates/components/hdfs-browser.hbs   |   2 +-
 .../templates/components/import-from-stream.hbs |  63 +++
 .../ui/app/templates/components/job-config.hbs  |  10 +-
 .../ui/app/templates/components/job-details.hbs |  34 +-
 .../ui/app/templates/components/job-row.hbs     |  14 +-
 .../app/templates/components/preview-dialog.hbs |   5 +-
 .../components/search-create-new-bar.hbs        |   2 +-
 .../app/templates/components/search-table.hbs   |   3 +-
 .../templates/components/workflow-actions.hbs   |   8 +-
 .../app/templates/components/workflow-icon.hbs  |  24 +
 .../components/workflow-job-details.hbs         |  28 +-
 .../main/resources/ui/app/templates/design.hbs  |   2 +-
 .../ui/app/templates/design/dashboardtab.hbs    |  30 ++
 .../ui/app/templates/design/jobtab.hbs          |  21 +
 .../src/main/resources/ui/app/templates/job.hbs |   2 +-
 .../main/resources/ui/app/utils/common-utils.js |   3 +
 .../main/resources/ui/app/utils/constants.js    |   2 +-
 .../wfmanager/src/main/resources/ui/bower.json  |   3 +-
 .../src/main/resources/ui/ember-cli-build.js    |   7 +
 .../src/main/resources/ui/package.json          |   4 +-
 .../components/bundle-version-settings-test.js  |  40 ++
 .../components/coord-version-settings-test.js   |  40 ++
 .../components/import-from-stream-test.js       |  41 ++
 .../components/workflow-icon-test.js            |  40 ++
 .../unit/routes/design/dashboardtab-test.js     |  27 ++
 .../unit/services/dashboard-context-test.js     |  28 ++
 .../ui/tests/unit/services/save-job-test.js     |  29 ++
 92 files changed, 3530 insertions(+), 607 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/pom.xml
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/pom.xml b/contrib/views/wfmanager/pom.xml
index b8578ac..95b988f 100644
--- a/contrib/views/wfmanager/pom.xml
+++ b/contrib/views/wfmanager/pom.xml
@@ -213,12 +213,11 @@
                                                        <goal>exec</goal>
                                                </goals>
                                                <configuration>
-                                                       
<workingDirectory>${basedir}/src/main/resources/ui</workingDirectory>
-                                                       
<executable>node/node</executable>
+                                                       
<workingDirectory>${ui.directory}</workingDirectory>
+                                                       
<executable>${ui.directory}/node_modules/.bin/${ember.executable}</executable>
                                                        <arguments>
-                                                               
<argument>node_modules/.bin/ember</argument>
                                                                
<argument>build</argument>
-
+                                                               
<argument>-prod</argument>
                                                        </arguments>
                                                </configuration>
                                        </execution>
@@ -303,6 +302,7 @@
         </activation>
         <properties>
           <node.executable>node.exe</node.executable>
+          <ember.executable>ember.cmd</ember.executable>
           <skip.nodegyp.chmod>true</skip.nodegyp.chmod>
         </properties>
       </profile>
@@ -315,6 +315,7 @@
         </activation>
         <properties>
           <node.executable>node</node.executable>
+          <ember.executable>ember</ember.executable>
           <skip.nodegyp.chmod>false</skip.nodegyp.chmod>
         </properties>
       </profile>

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/AmbariIOUtil.java
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/AmbariIOUtil.java
 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/AmbariIOUtil.java
new file mode 100644
index 0000000..93447b7
--- /dev/null
+++ 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/AmbariIOUtil.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.oozie.ambari.view;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+import org.apache.ambari.view.URLStreamProvider;
+import org.apache.ambari.view.ViewContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AmbariIOUtil {
+       private final static Logger LOGGER = LoggerFactory
+                       .getLogger(AmbariIOUtil.class);
+       private ViewContext viewContext;
+
+       public AmbariIOUtil(ViewContext viewContext) {
+               super();
+               this.viewContext = viewContext;
+       }
+
+       public 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);
+       }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/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
index 58c3980..327d8fc 100644
--- 
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
@@ -17,6 +17,7 @@
  */
 package org.apache.oozie.ambari.view;
 
+import java.io.FileNotFoundException;
 import java.io.IOException;
 
 import org.apache.ambari.view.ViewContext;
@@ -24,6 +25,7 @@ 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.apache.hadoop.fs.FileStatus;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,10 +38,10 @@ public class HDFSFileUtils {
                super();
                this.viewContext = viewContext;
        }
+
        public boolean fileExists(String path) {
-               boolean fileExists;
                try {
-                       fileExists = getHdfsgetApi().exists(path);
+                       return getHdfsgetApi().exists(path);
                } catch (IOException e) {
                        LOGGER.error(e.getMessage(), e);
                        throw new RuntimeException(e);
@@ -47,11 +49,9 @@ public class HDFSFileUtils {
                        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{
+
+       public FSDataInputStream read(String filePath) throws IOException {
                FSDataInputStream is;
                try {
                        is = getHdfsgetApi().open(filePath);
@@ -60,19 +60,28 @@ public class HDFSFileUtils {
                }
                return is;
        }
-       public String createWorkflowFile( String workflowFile,String postBody,
-                       boolean overwrite) throws IOException {
+
+       public String writeToFile(String filePath, String content, boolean 
overwrite)
+                       throws IOException {
                FSDataOutputStream fsOut;
                try {
-                       fsOut = getHdfsgetApi().create(workflowFile,
-                                       overwrite);
+                       fsOut = getHdfsgetApi().create(filePath, overwrite);
                } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                }
-               fsOut.write(postBody.getBytes());
+               fsOut.write(content.getBytes());
                fsOut.close();
-               return workflowFile;
+               return filePath;
+       }
+
+       public void deleteFile(String filePath) throws IOException {
+               try {
+                       getHdfsgetApi().delete(filePath, false);
+               } catch (InterruptedException e) {
+                       throw new RuntimeException(e);
+               }
        }
+
        private HdfsApi getHdfsgetApi() {
                try {
                        return HdfsUtil.connectToHDFSApi(viewContext);
@@ -84,4 +93,17 @@ public class HDFSFileUtils {
                }
        }
 
+       public FileStatus getFileStatus(String filePath) {
+               try {
+                       return getHdfsgetApi().getFileStatus(filePath);
+               } catch (FileNotFoundException e) {
+                       throw new RuntimeException(e);
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               } catch (InterruptedException e) {
+                       throw new RuntimeException(e);
+               }
+
+       }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/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 0533f04..08a166d 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
@@ -45,13 +45,13 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.StreamingOutput;
 import javax.ws.rs.core.UriInfo;
 
-import org.apache.ambari.view.URLStreamProvider;
 import org.apache.ambari.view.ViewContext;
 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.security.AccessControlException;
+import org.apache.oozie.ambari.view.workflowmanager.WorkflowManagerService;
+import org.apache.oozie.ambari.view.workflowmanager.WorkflowsManagerResource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -81,9 +81,13 @@ public class OozieProxyImpersonator {
 
        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 Utils utils = new Utils();
+       private AmbariIOUtil ambariIOUtil;
+       private OozieUtils oozieUtils = new OozieUtils();
        private HDFSFileUtils hdfsFileUtils;
+       private WorkflowFilesService workflowFilesService;
+       //private WorkflowManagerService workflowManagerService;
+
        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(
@@ -111,10 +115,14 @@ public class OozieProxyImpersonator {
        @Inject
        public OozieProxyImpersonator(ViewContext viewContext) {
                this.viewContext = viewContext;
-               hdfsFileUtils=new HDFSFileUtils(viewContext);
+               hdfsFileUtils = new HDFSFileUtils(viewContext);
+               workflowFilesService = new WorkflowFilesService(hdfsFileUtils);
+               ambariIOUtil=new AmbariIOUtil(viewContext);
+               //workflowManagerService = new 
WorkflowManagerService(viewContext);
                LOGGER.info(String.format(
                                "OozieProxyImpersonator initialized for 
instance: %s",
                                viewContext.getInstanceName()));
+
        }
 
        @Path("/fileServices")
@@ -122,6 +130,11 @@ public class OozieProxyImpersonator {
                return new FileServices(viewContext);
        }
 
+   @Path("/wfprojects")
+    public WorkflowsManagerResource workflowsManagerResource() {
+        return new WorkflowsManagerResource(viewContext);
+    }
+       
        @GET
        @Path("/getCurrentUserName")
        public Response getCurrentUserName() {
@@ -171,9 +184,12 @@ public class OozieProxyImpersonator {
                }
                postBody = utils.formatXml(postBody);
                try {
-                       String filePath = 
hdfsFileUtils.createWorkflowFile(getWorkflowFileName(appPath),postBody, 
overwrite);
+                       String filePath = 
workflowFilesService.createWorkflowFile(appPath,
+                                       postBody, overwrite);
                        LOGGER.info(String.format(
                                        "submit workflow job done. 
filePath=[%s]", filePath));
+               /*      workflowManagerService.saveWorkflow(appPath, 
JobType.WORKFLOW,
+                    "todo description", viewContext.getUsername());*/
                        return Response.ok().build();
                } catch (Exception ex) {
                        LOGGER.error(ex.getMessage(), ex);
@@ -181,6 +197,125 @@ public class OozieProxyImpersonator {
 
                }
        }
+       
+       @POST
+       @Path("/publishAsset")
+       @Consumes({ MediaType.TEXT_PLAIN + "," + MediaType.TEXT_XML })
+       public Response publishAsset(String postBody, @Context HttpHeaders 
headers,
+                       @Context UriInfo ui, @QueryParam("uploadPath") String 
uploadPath,
+                       @DefaultValue("false") @QueryParam("overwrite") Boolean 
overwrite) {
+               LOGGER.info("publish asset called");
+               if (StringUtils.isEmpty(uploadPath)) {
+                       throw new RuntimeException("upload path can't be 
empty.");
+               }
+               uploadPath = uploadPath.trim();
+               Response dryRunResponse = validateAsset(headers, postBody, 
ui.getQueryParameters());
+               if (dryRunResponse.getStatus() == 200) {
+                       return saveAsset(postBody, uploadPath, overwrite);
+               }
+               return dryRunResponse;
+       }
+
+       private Response validateAsset(HttpHeaders headers, String postBody, 
MultivaluedMap<String, String> queryParams) {
+               String workflowXml = oozieUtils.generateWorkflowXml(postBody);  
+               try {
+                       String tempWfPath = 
"/user/"+viewContext.getUsername()+"/tmpooziewfs/tempwf.xml";
+                       hdfsFileUtils.writeToFile(tempWfPath, workflowXml, 
true);
+                       
queryParams.put("oozieparam.action",getAsList("dryrun"));
+                       
queryParams.put("oozieconfig.rerunOnFailure",getAsList("false"));
+                       
queryParams.put("oozieconfig.useSystemLibPath",getAsList("true"));
+                       
queryParams.put("resourceManager",getAsList("useDefault"));
+                       String dryRunResp = 
submitWorkflowJobToOozie(headers,tempWfPath,queryParams,JobType.WORKFLOW);
+                       LOGGER.info(String.format("resp from validating 
asset=[%s]",dryRunResp));
+                       if (dryRunResp != null && 
dryRunResp.trim().startsWith("{")) {
+                               return 
Response.status(Response.Status.OK).entity(dryRunResp).build();
+                       } else {
+                               HashMap<String, String> resp = new 
HashMap<String, String>();
+                               resp.put("status", 
ErrorCodes.OOZIE_SUBMIT_ERROR.getErrorCode());
+                               resp.put("message", dryRunResp);
+                               //resp.put("stackTrace", dryRunResp);           
                
+                               return 
Response.status(Response.Status.BAD_REQUEST).entity(resp).build();
+                       }                       
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               }
+       }
+
+       private List<String> getAsList(String string) {
+               ArrayList<String> li=new ArrayList<>(1);
+               li.add(string);
+               return li;
+       }
+
+       private Response saveAsset(String postBody, String uploadPath,
+                       Boolean overwrite) {
+               uploadPath = workflowFilesService.getAssetFileName(uploadPath);
+               if (!overwrite) {
+                       boolean fileExists = 
hdfsFileUtils.fileExists(uploadPath);
+                       if (fileExists) {
+                               return getFileExistsResponse();
+                       }
+               }
+               postBody = utils.formatXml(postBody);
+               try {
+                       String filePath = 
workflowFilesService.createAssetFile(uploadPath,
+                                       postBody, overwrite);
+                       LOGGER.info(String.format(
+                                       "publish asset job done. 
filePath=[%s]", filePath));
+                       return Response.ok().build();
+               } catch (Exception ex) {
+                       LOGGER.error(ex.getMessage(), ex);
+                       return getRespCodeForException(ex);
+               }
+       }
+
+       @POST
+       @Path("/saveWorkflowDraft")
+       @Consumes({ MediaType.TEXT_PLAIN + "," + MediaType.TEXT_XML })
+       public Response saveDraft(String postBody, @Context HttpHeaders headers,
+                       @Context UriInfo ui, @QueryParam("app.path") String 
appPath,
+                       @DefaultValue("false") @QueryParam("overwrite") Boolean 
overwrite)
+                       throws IOException {
+               LOGGER.info("save workflow  called");
+               if (StringUtils.isEmpty(appPath)) {
+                       throw new RuntimeException("app path can't be empty.");
+               }
+               appPath = appPath.trim();
+               workflowFilesService.saveDraft(appPath, postBody, overwrite);
+       /*       workflowManagerService.saveWorkflow(appPath, JobType.WORKFLOW,
+                       "todo description", viewContext.getUsername());*/
+               return Response.ok().build();
+       }
+
+       @GET
+       @Path("/readWorkflowDraft")
+       public Response readDraft(@QueryParam("workflowXmlPath") String 
workflowPath) {
+               if (StringUtils.isEmpty(workflowPath)) {
+                       throw new RuntimeException("workflowXmlPath can't be 
empty.");
+               }
+               try {
+                       final InputStream is = 
workflowFilesService.readDraft(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);
+               }
+       }
+       
+       @POST
+       @Path("/discardWorkflowDraft")
+       public Response discardDraft(@QueryParam("workflowXmlPath") String 
workflowPath) throws IOException{
+                workflowFilesService.discardDraft(workflowPath);
+               return Response.ok().build();
+       }
 
        private Response submitJobInternal(String postBody, HttpHeaders headers,
                        UriInfo ui, String appPath, Boolean overwrite, JobType 
jobType) {
@@ -196,7 +331,8 @@ public class OozieProxyImpersonator {
                }
                postBody = utils.formatXml(postBody);
                try {
-                       String filePath = 
hdfsFileUtils.createWorkflowFile(getWorkflowFileName(appPath),postBody,overwrite);
+                       String filePath = hdfsFileUtils.writeToFile(appPath, 
postBody,
+                                       overwrite);
                        LOGGER.info(String.format(
                                        "submit workflow job done. 
filePath=[%s]", filePath));
                } catch (Exception ex) {
@@ -204,6 +340,8 @@ public class OozieProxyImpersonator {
                        return getRespCodeForException(ex);
 
                }
+               /* workflowManagerService.saveWorkflow(appPath, jobType,
+                       "todo description", viewContext.getUsername());*/
                String response = submitWorkflowJobToOozie(headers, appPath,
                                ui.getQueryParameters(), jobType);
                if (response != null && response.trim().startsWith("{")) {
@@ -226,21 +364,20 @@ public class OozieProxyImpersonator {
                                        
ErrorCodes.FILE_ACCESS_ACL_ERROR.getDescription(), ex);
                        return Response.status(Response.Status.BAD_REQUEST)
                                        .entity(errorDetails).build();
-               }else if (ex instanceof IOException){
+               } 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 {
+               } 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() {
@@ -250,18 +387,14 @@ public class OozieProxyImpersonator {
                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("/readWorkflowDetail")
+       public Response isDraftAvailable(@QueryParam("workflowXmlPath") String 
workflowPath){
+               WorkflowFileInfo workflowDetails = 
workflowFilesService.getWorkflowDetails(workflowPath);
+               return Response.ok(workflowDetails).build();
        }
-
+       
        @GET
        @Path("/readWorkflowXml")
        public Response readWorkflowXxml(
@@ -270,7 +403,7 @@ public class OozieProxyImpersonator {
                        throw new RuntimeException("workflowXmlPath can't be 
empty.");
                }
                try {
-                       final FSDataInputStream is = 
hdfsFileUtils.read(workflowPath);
+                       final InputStream is = 
workflowFilesService.readWorkflowXml(workflowPath);
                        StreamingOutput streamer = new StreamingOutput() {
                                @Override
                                public void write(OutputStream os) throws 
IOException,
@@ -281,7 +414,7 @@ public class OozieProxyImpersonator {
                                }
                        };
                        return Response.ok(streamer).status(200).build();
-               } catch(IOException e){
+               } catch (IOException e) {
                        return getRespCodeForException(e);
                }
        }
@@ -405,7 +538,7 @@ public class OozieProxyImpersonator {
                        queryParams.put("config.nameNode", nameNodes);
                }
 
-               HashMap<String, String> workflowConigs = 
getWorkflowConfigs(filePath,
+               Map<String, String> workflowConigs = 
getWorkflowConfigs(filePath,
                                queryParams, jobType, nameNode);
                String configXMl = oozieUtils.generateConfigXml(workflowConigs);
                LOGGER.info("Config xml==" + configXMl);
@@ -415,7 +548,7 @@ public class OozieProxyImpersonator {
                                + "/v2/jobs?" + 
getJobSumbitOozieParams(queryParams),
                                HttpMethod.POST, configXMl, customHeaders);
 
-               LOGGER.info("REsp from oozie status entity=="
+               LOGGER.info("Resp from oozie status entity=="
                                + serviceResponse.getEntity());
                if (serviceResponse.getEntity() instanceof String) {
                        return (String) serviceResponse.getEntity();
@@ -425,7 +558,7 @@ public class OozieProxyImpersonator {
 
        }
 
-       private HashMap<String, String> getWorkflowConfigs(String filePath,
+       private Map<String, String> getWorkflowConfigs(String filePath,
                        MultivaluedMap<String, String> queryParams, JobType 
jobType,
                        String nameNode) {
                HashMap<String, String> workflowConigs = new HashMap<String, 
String>();
@@ -466,7 +599,8 @@ public class OozieProxyImpersonator {
                        workflowConigs.put(OOZIE_WF_RERUN_FAILNODES_CONF_KEY, 
"true");
                }
                workflowConigs.put("user.name", viewContext.getUsername());
-               workflowConigs.put(oozieUtils.getJobPathPropertyKey(jobType), 
nameNode + filePath);
+               workflowConigs.put(oozieUtils.getJobPathPropertyKey(jobType), 
nameNode
+                               + filePath);
                return workflowConigs;
        }
 
@@ -497,10 +631,13 @@ public class OozieProxyImpersonator {
                uiURI = uiURI.substring(index);
                String serviceURI = getServiceUri();
                serviceURI += uiURI;
-               MultivaluedMap<String, String> params = 
addOrReplaceUserName(ui.getQueryParameters());
-               return serviceURI+utils.convertParamsToUrl(params);
+               MultivaluedMap<String, String> params = addOrReplaceUserName(ui
+                               .getQueryParameters());
+               return serviceURI + utils.convertParamsToUrl(params);
        }
-       private MultivaluedMap<String, String> 
addOrReplaceUserName(MultivaluedMap<String, String> parameters){
+
+       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);
@@ -521,7 +658,7 @@ public class OozieProxyImpersonator {
                        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;
@@ -539,8 +676,8 @@ public class OozieProxyImpersonator {
                                        
.entity(stringResponse).type(MediaType.TEXT_PLAIN).build();
                } else {
                        response = Response.status(Response.Status.OK)
-                                       
.entity(stringResponse).type(utils.deduceType(stringResponse))
-                                       .build();
+                                       .entity(stringResponse)
+                                       
.type(utils.deduceType(stringResponse)).build();
                }
                return response;
        }
@@ -558,36 +695,7 @@ public class OozieProxyImpersonator {
                }
                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;
+               return ambariIOUtil.readFromUrl(urlToRead, method, body, 
newHeaders);
        }
-
-       
-       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/9bc0b996/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
index 170132f..f002102 100644
--- 
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
@@ -17,6 +17,8 @@
  */
 package org.apache.oozie.ambari.view;
 
+import java.io.IOException;
+import java.io.StringReader;
 import java.util.Map;
 
 import javax.xml.parsers.DocumentBuilder;
@@ -27,6 +29,8 @@ 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;
 
 public class OozieUtils {
        private final static Logger LOGGER = LoggerFactory
@@ -68,4 +72,52 @@ public class OozieUtils {
                }
                throw new RuntimeException("Unknown Job Type");
        }
+       
+       public String generateWorkflowXml(String actionNodeXml) {
+               DocumentBuilderFactory dbf = 
DocumentBuilderFactory.newInstance();
+               DocumentBuilder db;
+               try {
+                       db = dbf.newDocumentBuilder();
+                       Document doc = db.newDocument();
+                       
+                       Element workflowElement = 
doc.createElement("workflow-app");
+                       workflowElement.setAttribute("name", "testWorkflow");
+                       workflowElement.setAttribute("xmlns", 
"uri:oozie:workflow:0.5");
+                       doc.appendChild(workflowElement);
+                       
+                       Element startElement = doc.createElement("start");
+                       startElement.setAttribute("to", "testAction");
+                       workflowElement.appendChild(startElement);
+                       
+                       Element actionElement = doc.createElement("action");
+                       actionElement.setAttribute("name", "testAction");
+                       Element actionSettingsElement = db.parse(new 
InputSource(new StringReader(actionNodeXml))).getDocumentElement();
+                       
actionElement.appendChild(doc.importNode(actionSettingsElement, true));
+                       workflowElement.appendChild(actionElement);
+                       
+                       Element actionOkTransitionElement = 
doc.createElement("ok");
+                       actionOkTransitionElement.setAttribute("to", "end");
+                       actionElement.appendChild(actionOkTransitionElement);
+                       
+                       Element actionErrorTransitionElement = 
doc.createElement("error");
+                       actionErrorTransitionElement.setAttribute("to", "kill");
+                       actionElement.appendChild(actionErrorTransitionElement);
+                       
+                       Element killElement = doc.createElement("kill");
+                       killElement.setAttribute("name", "kill");
+                       Element killMessageElement = 
doc.createElement("message");
+                       killMessageElement.setTextContent("Kill node message");
+                       killElement.appendChild(killMessageElement);
+                       workflowElement.appendChild(killElement);
+                       
+                       Element endElement = doc.createElement("end");
+                       endElement.setAttribute("name", "end");
+                       workflowElement.appendChild(endElement);
+                       
+                       return utils.generateXml(doc);
+               } catch (ParserConfigurationException | SAXException | 
IOException e) {
+                       LOGGER.error("error in generating workflow xml", e);
+                       throw new RuntimeException(e);
+               }
+       }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFileInfo.java
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFileInfo.java
 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFileInfo.java
new file mode 100644
index 0000000..6dbf30e
--- /dev/null
+++ 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFileInfo.java
@@ -0,0 +1,64 @@
+/**
+ * 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 class WorkflowFileInfo {
+       private String workflowPath;
+       private String draftPath;
+       private Boolean draftExists;
+       private Boolean isDraftCurrent=false;
+       public Boolean getIsDraftCurrent() {
+               return isDraftCurrent;
+       }
+       public void setIsDraftCurrent(Boolean isDraftCurrent) {
+               this.isDraftCurrent = isDraftCurrent;
+       }
+       private Long workflowModificationTime;
+       private Long draftModificationTime;
+       public String getWorkflowPath() {
+               return workflowPath;
+       }
+       public void setWorkflowPath(String workflowPath) {
+               this.workflowPath = workflowPath;
+       }
+       public String getDraftPath() {
+               return draftPath;
+       }
+       public void setDraftPath(String draftPath) {
+               this.draftPath = draftPath;
+       }
+       public Boolean getDraftExists() {
+               return draftExists;
+       }
+       public void setDraftExists(Boolean draftExists) {
+               this.draftExists = draftExists;
+       }
+       public void setWorkflowModificationTime(Long modificationTime) {
+               this.workflowModificationTime=modificationTime;
+       }
+       public void setDraftModificationTime(Long modificationTime) {
+               this.draftModificationTime=modificationTime;            
+       }
+       public Long getWorkflowModificationTime() {
+               return workflowModificationTime;
+       }
+       public Long getDraftModificationTime() {
+               return draftModificationTime;
+       }
+       
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFilesService.java
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFilesService.java
 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFilesService.java
new file mode 100644
index 0000000..01bde47
--- /dev/null
+++ 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFilesService.java
@@ -0,0 +1,116 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.oozie.ambari.view;
+
+import java.io.IOException;
+import java.io.InputStream;
+import org.apache.hadoop.fs.FileStatus;
+
+public class WorkflowFilesService {
+       private HDFSFileUtils hdfsFileUtils;
+
+       public WorkflowFilesService(HDFSFileUtils hdfsFileUtils) {
+               super();
+               this.hdfsFileUtils = hdfsFileUtils;
+       }
+
+       public String createWorkflowFile(String appPath, String content,
+                       boolean overwrite) throws IOException {
+               return hdfsFileUtils.writeToFile(getWorkflowFileName(appPath), 
content,
+                               overwrite);
+       }
+       
+       public String createAssetFile(String appPath, String content,
+                       boolean overwrite) throws IOException {
+               return hdfsFileUtils.writeToFile(appPath, content,
+                               overwrite);
+       }
+
+       public String saveDraft(String appPath, String content, boolean 
overwrite)
+                       throws IOException {
+               return 
hdfsFileUtils.writeToFile(getWorkflowDrafFileName(appPath),
+                               content, overwrite);
+       }
+
+       public InputStream readDraft(String appPath) throws IOException {
+               return hdfsFileUtils.read(getWorkflowDrafFileName(appPath));
+       }
+       public InputStream readWorkflowXml(String appPath) throws IOException {
+               return hdfsFileUtils.read(getWorkflowFileName(appPath));
+       }
+
+       private String getWorkflowDrafFileName(String appPath) {
+               return getWorkflowFileName(appPath).concat(".draft.json");
+       }
+
+       private String getWorkflowFileName(String appPath) {
+               String workflowFile = null;
+               if (appPath.endsWith(".xml")) {
+                       workflowFile = appPath;
+               } else {
+                       workflowFile = appPath + (appPath.endsWith("/") ? "" : 
"/")
+                                       + "workflow.xml";
+               }
+               return workflowFile;
+       }
+       
+       public String getAssetFileName(String appPath) {
+               String assetFile = null;
+               if (appPath.endsWith(".xml")) {
+                       assetFile = appPath;
+               } else {
+                       assetFile = appPath + (appPath.endsWith("/") ? "" : "/")
+                                       + "asset.xml";
+               }
+               return assetFile;
+       }
+
+       public void discardDraft(String workflowPath) throws IOException {
+               hdfsFileUtils.deleteFile(getWorkflowDrafFileName(workflowPath));
+
+       }
+
+       public WorkflowFileInfo getWorkflowDetails(String appPath) {
+               WorkflowFileInfo workflowInfo = new WorkflowFileInfo();
+               workflowInfo.setWorkflowPath(getWorkflowFileName(appPath));
+               boolean draftExists = hdfsFileUtils
+                               .fileExists(getWorkflowDrafFileName(appPath));
+               workflowInfo.setDraftExists(draftExists);
+               boolean workflowExists = 
hdfsFileUtils.fileExists(getWorkflowFileName(appPath));
+               FileStatus workflowFileStatus = null;
+               if (workflowExists){
+                       workflowFileStatus = hdfsFileUtils
+                                       
.getFileStatus(getWorkflowFileName(appPath));
+                       
workflowInfo.setWorkflowModificationTime(workflowFileStatus
+                                       .getModificationTime());
+               }
+               if (draftExists) {
+                       FileStatus draftFileStatus = hdfsFileUtils
+                                       
.getFileStatus(getWorkflowDrafFileName(appPath));
+                       workflowInfo.setDraftModificationTime(draftFileStatus
+                                       .getModificationTime());
+                       if (!workflowExists){
+                               workflowInfo.setIsDraftCurrent(true);
+                       }else{
+                               
workflowInfo.setIsDraftCurrent(draftFileStatus.getModificationTime()
+                                               - 
workflowFileStatus.getModificationTime() > 0);
+                       }
+               }
+               return workflowInfo;
+       }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/AssetRepo.java
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/AssetRepo.java
 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/AssetRepo.java
new file mode 100644
index 0000000..1390ec0
--- /dev/null
+++ 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/AssetRepo.java
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.oozie.ambari.view.assets;
+
+import java.util.Collection;
+
+import org.apache.ambari.view.DataStore;
+import org.apache.oozie.ambari.view.assets.model.ActionAsset;
+
+public class AssetRepo {
+    private final DataStore dataStore;
+
+    public AssetRepo(DataStore dataStore) {
+        super();
+        this.dataStore = dataStore;
+    }
+    public void saveAsset(ActionAsset asset){
+        
+    }
+    public void deleteAsset(ActionAsset asset){
+        
+    }
+    public  Collection<ActionAsset>listAllAssets(){
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/AssetService.java
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/AssetService.java
 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/AssetService.java
new file mode 100644
index 0000000..648a89f
--- /dev/null
+++ 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/AssetService.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.oozie.ambari.view.assets;
+
+import java.util.Collection;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.oozie.ambari.view.assets.model.ActionAsset;
+
+public class AssetService {
+    private AssetRepo assetRepo;
+
+    public AssetService(ViewContext viewContext) {
+        super();
+        assetRepo = new AssetRepo(viewContext.getDataStore());
+    }
+
+    public Collection<ActionAsset> getAssets() {
+
+        return null;
+    }
+
+    public Collection<ActionAsset> getPrioritizedAssets() {
+        Collection<ActionAsset> assets = getAssets();
+        // reorder
+        return assets;
+    }
+
+    public void addAsset() {
+
+    }
+
+    public void deleteAsset() {
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/model/ActionAsset.java
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/model/ActionAsset.java
 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/model/ActionAsset.java
new file mode 100644
index 0000000..8eb6081
--- /dev/null
+++ 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/model/ActionAsset.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.oozie.ambari.view.assets.model;
+
+import org.apache.oozie.ambari.view.model.BaseModel;
+
+public class ActionAsset extends BaseModel {
+    private String id;
+    private String name;
+    private String description;
+    private String assetLocation;
+    private String type;
+
+    public String getId() {
+        return id;
+    }
+    public void setId(String id) {
+        this.id = id;
+    }
+    public String getName() {
+        return name;
+    }
+    public void setName(String name) {
+        this.name = name;
+    }
+    public String getDescription() {
+        return description;
+    }
+    public void setDescription(String description) {
+        this.description = description;
+    }
+  
+    public String getType() {
+        return type;
+    }
+    public void setType(String type) {
+        this.type = type;
+    }
+    public String getAssetLocation() {
+        return assetLocation;
+    }
+    public void setAssetLocation(String assetLocation) {
+        this.assetLocation = assetLocation;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/model/BaseModel.java
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/model/BaseModel.java
 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/model/BaseModel.java
new file mode 100644
index 0000000..553ce24
--- /dev/null
+++ 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/model/BaseModel.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.oozie.ambari.view.model;
+
+import java.io.Serializable;
+
+
+public class BaseModel implements Serializable{
+    private static final long serialVersionUID = 1L;
+    private String createdAt;
+    private String updatedAt;
+    private String owner;
+    
+    public String getCreatedAt() {
+        return createdAt;
+    }
+    public void setCreatedAt(String createdAt) {
+        this.createdAt = createdAt;
+    }
+    public String getUpdatedAt() {
+        return updatedAt;
+    }
+    public void setUpdatedAt(String updatedAt) {
+        this.updatedAt = updatedAt;
+    }
+    public String getOwner() {
+        return owner;
+    }
+    public void setOwner(String owner) {
+        this.owner = owner;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowManagerService.java
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowManagerService.java
 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowManagerService.java
new file mode 100644
index 0000000..4c88454
--- /dev/null
+++ 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowManagerService.java
@@ -0,0 +1,76 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.oozie.ambari.view.workflowmanager;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Date;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.oozie.ambari.view.HDFSFileUtils;
+import org.apache.oozie.ambari.view.JobType;
+import org.apache.oozie.ambari.view.workflowmanager.model.Workflow;
+
+public class WorkflowManagerService {
+
+    private WorkflowsRepo workflowsRepository;
+    private HDFSFileUtils hdfsFileUtils;
+
+    public WorkflowManagerService(ViewContext viewContext) {
+        workflowsRepository = new WorkflowsRepo(viewContext.getDataStore());
+        hdfsFileUtils = new HDFSFileUtils(viewContext);
+    }
+
+    public void saveWorkflow(String path, JobType jobType, String descripton,
+            String userName) {
+        // workflowsRepository.getWorkflow(path);
+        Workflow workflowByPath = getWorkflowByPath(path);
+        if (workflowByPath == null) {
+            Workflow wf = new Workflow();
+            wf.setOwner(userName);
+            wf.setType(jobType.name());
+            wf.setWorkflowDefinitionPath(path);
+            Date now = new Date();
+            wf.setUpdatedAt(String.valueOf(now.getTime()));
+            workflowsRepository.updateWorkflow(wf);
+        } else {
+            Date now = new Date();
+            workflowByPath.setUpdatedAt(String.valueOf(now.getTime()));
+            workflowsRepository.updateWorkflow(workflowByPath);
+        }
+    }
+
+    public Collection<Workflow> getAllWorkflows() {
+        return workflowsRepository.getAllWorkflows();
+    }
+
+    public Workflow getWorkflowByPath(String path) {
+        return workflowsRepository.getWorkflow(path);
+    }
+
+    public void deleteWorkflow(String path, Boolean deleteDefinition) {
+        if (deleteDefinition) {
+            try {
+                hdfsFileUtils.deleteFile(path);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        workflowsRepository.deleteWorkflow(path);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsManagerResource.java
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsManagerResource.java
 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsManagerResource.java
new file mode 100644
index 0000000..17a3296
--- /dev/null
+++ 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsManagerResource.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.oozie.ambari.view.workflowmanager;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.QueryParam;
+
+import org.apache.ambari.view.ViewContext;
+
+public class WorkflowsManagerResource {
+       private WorkflowManagerService workflowManagerService;
+       
+       public WorkflowsManagerResource(ViewContext viewContext) {
+               super();
+               this.workflowManagerService=new 
WorkflowManagerService(viewContext);
+       }
+
+       @GET
+       public Map<String,Object> getWorkflows(){
+           HashMap<String,Object> result=new HashMap<>();
+           result.put("wfprojects", workflowManagerService.getAllWorkflows());
+           return result;
+       }
+       
+       
+       @DELETE
+       public void deleteWorkflow( @QueryParam("worfkflowPath") String path,
+            @DefaultValue("false") @QueryParam("deleteDefinition") Boolean 
deleteDefinition){
+           workflowManagerService.deleteWorkflow(path,deleteDefinition);
+       }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsRepo.java
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsRepo.java
 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsRepo.java
new file mode 100644
index 0000000..978c059
--- /dev/null
+++ 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsRepo.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.oozie.ambari.view.workflowmanager;
+
+import java.util.Collection;
+
+import org.apache.ambari.view.DataStore;
+import org.apache.ambari.view.PersistenceException;
+import org.apache.oozie.ambari.view.workflowmanager.model.Workflow;
+
+public class WorkflowsRepo {
+    private final DataStore dataStore;
+
+    public WorkflowsRepo(DataStore dataStore) {
+        super();
+        this.dataStore=dataStore;
+    }
+    public Collection<Workflow> getAllWorkflows(){
+        try {
+            return dataStore.findAll(Workflow.class,null);
+        } catch (PersistenceException e) {
+           throw new RuntimeException(e);
+        }
+    }
+    public void deleteWorkflow(String workflowPath){
+        try {
+            Workflow workflow = this.getWorkflow(workflowPath);
+            this.dataStore.remove(workflow);
+        } catch (PersistenceException e) {
+           throw new RuntimeException(e);
+        }
+    }
+    public void createWorkflow(Workflow wf){
+        try {
+            this.dataStore.store(wf);
+        } catch (PersistenceException e) {
+           throw new RuntimeException(e);
+        }
+    }
+    public void updateWorkflow(Workflow wf){
+        try {
+            this.dataStore.store(wf);
+        } catch (PersistenceException e) {
+           throw new RuntimeException(e);
+        }
+    }
+    public Workflow getWorkflow(String path) {
+        try {
+            return this.dataStore.find(Workflow.class, 
"workflowDefinitionPath='"+path+"'");
+        } catch (PersistenceException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/model/Workflow.java
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/model/Workflow.java
 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/model/Workflow.java
new file mode 100644
index 0000000..ad5f48b
--- /dev/null
+++ 
b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/model/Workflow.java
@@ -0,0 +1,88 @@
+/**
+ * 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.workflowmanager.model;
+
+import org.apache.oozie.ambari.view.model.BaseModel;
+
+public class Workflow extends BaseModel{
+    private static final long serialVersionUID = 1L;
+    private String id = null;
+    private String name;
+    private String desciption;
+    private String workflowDefinitionPath;
+    private String type;
+    private String isDraft;
+    private String definitionMissing;//true or not if path is fine. 
+    
+    public String getType() {
+        return type;
+    }
+    
+    public void setType(String type) {
+        this.type = type;
+    }
+    
+    public String getId() {
+        return id;
+    }
+    
+    public void setId(String id) {
+        this.id = id;
+    }
+    
+    public String getName() {
+        return name;
+    }
+    
+    public void setName(String name) {
+        this.name = name;
+    }
+    
+    public String getWorkflowDefinitionPath() {
+        return workflowDefinitionPath;
+    }
+    
+    public void setWorkflowDefinitionPath(String workflowDefinitionPath) {
+        this.workflowDefinitionPath = workflowDefinitionPath;
+    }
+   
+    public String getIsDraft() {
+        return isDraft;
+    }
+   
+    public void setIsDraft(String isDraft) {
+        this.isDraft = isDraft;
+    }
+    
+    public String getDesciption() {
+        return desciption;
+    }
+    
+    public void setDesciption(String desciption) {
+        this.desciption = desciption;
+    }
+   
+    public String getDefinitionMissing() {
+        return definitionMissing;
+    }
+
+    public void setDefinitionMissing(String definitionMissing) {
+        this.definitionMissing = definitionMissing;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/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
index 2799db5..4f409a1 100644
--- 
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
@@ -20,6 +20,7 @@ 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';
+import SchemaVersions from '../domain/schema-versions';
 
 const Validations = buildValidations({
   'bundle.name': validator('presence', {
@@ -41,6 +42,8 @@ const Validations = buildValidations({
 
 export default Ember.Component.extend(Ember.Evented, Validations, {
   bundle : null,
+  errors: Ember.A([]),
+  schemaVersions : SchemaVersions.create({}),
   propertyExtractor : Ember.inject.service('property-extractor'),
   fileBrowser : Ember.inject.service('file-browser'),
   workspaceManager : Ember.inject.service('workspace-manager'),
@@ -107,7 +110,8 @@ export default Ember.Component.extend(Ember.Evented, 
Validations, {
         displayValue : '',
         type : 'date'
       },
-      coordinators : null
+      coordinators : null,
+      schemaVersions : this.get("schemaVersions")
     });
   },
   importSampleBundle (){
@@ -156,9 +160,11 @@ export default Ember.Component.extend(Ember.Evented, 
Validations, {
     return deferred;
   },
   getBundleFromXml(bundleXml){
-    var bundleXmlImporter = BundleXmlImporter.create({});
-    var bundle = bundleXmlImporter.importBundle(bundleXml);
-    this.set("bundle", bundle);
+    var bundleXmlImporter = BundleXmlImporter.create({schemaVersions: 
this.get("schemaVersions")});
+    var bundleObj = bundleXmlImporter.importBundle(bundleXml, 
this.get("errors"));
+    this.set("bundle", bundleObj.bundle);
+    this.get("errors").clear();
+    this.get("errors").pushObjects(bundleObj.errors);
   },
   actions : {
     closeFileBrowser(){
@@ -220,6 +226,7 @@ export default Ember.Component.extend(Ember.Evented, 
Validations, {
     },
     resetBundle(){
       this.set('bundle', this.createBundle());
+      this.set('errors').clear();
     },
     closeBundleSubmitConfig(){
       this.set("showingJobConfig", false);
@@ -257,6 +264,9 @@ export default Ember.Component.extend(Ember.Evented, 
Validations, {
     },
     openTab(type, path){
       this.sendAction('openTab', type, path);
+    },
+    showVersionSettings(value){
+      this.set('showVersionSettings', value);
     }
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/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
index 229b2cc..2280f82 100644
--- 
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
@@ -99,7 +99,7 @@ export default Ember.Component.extend(Validations, {
       deferred.promise.then(function(data){
         var x2js = new X2JS();
         var coordJson = x2js.xml_str2json(data);
-        this.set('coordinatorName', coordJson["coordinator-app"]._name);
+        this.set('coordinator.name', coordJson["coordinator-app"]._name);
       }.bind(this)).catch(function(){
         this.set('coordinatorName', null);
       }.bind(this));

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-version-settings.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-version-settings.js
 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-version-settings.js
new file mode 100644
index 0000000..3bd6653
--- /dev/null
+++ 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-version-settings.js
@@ -0,0 +1,49 @@
+/*
+*    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 Constants from '../utils/constants';
+
+export default Ember.Component.extend({
+  initialize : function(){
+    this.set('currentBundleVersion', 
this.get('schemaVersions').getCurrentBundleVersion());
+    this.set('bundleSchemaVersions', 
this.get('schemaVersions').getBundleVersions());
+    this.get('schemaVersions').createCopy();
+  }.on('init'),
+  BundleVersionObserver : Ember.observer('currentBundleVersion',function(){
+    
this.get('schemaVersions').setCurrentBundleVersion(this.get('currentBundleVersion'));
+  }),
+  rendered : function(){
+    this.$('#version-settings-dialog').modal({
+      backdrop: 'static',
+      keyboard: false
+    });
+    this.$('#version-settings-dialog').modal('show');
+    this.$('#version-settings-dialog').modal().on('hidden.bs.modal', 
function() {
+      this.sendAction('showVersionSettings', false);
+    }.bind(this));
+  }.on('didInsertElement'),
+  actions : {
+    save (){
+      this.$('#version-settings-dialog').modal('hide');
+    },
+    cancel (){
+      this.get('schemaVersions').rollBack();
+      this.$('#version-settings-dialog').modal('hide');
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js
index 57fcdf8..23d1955 100644
--- 
a/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js
+++ 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js
@@ -19,6 +19,7 @@ import {Coordinator} from '../domain/coordinator/coordinator';
 import {CoordinatorGenerator} from 
'../domain/coordinator/coordinator-xml-generator';
 import {CoordinatorXmlImporter} from 
'../domain/coordinator/coordinator-xml-importer';
 import {SlaInfo} from '../domain/sla-info';
+import SchemaVersions from '../domain/schema-versions';
 import Constants from '../utils/constants';
 import { validator, buildValidations } from 'ember-cp-validations';
 
@@ -42,6 +43,8 @@ const Validations = buildValidations({
 
 export default Ember.Component.extend(Validations, Ember.Evented, {
   coordinator : null,
+  errors: Ember.A([]),
+  schemaVersions : SchemaVersions.create({}),
   childComponents : new Map(),
   fileBrowser : Ember.inject.service('file-browser'),
   propertyExtractor : Ember.inject.service('property-extractor'),
@@ -204,18 +207,20 @@ export default Ember.Component.extend(Validations, 
Ember.Evented, {
         }
       },
       controls : Ember.A([]),
-      slainfo : SlaInfo.create({})
+      slainfo : SlaInfo.create({}),
+      schemaVersions : this.get("schemaVersions")
     });
   },
   importSampleCoordinator (){
+    var self = this;
     var deferred = Ember.RSVP.defer();
     Ember.$.ajax({
       url: "/sampledata/coordinator.xml",
       dataType: "text",
       cache:false,
       success: function(data) {
-        var coordinatorXmlImporter = CoordinatorXmlImporter.create({});
-        var coordinator = coordinatorXmlImporter.importCoordinator(data);
+        var coordinatorXmlImporter = 
CoordinatorXmlImporter.create({schemaVersions: self.schemaVersions});
+        var coordinator = coordinatorXmlImporter.importCoordinator(data, 
self.errors);
         deferred.resolve(coordinator);
       }.bind(this),
       failure : function(data){
@@ -270,9 +275,12 @@ export default Ember.Component.extend(Validations, 
Ember.Evented, {
     return deferred;
   },
   getCoordinatorFromXml(coordinatorXml){
-    var coordinatorXmlImporter = CoordinatorXmlImporter.create({});
-    var coordinator = coordinatorXmlImporter.importCoordinator(coordinatorXml);
+    var coordinatorXmlImporter = 
CoordinatorXmlImporter.create({schemaVersions: this.get("schemaVersions")});
+    var coordinatorObj = 
coordinatorXmlImporter.importCoordinator(coordinatorXml, this.errors);
+    var coordinator = coordinatorObj.coordinator;
     this.set("coordinator", coordinator);
+    this.get("errors").clear();
+    this.get("errors").pushObjects(coordinatorObj.errors);
     this.$('input[name="dataInputType"][value="'+ 
coordinator.get('dataInputType')+'"]').prop('checked', true);
     if(coordinator.get('dataInputType') === 'logical'){
       this.set('conditionalDataInExists', true);
@@ -450,13 +458,16 @@ export default Ember.Component.extend(Validations, 
Ember.Evented, {
     },
     resetCoordinator(){
       this.set('coordinator', this.createNewCoordinator());
+      this.get("errors").clear();
     },
     importCoordinatorTest(){
       var deferred = this.importSampleCoordinator();
       deferred.promise.then(function(data){
-        this.set("coordinator", data);
-        this.$('input[name="dataInputType"][value="'+ 
data.get('dataInputType')+'"]').prop('checked', true);
-        if(data.get('dataInputType') === 'logical'){
+        this.set("coordinator", data.coordinator);
+        this.get("errors").clear();
+        this.get("errors").pushObjects(data.errors);
+        this.$('input[name="dataInputType"][value="'+ 
data.coordinator.get('dataInputType')+'"]').prop('checked', true);
+        if(data.coordinator.get('dataInputType') === 'logical'){
           this.set('conditionalDataInExists', true);
         }
         console.error(this.get('coordinator'));
@@ -516,6 +527,9 @@ export default Ember.Component.extend(Validations, 
Ember.Evented, {
       }.bind(this)).catch(function(){
         this.set('workflowName', null);
       }.bind(this));
+    },
+    showVersionSettings(value){
+      this.set('showVersionSettings', value);
     }
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-version-settings.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-version-settings.js
 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-version-settings.js
new file mode 100644
index 0000000..6385a44
--- /dev/null
+++ 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-version-settings.js
@@ -0,0 +1,49 @@
+/*
+*    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 Constants from '../utils/constants';
+
+export default Ember.Component.extend({
+  initialize : function(){
+    this.set('currentCoordinatorVersion', 
this.get('schemaVersions').getCurrentCoordinatorVersion());
+    this.set('coordinatorSchemaVersions', 
this.get('schemaVersions').getCoordinatorVersions());
+    this.get('schemaVersions').createCopy();
+  }.on('init'),
+  CoordinatorVersionObserver : 
Ember.observer('currentCoordinatorVersion',function(){
+    
this.get('schemaVersions').setCurrentCoordinatorVersion(this.get('currentCoordinatorVersion'));
+  }),
+  rendered : function(){
+    this.$('#version-settings-dialog').modal({
+      backdrop: 'static',
+      keyboard: false
+    });
+    this.$('#version-settings-dialog').modal('show');
+    this.$('#version-settings-dialog').modal().on('hidden.bs.modal', 
function() {
+      this.sendAction('showVersionSettings', false);
+    }.bind(this));
+  }.on('didInsertElement'),
+  actions : {
+    save (){
+      this.$('#version-settings-dialog').modal('hide');
+    },
+    cancel (){
+      this.get('schemaVersions').rollBack();
+      this.$('#version-settings-dialog').modal('hide');
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/src/main/resources/ui/app/components/date-with-expr.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/resources/ui/app/components/date-with-expr.js
 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/date-with-expr.js
index dd9a9ae..541104d 100644
--- 
a/contrib/views/wfmanager/src/main/resources/ui/app/components/date-with-expr.js
+++ 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/date-with-expr.js
@@ -55,7 +55,6 @@ export default Ember.Component.extend(Validations, {
         useCurrent: false,
         showClose : true
       });
-      this.set('dateField.displayValue', undefined);
     }else{
       var dateTimePicker = 
this.$('input[name="'+this.get('inputName')+'"]').data("DateTimePicker");
       if(dateTimePicker){

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bc0b996/contrib/views/wfmanager/src/main/resources/ui/app/components/designer-workspace.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/resources/ui/app/components/designer-workspace.js
 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/designer-workspace.js
index a3d64b0..6cbc3dd 100644
--- 
a/contrib/views/wfmanager/src/main/resources/ui/app/components/designer-workspace.js
+++ 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/designer-workspace.js
@@ -15,7 +15,7 @@
 *    limitations under the License.
 */
 import Ember from 'ember';
-
+import CommonUtils from "../utils/common-utils";
 export default Ember.Component.extend({
   workspaceManager : Ember.inject.service('workspace-manager'),
   xmlAppPath : null,
@@ -42,10 +42,22 @@ export default Ember.Component.extend({
     this.get('tabs').forEach((tab)=>{
       this.get('tabCounter').set(tab.type, 
(this.get('tabCounter').get(tab.type)) + 1);
     }, this);
+
+    Ember.getOwner(this).lookup('route:design').on('openNewTab', 
function(path){
+      this.createNewTab('wf', path);
+    }.bind(this));
+
   }.on('init'),
   elementsInserted : function(){
     this.$('.nav-tabs a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
-      
this.get('workspaceManager').setLastActiveTab((this.$(e.target).attr('href').slice(1)));
+      var id = this.$(e.target).attr('href').slice(1);
+      this.get('workspaceManager').setLastActiveTab(id);
+      var tab = this.get('tabs').findBy('id', id);
+      if(tab.type === 'dashboard'){
+        this.sendAction('showDashboard');
+      }else{
+        this.sendAction('hideDashboard');
+      }
     }.bind(this));
 
     if(this.get('tabs') && this.get('tabs').length > 0){
@@ -54,19 +66,13 @@ export default Ember.Component.extend({
       if(!activeTab){
         activeTab = this.get('tabs').objectAt(this.get('tabs').length - 1);
       }
-      this.$('.nav-tabs a[href="#' + activeTab.id + '"]').tab('show');
-    }else{
-      if(this.get('hasMultitabSupport')){
-        this.createNewTab(this.get('type'), this.get('xmlAppPath'));
+      if(activeTab.type === 'dashboard'){
+        this.createOrshowDashboard();
       }else{
-         var tab = this.get('tabs').findBy('type', this.get('type'));
-        if(!tab){
-          this.createNewTab(this.get('type'), this.get('xmlAppPath'));
-        }else{
-          Ember.set(tab,'path', this.get('xmlAppPath'));
-          this.$('.nav-tabs a[href="#' + tab.id + '"]').tab('show');
-        }
+        this.$('.nav-tabs a[href="#' + activeTab.id + '"]').tab('show');
       }
+    }else{
+      this.createOrshowDashboard();
     }
   }.on('didInsertElement'),
   onDestroy : function(){
@@ -100,6 +106,23 @@ export default Ember.Component.extend({
     this.get('tabCounter').set(type, ++count);
     return count;
   },
+  createOrshowDashboard(){
+    var dashboardTab = this.get('tabs').findBy('type', 'dashboard');
+    if(dashboardTab && dashboardTab.type === 'dashboard'){
+      this.$('.nav-tabs a[href="#' + dashboardTab.id + '"]').tab('show');
+    }else{
+      var tab = {
+        type : 'dashboard',
+        id : this.generateTabId(),
+        name : 'Dashboard'
+      };
+      this.$('.nav-tabs li').removeClass('active');
+      this.$('.tab-content .tab-pane').removeClass('active');
+      this.get('tabs').pushObject(tab);
+      this.$('.nav-tabs a[href="#' + tab.id + '"]').tab('show');
+    }
+    this.sendAction('showDashboard');
+  },
   generateTabId(){
     return 'tab-'+ Math.ceil(Math.random() * 100000);
   },
@@ -109,6 +132,7 @@ export default Ember.Component.extend({
       Ember.set(tab, 'context', context);
     },
     show(type){
+      this.sendAction('hideDashboard');
       if(this.get('hasMultitabSupport')){
         this.createNewTab(type);
       }else{
@@ -120,6 +144,9 @@ export default Ember.Component.extend({
         }
       }
     },
+    showDashboard(){
+      this.createOrshowDashboard();
+    },
     closeTab(index){
       if(index < this.get('tabs').length - 1){
         var previousTab = this.get('tabs').objectAt(index + 1);
@@ -127,6 +154,13 @@ export default Ember.Component.extend({
       }
       
this.get('workspaceManager').deleteWorkInProgress(this.get('tabs').objectAt(index).id);
       this.get('tabs').removeAt(index);
+      Ember.run.later(()=>{
+        var type = this.$('.nav-tabs').find('.active').attr('data-type');
+        console.error(type);
+        if(type === 'dashboard'){
+          this.createOrshowDashboard();
+        }
+      }.bind(this));
     },
     openTab(type, path){
       if(this.get('hasMultitabSupport')){
@@ -151,7 +185,10 @@ export default Ember.Component.extend({
     },
     interceptShow(tab){
       if(tab.type === 'wf' && tab.context){
+        CommonUtils.setTestContext(tab.context);
         tab.context.resize();
+      }else if(tab.type === 'dashboard'){
+        this.sendAction('showDashboard');
       }
     }
   }

Reply via email to