You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by db...@apache.org on 2016/04/13 14:22:46 UTC

[2/2] ambari git commit: AMBARI-15829. Files View: Extract the directory viewer UI component so that other views can use it. (dipayanb)

AMBARI-15829. Files View: Extract the directory viewer UI component so that other views can use it. (dipayanb)


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

Branch: refs/heads/trunk
Commit: 281307fceb533c1a557d9972991263546288bb41
Parents: 33ef653
Author: Dipayan Bhowmick <di...@gmail.com>
Authored: Wed Apr 13 17:52:01 2016 +0530
Committer: Dipayan Bhowmick <di...@gmail.com>
Committed: Wed Apr 13 17:52:01 2016 +0530

----------------------------------------------------------------------
 contrib/views/commons/README.md                 |  84 ++++
 contrib/views/commons/pom.xml                   | 140 ++++++
 .../MisconfigurationFormattedException.java     |  43 ++
 .../exceptions/NotFoundFormattedException.java  |  27 ++
 .../exceptions/ServiceFormattedException.java   |  57 +++
 .../view/commons/hdfs/FileOperationService.java | 479 ++++++++++++++++++
 .../ambari/view/commons/hdfs/HdfsService.java   | 160 ++++++
 .../ambari/view/commons/hdfs/UploadService.java | 138 ++++++
 .../ambari/view/commons/hdfs/UserService.java   | 106 ++++
 .../resources/ui/hdfs-directory-viewer/.bowerrc |   4 +
 .../ui/hdfs-directory-viewer/.editorconfig      |  34 ++
 .../ui/hdfs-directory-viewer/.ember-cli         |  27 ++
 .../ui/hdfs-directory-viewer/.gitignore         |  17 +
 .../ui/hdfs-directory-viewer/.jshintrc          |  32 ++
 .../ui/hdfs-directory-viewer/.npmignore         |  30 ++
 .../ui/hdfs-directory-viewer/.travis.yml        |  50 ++
 .../ui/hdfs-directory-viewer/.watchmanconfig    |  21 +
 .../ui/hdfs-directory-viewer/LICENSE.md         |  28 ++
 .../ui/hdfs-directory-viewer/README.md          |  97 ++++
 .../ui/hdfs-directory-viewer/addon/.gitkeep     |   0
 .../addon/components/directory-viewer.js        | 196 ++++++++
 .../templates/components/directory-viewer.hbs   |  18 +
 .../addon/utils/viewer-config.js                |  59 +++
 .../ui/hdfs-directory-viewer/app/.gitkeep       |   0
 .../app/components/directory-viewer.js          |  19 +
 .../app/utils/viewer-config.js                  |  19 +
 .../ui/hdfs-directory-viewer/bower.json         |  19 +
 .../hdfs-directory-viewer/config/ember-try.js   |  54 +++
 .../hdfs-directory-viewer/config/environment.js |  24 +
 .../ui/hdfs-directory-viewer/ember-cli-build.js |  36 ++
 .../resources/ui/hdfs-directory-viewer/index.js |  32 ++
 .../ui/hdfs-directory-viewer/package.json       |  51 ++
 .../ui/hdfs-directory-viewer/testem.json        |  12 +
 .../ui/hdfs-directory-viewer/tests/.jshintrc    |  52 ++
 .../tests/dummy/app/app.js                      |  36 ++
 .../tests/dummy/app/components/.gitkeep         |   0
 .../tests/dummy/app/controllers/.gitkeep        |   0
 .../tests/dummy/app/controllers/application.js  |  32 ++
 .../tests/dummy/app/helpers/.gitkeep            |   0
 .../tests/dummy/app/index.html                  |  43 ++
 .../tests/dummy/app/models/.gitkeep             |   0
 .../tests/dummy/app/router.js                   |  29 ++
 .../tests/dummy/app/routes/.gitkeep             |   0
 .../tests/dummy/app/styles/app.css              |  23 +
 .../tests/dummy/app/templates/application.hbs   |  36 ++
 .../dummy/app/templates/components/.gitkeep     |   0
 .../tests/dummy/app/utils/my-viewer-config.js   |  35 ++
 .../tests/dummy/config/environment.js           |  65 +++
 .../tests/dummy/public/crossdomain.xml          |  15 +
 .../tests/dummy/public/robots.txt               |   3 +
 .../tests/helpers/destroy-app.js                |  23 +
 .../tests/helpers/module-for-acceptance.js      |  41 ++
 .../tests/helpers/resolver.js                   |  29 ++
 .../tests/helpers/start-app.js                  |  36 ++
 .../ui/hdfs-directory-viewer/tests/index.html   |  52 ++
 .../tests/integration/.gitkeep                  |   0
 .../hdfs-directory-viewer/tests/test-helper.js  |  24 +
 .../hdfs-directory-viewer/tests/unit/.gitkeep   |   0
 .../ui/hdfs-directory-viewer/vendor/.gitkeep    |   0
 contrib/views/files/pom.xml                     |   5 +
 .../view/filebrowser/DownloadService.java       |   8 +-
 .../view/filebrowser/FileBrowserService.java    |  13 +-
 .../view/filebrowser/FileOperationService.java  | 484 -------------------
 .../view/filebrowser/FilePreviewService.java    |   7 +-
 .../ambari/view/filebrowser/HdfsService.java    | 160 ------
 .../ambari/view/filebrowser/HelpService.java    |  67 +--
 .../ambari/view/filebrowser/UploadService.java  | 137 ------
 .../MisconfigurationFormattedException.java     |  43 --
 .../utils/NotFoundFormattedException.java       |  27 --
 .../utils/ServiceFormattedException.java        |  57 ---
 .../resources/ui/app/services/file-operation.js |   4 +-
 .../files/src/main/resources/ui/package.json    |   5 +
 .../view/filebrowser/FilebrowserTest.java       |   1 +
 contrib/views/pom.xml                           |   1 +
 74 files changed, 2721 insertions(+), 985 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/README.md
----------------------------------------------------------------------
diff --git a/contrib/views/commons/README.md b/contrib/views/commons/README.md
new file mode 100644
index 0000000..b956fbd
--- /dev/null
+++ b/contrib/views/commons/README.md
@@ -0,0 +1,84 @@
+<!---
+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](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.
+-->
+
+#Ambari Views Commons Module
+
+Have this as a dependency in the view which need the functionality.
+
+This has common code for:
+
+* HDFS access
+
+**Note: More to be added later**
+
+### How to Include it in dependant project
+
+In the service class for the project use `commons` projects code in the way described in the below example for `files` view.
+
+```java
+package org.apache.ambari.view.filebrowser;
+
+import javax.ws.rs.Path;
+
+import org.apache.ambari.view.ViewContext;
+
+import com.google.inject.Inject;
+import org.apache.ambari.view.commons.hdfs.FileOperationService;
+import org.apache.ambari.view.commons.hdfs.UploadService;
+import org.apache.ambari.view.commons.hdfs.UserService;
+
+/**
+ * Root files service
+ */
+public class FileBrowserService {
+
+  @Inject
+  ViewContext context;
+
+  /**
+   * @see UploadService
+   * @return service
+   */
+  @Path("/upload")
+  public UploadService upload() {
+    return new UploadService(context);
+  }
+
+  /**
+   * @see org.apache.ambari.view.commons.hdfs.FileOperationService
+   * @return service
+   */
+  @Path("/fileops")
+  public FileOperationService fileOps() {
+    return new FileOperationService(context);
+  }
+
+  /**
+   * @see org.apache.ambari.view.commons.hdfs.UserService
+   * @return service
+   */
+  @Path("/user")
+  public UserService userService() { return new UserService(context); }
+
+}
+```
+
+
+####Also, look into the various ember addons that are included in `src/main/resources/ui`.
+Currently we have:
+
+* hdfs-directory-viewer
+
+**More to be added later**
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/pom.xml
----------------------------------------------------------------------
diff --git a/contrib/views/commons/pom.xml b/contrib/views/commons/pom.xml
new file mode 100644
index 0000000..5018d46
--- /dev/null
+++ b/contrib/views/commons/pom.xml
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>ambari-views-commons</artifactId>
+  <version>2.0.0.0-SNAPSHOT</version>
+  <name>Ambari View Commons</name>
+
+  <parent>
+    <artifactId>ambari-contrib-views</artifactId>
+    <groupId>org.apache.ambari.contrib.views</groupId>
+    <version>2.0.0.0-SNAPSHOT</version>
+  </parent>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.ambari.contrib.views</groupId>
+      <artifactId>ambari-views-utils</artifactId>
+      <version>2.0.0.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.ambari</groupId>
+      <artifactId>ambari-views</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-hdfs</artifactId>
+      <version>${hadoop.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>tomcat</groupId>
+          <artifactId>jasper-runtime</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-common</artifactId>
+      <version>${hadoop.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>tomcat</groupId>
+          <artifactId>jasper-runtime</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>com.google.inject</groupId>
+      <artifactId>guice</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.googlecode.json-simple</groupId>
+      <artifactId>json-simple</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.sun.jersey.contribs</groupId>
+      <artifactId>jersey-multipart</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.glassfish.jersey.containers</groupId>
+      <artifactId>jersey-container-servlet</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <version>2.4</version>
+    </dependency>
+
+    <!-- Testing -->
+    <dependency>
+      <groupId>com.sun.jersey.jersey-test-framework</groupId>
+      <artifactId>jersey-test-framework-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-minicluster</artifactId>
+      <version>${hadoop.version}</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymock</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <resources>
+      <resource>
+        <directory>src/main/resources/</directory>
+        <filtering>false</filtering>
+        <excludes>
+          <exclude>ui/**</exclude>
+        </excludes>
+      </resource>
+    </resources>
+  </build>
+
+  <properties>
+    <ambari.dir>${project.parent.parent.parent.basedir}</ambari.dir>
+  </properties>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/exceptions/MisconfigurationFormattedException.java
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/exceptions/MisconfigurationFormattedException.java b/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/exceptions/MisconfigurationFormattedException.java
new file mode 100644
index 0000000..b7ce938
--- /dev/null
+++ b/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/exceptions/MisconfigurationFormattedException.java
@@ -0,0 +1,43 @@
+/**
+ * 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.ambari.view.commons.exceptions;
+
+import org.json.simple.JSONObject;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.HashMap;
+
+public class MisconfigurationFormattedException extends WebApplicationException {
+  private final static int STATUS = 500;
+  private final static String message = "Parameter \"%s\" is set to null";
+
+  public MisconfigurationFormattedException(String name) {
+    super(errorEntity(name));
+  }
+
+  protected static Response errorEntity(String name) {
+    HashMap<String, Object> response = new HashMap<String, Object>();
+    response.put("message", String.format(message, name));
+    response.put("trace", null);
+    response.put("status", STATUS);
+    return Response.status(STATUS).entity(new JSONObject(response)).type(MediaType.APPLICATION_JSON).build();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/exceptions/NotFoundFormattedException.java
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/exceptions/NotFoundFormattedException.java b/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/exceptions/NotFoundFormattedException.java
new file mode 100644
index 0000000..a8c51f7
--- /dev/null
+++ b/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/exceptions/NotFoundFormattedException.java
@@ -0,0 +1,27 @@
+/**
+ * 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.ambari.view.commons.exceptions;
+
+public class NotFoundFormattedException extends ServiceFormattedException {
+  private final static int STATUS = 404;
+
+  public NotFoundFormattedException(String message, Throwable exception) {
+    super(message, exception, STATUS);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/exceptions/ServiceFormattedException.java
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/exceptions/ServiceFormattedException.java b/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/exceptions/ServiceFormattedException.java
new file mode 100644
index 0000000..bb77404
--- /dev/null
+++ b/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/exceptions/ServiceFormattedException.java
@@ -0,0 +1,57 @@
+/**
+ * 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.ambari.view.commons.exceptions;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.json.simple.JSONObject;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.security.AccessControlException;
+import java.util.HashMap;
+
+public class ServiceFormattedException extends WebApplicationException {
+  public ServiceFormattedException(String message, Throwable exception) {
+    super(errorEntity(message, exception, suggestStatus(exception)));
+  }
+
+  public ServiceFormattedException(String message, Throwable exception, int status) {
+    super(errorEntity(message, exception, status));
+  }
+
+  private static int suggestStatus(Throwable exception) {
+    int status = 500;
+    if (exception instanceof AccessControlException) {
+      status = 403;
+    }
+    return status;
+  }
+
+  protected static Response errorEntity(String message, Throwable e, int status) {
+    HashMap<String, Object> response = new HashMap<String, Object>();
+    response.put("message", message);
+    String trace = null;
+    if (e != null)
+      trace = ExceptionUtils.getStackTrace(e);
+    response.put("trace", trace);
+    response.put("status", status);
+    return Response.status(status).entity(new JSONObject(response)).type(MediaType.APPLICATION_JSON).build();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/hdfs/FileOperationService.java
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/hdfs/FileOperationService.java b/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/hdfs/FileOperationService.java
new file mode 100644
index 0000000..bc3d11d
--- /dev/null
+++ b/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/hdfs/FileOperationService.java
@@ -0,0 +1,479 @@
+/**
+ * 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.ambari.view.commons.hdfs;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.commons.exceptions.NotFoundFormattedException;
+import org.apache.ambari.view.commons.exceptions.ServiceFormattedException;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.ambari.view.utils.hdfs.HdfsApiException;
+import org.json.simple.JSONObject;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.*;
+import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * File operations service
+ */
+public class FileOperationService extends HdfsService {
+
+  /**
+   * Constructor
+   * @param context View Context instance
+   */
+  public FileOperationService(ViewContext context) {
+    super(context);
+  }
+
+  /**
+   * List dir
+   * @param path path
+   * @return response with dir content
+   */
+  @GET
+  @Path("/listdir")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response listdir(@QueryParam("path") String path) {
+    try {
+      JSONObject response = new JSONObject();
+      response.put("files", getApi(context).fileStatusToJSON(getApi(context).listdir(path)));
+      response.put("meta", getApi(context).fileStatusToJSON(getApi(context).getFileStatus(path)));
+      return Response.ok(response).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (FileNotFoundException ex) {
+      throw new NotFoundFormattedException(ex.getMessage(), ex);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Rename
+   * @param request rename request
+   * @return response with success
+   */
+  @POST
+  @Path("/rename")
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response rename(final SrcDstFileRequest request) {
+    try {
+      HdfsApi api = getApi(context);
+      ResponseBuilder result;
+      if (api.rename(request.src, request.dst)) {
+        result = Response.ok(getApi(context).fileStatusToJSON(api
+            .getFileStatus(request.dst)));
+      } else {
+        result = Response.ok(new FileOperationResult(false, "Can't move '" + request.src + "' to '" + request.dst + "'")).status(422);
+      }
+      return result.build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Chmod
+   * @param request chmod request
+   * @return response with success
+   */
+  @POST
+  @Path("/chmod")
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response chmod(final ChmodRequest request) {
+    try {
+      HdfsApi api = getApi(context);
+      ResponseBuilder result;
+      if (api.chmod(request.path, request.mode)) {
+        result = Response.ok(getApi(context).fileStatusToJSON(api
+            .getFileStatus(request.path)));
+      } else {
+        result = Response.ok(new FileOperationResult(false, "Can't chmod '" + request.path + "'")).status(422);
+      }
+      return result.build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Copy file
+   * @param request source and destination request
+   * @return response with success
+   */
+  @POST
+  @Path("/move")
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response move(final MultiSrcDstFileRequest request,
+                       @Context HttpHeaders headers, @Context UriInfo ui) {
+    try {
+      HdfsApi api = getApi(context);
+      ResponseBuilder result;
+      String message = "";
+
+      List<String> sources = request.sourcePaths;
+      String destination = request.destinationPath;
+      if(sources.isEmpty()) {
+        result = Response.ok(new FileOperationResult(false, "Can't move 0 file/folder to '" + destination + "'")).
+          status(422);
+        return result.build();
+      }
+
+      int index = 0;
+      for (String src : sources) {
+        String fileName = getFileName(src);
+        String finalDestination = getDestination(destination, fileName);
+        try {
+          if (api.rename(src, finalDestination)) {
+            index ++;
+          } else {
+            message = "Failed to move '" + src + "' to '" + finalDestination + "'";
+            break;
+          }
+        } catch (IOException exception) {
+          message = exception.getMessage();
+          logger.error("Failed to move '{}' to '{}'. Exception: {}", src, finalDestination,
+            exception.getMessage());
+          break;
+        }
+      }
+      if (index == sources.size()) {
+        result = Response.ok(new FileOperationResult(true)).status(200);
+      } else {
+        FileOperationResult errorResult = getFailureFileOperationResult(sources, index, message);
+        result = Response.ok(errorResult).status(422);
+      }
+      return result.build();
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Copy file
+   * @param request source and destination request
+   * @return response with success
+   */
+  @POST
+  @Path("/copy")
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response copy(final MultiSrcDstFileRequest request,
+                       @Context HttpHeaders headers, @Context UriInfo ui) {
+    try {
+      HdfsApi api = getApi(context);
+      ResponseBuilder result;
+      String message = "";
+
+      List<String> sources = request.sourcePaths;
+      String destination = request.destinationPath;
+      if(sources.isEmpty()) {
+        result = Response.ok(new FileOperationResult(false, "Can't copy 0 file/folder to '" + destination + "'")).
+          status(422);
+        return result.build();
+      }
+
+      int index = 0;
+      for (String src : sources) {
+        String fileName = getFileName(src);
+        String finalDestination = getDestination(destination, fileName);
+        try {
+          api.copy(src, finalDestination);
+          index ++;
+        } catch (IOException|HdfsApiException exception) {
+          message = exception.getMessage();
+          logger.error("Failed to copy '{}' to '{}'. Exception: {}", src, finalDestination,
+            exception.getMessage());
+          break;
+        }
+      }
+      if (index == sources.size()) {
+        result = Response.ok(new FileOperationResult(true)).status(200);
+      } else {
+        FileOperationResult errorResult = getFailureFileOperationResult(sources, index, message);
+        result = Response.ok(errorResult).status(422);
+      }
+      return result.build();
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Make directory
+   * @param request make directory request
+   * @return response with success
+   */
+  @PUT
+  @Path("/mkdir")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response mkdir(final MkdirRequest request) {
+    try{
+      HdfsApi api = getApi(context);
+      ResponseBuilder result;
+      if (api.mkdir(request.path)) {
+        result = Response.ok(getApi(context).fileStatusToJSON(api.getFileStatus(request.path)));
+      } else {
+        result = Response.ok(new FileOperationResult(false, "Can't create dir '" + request.path + "'")).status(422);
+      }
+      return result.build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Empty trash
+   * @return response with success
+   */
+  @DELETE
+  @Path("/trash/emptyTrash")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response emptyTrash() {
+    try {
+      HdfsApi api = getApi(context);
+      api.emptyTrash();
+      return Response.ok(new FileOperationResult(true)).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Move to trash
+   * @param request remove request
+   * @return response with success
+   */
+  @DELETE
+  @Path("/moveToTrash")
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response moveToTrash(MultiRemoveRequest request) {
+    try {
+      ResponseBuilder result;
+      HdfsApi api = getApi(context);
+      String trash = api.getTrashDirPath();
+      String message = "";
+
+      if (request.paths.size() == 0) {
+        result = Response.ok(new FileOperationResult(false, "No path entries provided.")).status(422);
+      } else {
+        if (!api.exists(trash)) {
+          if (!api.mkdir(trash)) {
+            result = Response.ok(new FileOperationResult(false, "Trash dir does not exists. Can't create dir for " +
+              "trash '" + trash + "'")).status(422);
+            return result.build();
+          }
+        }
+
+        int index = 0;
+        for (MultiRemoveRequest.PathEntry entry : request.paths) {
+          String trashFilePath = api.getTrashDirPath(entry.path);
+          try {
+            if (api.rename(entry.path, trashFilePath)) {
+              index ++;
+            } else {
+              message = "Failed to move '" + entry.path + "' to '" + trashFilePath + "'";
+              break;
+            }
+          } catch (IOException exception) {
+            message = exception.getMessage();
+            logger.error("Failed to move '{}' to '{}'. Exception: {}", entry.path, trashFilePath,
+              exception.getMessage());
+            break;
+          }
+        }
+        if (index == request.paths.size()) {
+          result = Response.ok(new FileOperationResult(true)).status(200);
+        } else {
+          FileOperationResult errorResult = getFailureFileOperationResult(getPathsFromPathsEntries(request.paths), index, message);
+          result = Response.ok(errorResult).status(422);
+        }
+      }
+      return result.build();
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Remove
+   * @param request remove request
+   * @return response with success
+   */
+  @DELETE
+  @Path("/remove")
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response remove(MultiRemoveRequest request, @Context HttpHeaders headers,
+                         @Context UriInfo ui) {
+    try {
+      HdfsApi api = getApi(context);
+      ResponseBuilder result;
+      String message = "";
+      if(request.paths.size() == 0) {
+        result = Response.ok(new FileOperationResult(false, "No path entries provided."));
+      } else {
+        int index = 0;
+        for (MultiRemoveRequest.PathEntry entry : request.paths) {
+          try {
+            if (api.delete(entry.path, entry.recursive)) {
+              index++;
+            } else {
+              message = "Failed to remove '" + entry.path + "'";
+              break;
+            }
+          } catch (IOException exception) {
+            message = exception.getMessage();
+            logger.error("Failed to remove '{}'. Exception: {}", entry.path, exception.getMessage());
+            break;
+          }
+
+        }
+        if (index == request.paths.size()) {
+          result = Response.ok(new FileOperationResult(true)).status(200);
+        } else {
+          FileOperationResult errorResult = getFailureFileOperationResult(getPathsFromPathsEntries(request.paths), index, message);
+          result = Response.ok(errorResult).status(422);
+        }
+      }
+      return result.build();
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  private List<String> getPathsFromPathsEntries(List<MultiRemoveRequest.PathEntry> paths) {
+    List<String> entries = new ArrayList<>();
+    for(MultiRemoveRequest.PathEntry path: paths) {
+      entries.add(path.path);
+    }
+    return entries;
+  }
+
+  private FileOperationResult getFailureFileOperationResult(List<String> paths, int failedIndex, String message) {
+    List<String> succeeded = new ArrayList<>();
+    List<String> unprocessed = new ArrayList<>();
+    List<String> failed = new ArrayList<>();
+    ListIterator<String> iter = paths.listIterator();
+    while (iter.hasNext()) {
+      int index = iter.nextIndex();
+      String path = iter.next();
+      if (index < failedIndex) {
+        succeeded.add(path);
+      } else if (index == failedIndex) {
+        failed.add(path);
+      } else {
+        unprocessed.add(path);
+      }
+    }
+    return new FileOperationResult(false, message, succeeded, failed, unprocessed);
+  }
+
+  private String getDestination(String baseDestination, String fileName) {
+    if(baseDestination.endsWith("/")) {
+      return baseDestination + fileName;
+    } else {
+      return baseDestination + "/" + fileName;
+    }
+  }
+
+  private String getFileName(String srcPath) {
+    return srcPath.substring(srcPath.lastIndexOf('/') + 1);
+  }
+
+
+  /**
+   * Wrapper for json mapping of mkdir request
+   */
+  @XmlRootElement
+  public static class MkdirRequest {
+    @XmlElement(nillable = false, required = true)
+    public String path;
+  }
+
+  /**
+   * Wrapper for json mapping of chmod request
+   */
+  @XmlRootElement
+  public static class ChmodRequest {
+    @XmlElement(nillable = false, required = true)
+    public String path;
+    @XmlElement(nillable = false, required = true)
+    public String mode;
+  }
+
+  /**
+   * Wrapper for json mapping of request with
+   * source and destination
+   */
+  @XmlRootElement
+  public static class SrcDstFileRequest {
+    @XmlElement(nillable = false, required = true)
+    public String src;
+    @XmlElement(nillable = false, required = true)
+    public String dst;
+  }
+
+  /**
+   * Wrapper for json mapping of request with multiple
+   * source and destination
+   */
+  @XmlRootElement
+  public static class MultiSrcDstFileRequest {
+    @XmlElement(nillable = false, required = true)
+    public List<String> sourcePaths = new ArrayList<>();
+    @XmlElement(nillable = false, required = true)
+    public String destinationPath;
+  }
+
+  /**
+   * Wrapper for json mapping of remove request
+   */
+  @XmlRootElement
+  public static class MultiRemoveRequest {
+    @XmlElement(nillable = false, required = true)
+    public List<PathEntry> paths = new ArrayList<>();
+    public static class PathEntry {
+      @XmlElement(nillable = false, required = true)
+      public String path;
+      public boolean recursive;
+    }
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/hdfs/HdfsService.java
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/hdfs/HdfsService.java b/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/hdfs/HdfsService.java
new file mode 100644
index 0000000..91eebcf
--- /dev/null
+++ b/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/hdfs/HdfsService.java
@@ -0,0 +1,160 @@
+/**
+ * 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.ambari.view.commons.hdfs;
+
+import javax.ws.rs.WebApplicationException;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.commons.exceptions.ServiceFormattedException;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.ambari.view.utils.hdfs.HdfsUtil;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Base Hdfs service
+ */
+public abstract class HdfsService {
+
+  protected static final Logger logger = LoggerFactory.getLogger(HdfsService.class);
+
+  protected final ViewContext context;
+
+  /**
+   * Constructor
+   * @param context View Context instance
+   */
+  public HdfsService(ViewContext context) {
+    this.context = context;
+  }
+
+  /**
+   * Wrapper for json mapping of result of Multi Remove Request
+   */
+  @XmlRootElement
+  public static class FileOperationResult {
+    public boolean success;
+    public String message;
+    public List<String> succeeded;
+    public List<String> failed;
+    public List<String> unprocessed;
+
+    public FileOperationResult(boolean success) {
+      this.success = success;
+    }
+
+    public FileOperationResult(boolean success, String message) {
+      this(success);
+      this.message = message;
+    }
+
+    public FileOperationResult(boolean success, String message, List<String> succeeded, List<String> failed, List<String> unprocessed) {
+      this(success, message);
+      this.succeeded = succeeded;
+      this.failed = failed;
+      this.unprocessed = unprocessed;
+    }
+
+  }
+
+  private HdfsApi _api = null;
+
+  /**
+   * Ger HdfsApi instance
+   * @param context View Context instance
+   * @return HdfsApi business delegate
+   */
+  public HdfsApi getApi(ViewContext context) {
+    if (_api == null) {
+      try {
+        _api = HdfsUtil.connectToHDFSApi(context);
+      } catch (Exception ex) {
+        throw new ServiceFormattedException("HdfsApi connection failed. Check \"webhdfs.url\" property", ex);
+      }
+    }
+    return _api;
+  }
+
+  private static Map<String, String> getHdfsAuthParams(ViewContext context) {
+    String auth = context.getProperties().get("webhdfs.auth");
+    Map<String, String> params = new HashMap<String, String>();
+    if (auth == null || auth.isEmpty()) {
+      auth = "auth=SIMPLE";
+    }
+    for(String param : auth.split(";")) {
+      String[] keyvalue = param.split("=");
+      if (keyvalue.length != 2) {
+        logger.error("Can not parse authentication param " + param + " in " + auth);
+        continue;
+      }
+      params.put(keyvalue[0], keyvalue[1]);
+    }
+    return params;
+  }
+
+  /**
+   * Get doAs username to use in HDFS
+   * @param context View Context instance
+   * @return user name
+   */
+  public String getDoAsUsername(ViewContext context) {
+    String username = context.getProperties().get("webhdfs.username");
+    if (username == null || username.isEmpty())
+      username = context.getUsername();
+    return username;
+  }
+
+  /**
+   * Checks connection to HDFS
+   * @param context View Context
+   */
+  public static void hdfsSmokeTest(ViewContext context) {
+    try {
+      HdfsApi api = HdfsUtil.connectToHDFSApi(context);
+      api.getStatus();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Get proxyuser username to use in HDFS
+   * @param context View Context instance
+   * @return user name
+   */
+  public String getRealUsername(ViewContext context) {
+    String username = context.getProperties().get("webhdfs.proxyuser");
+    if (username == null || username.isEmpty())
+      try {
+        username = UserGroupInformation.getCurrentUser().getShortUserName();
+      } catch (IOException e) {
+        throw new ServiceFormattedException("HdfsApi connection failed. Can't get current user", e);
+      }
+    return username;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/hdfs/UploadService.java
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/hdfs/UploadService.java b/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/hdfs/UploadService.java
new file mode 100644
index 0000000..97253ad
--- /dev/null
+++ b/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/hdfs/UploadService.java
@@ -0,0 +1,138 @@
+/**
+ * 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.ambari.view.commons.hdfs;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.commons.exceptions.ServiceFormattedException;
+import org.apache.ambari.view.commons.hdfs.HdfsService;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.hadoop.fs.FSDataOutputStream;
+
+import com.sun.jersey.core.header.FormDataContentDisposition;
+import com.sun.jersey.multipart.FormDataParam;
+
+/**
+ * Upload service
+ */
+public class UploadService extends HdfsService {
+
+  /**
+   * Constructor
+   * @param context View Context instance
+   */
+  public UploadService(ViewContext context) {
+    super(context);
+  }
+
+  private void uploadFile(final String filePath, InputStream uploadedInputStream)
+      throws IOException, InterruptedException {
+    int read;
+    byte[] chunk = new byte[1024];
+    FSDataOutputStream out = null;
+    try {
+      out = getApi(context).create(filePath, false);
+      while ((read = uploadedInputStream.read(chunk)) != -1) {
+        out.write(chunk, 0, read);
+      }
+    } finally {
+      if (out != null) {
+        out.close();
+      }
+    }
+  }
+
+  /**
+   * Upload file
+   * @param uploadedInputStream file input stream
+   * @param contentDisposition content disposition
+   * @param path path
+   * @return file status
+   */
+  @PUT
+  @Consumes(MediaType.MULTIPART_FORM_DATA)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response uploadFile(
+      @FormDataParam("file") InputStream uploadedInputStream,
+      @FormDataParam("file") FormDataContentDisposition contentDisposition,
+      @FormDataParam("path") String path) {
+    try {
+      if (!path.endsWith("/"))
+        path = path + "/";
+      String filePath = path + contentDisposition.getFileName();
+      uploadFile(filePath, uploadedInputStream);
+      return Response.ok(
+          getApi(context).fileStatusToJSON(getApi(context).getFileStatus(filePath)))
+          .build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Upload zip and unpack
+   * @param uploadedInputStream file input stream
+   * @param contentDisposition content disposition
+   * @param path path
+   * @return files statuses
+   * @throws IOException
+   * @throws Exception
+   */
+  @PUT
+  @Path("/zip")
+  @Consumes(MediaType.MULTIPART_FORM_DATA)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response uploadZip(
+      @FormDataParam("file") InputStream uploadedInputStream,
+      @FormDataParam("file") FormDataContentDisposition contentDisposition,
+      @FormDataParam("path") String path) {
+    try {
+      if (!path.endsWith("/"))
+        path = path + "/";
+      ZipInputStream zip = new ZipInputStream(uploadedInputStream);
+      ZipEntry ze = zip.getNextEntry();
+      HdfsApi api = getApi(context);
+      while (ze != null) {
+        String filePath = path + ze.getName();
+        if (ze.isDirectory()) {
+          api.mkdir(filePath);
+        } else {
+          uploadFile(filePath, zip);
+        }
+        ze = zip.getNextEntry();
+      }
+      return Response.ok(getApi(context).fileStatusToJSON(api.listdir(path))).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/hdfs/UserService.java
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/hdfs/UserService.java b/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/hdfs/UserService.java
new file mode 100644
index 0000000..dc303ce
--- /dev/null
+++ b/contrib/views/commons/src/main/java/org/apache/ambari/view/commons/hdfs/UserService.java
@@ -0,0 +1,106 @@
+/**
+ * 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.ambari.view.commons.hdfs;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.commons.exceptions.NotFoundFormattedException;
+import org.apache.ambari.view.commons.exceptions.ServiceFormattedException;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.FileNotFoundException;
+
+/**
+ * User related info service
+ */
+public class UserService extends HdfsService {
+
+  /**
+   * Constructor
+   * @param context View Context instance
+   */
+  public UserService(ViewContext context) {
+    super(context);
+  }
+
+  /**
+   * Returns home directory
+   * @return home directory
+   */
+  @GET
+  @Path("/home")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response homeDir() {
+    try {
+      HdfsApi api = getApi(context);
+      return Response
+        .ok(getApi(context).fileStatusToJSON(api.getFileStatus(api.getHomeDir()
+          .toString()))).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Is trash enabled
+   * @return is trash enabled
+   */
+  @GET
+  @Path("/trash/enabled")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response trashEnabled() {
+    try {
+      HdfsApi api = getApi(context);
+      return Response.ok(new FileOperationResult(api.trashEnabled())).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Trash dir
+   * @return trash dir
+   */
+  @GET
+  @Path("/trashDir")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response trashdir() {
+    try {
+      HdfsApi api = getApi(context);
+      return Response.ok(
+        getApi(context).fileStatusToJSON(api.getFileStatus(api.getTrashDir()
+          .toString()))).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (FileNotFoundException ex) {
+      throw new NotFoundFormattedException(ex.getMessage(), ex);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.bowerrc
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.bowerrc b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.bowerrc
new file mode 100644
index 0000000..959e169
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.bowerrc
@@ -0,0 +1,4 @@
+{
+  "directory": "bower_components",
+  "analytics": false
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.editorconfig
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.editorconfig b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.editorconfig
new file mode 100644
index 0000000..47c5438
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.editorconfig
@@ -0,0 +1,34 @@
+# EditorConfig helps developers define and maintain consistent
+# coding styles between different editors and IDEs
+# editorconfig.org
+
+root = true
+
+
+[*]
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+indent_style = space
+indent_size = 2
+
+[*.js]
+indent_style = space
+indent_size = 2
+
+[*.hbs]
+insert_final_newline = false
+indent_style = space
+indent_size = 2
+
+[*.css]
+indent_style = space
+indent_size = 2
+
+[*.html]
+indent_style = space
+indent_size = 2
+
+[*.{diff,md}]
+trim_trailing_whitespace = false

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.ember-cli
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.ember-cli b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.ember-cli
new file mode 100644
index 0000000..5a339b9
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.ember-cli
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+{
+  /**
+    Ember CLI sends analytics information by default. The data is completely
+    anonymous, but there are times when you might want to disable this behavior.
+
+    Setting `disableAnalytics` to true will prevent any data from being sent.
+  */
+  "disableAnalytics": false
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.gitignore
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.gitignore b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.gitignore
new file mode 100644
index 0000000..86fceae
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.gitignore
@@ -0,0 +1,17 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+
+# compiled output
+/dist
+/tmp
+
+# dependencies
+/node_modules
+/bower_components
+
+# misc
+/.sass-cache
+/connect.lock
+/coverage/*
+/libpeerconnection.log
+npm-debug.log
+testem.log

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.jshintrc
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.jshintrc b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.jshintrc
new file mode 100644
index 0000000..08096ef
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.jshintrc
@@ -0,0 +1,32 @@
+{
+  "predef": [
+    "document",
+    "window",
+    "-Promise"
+  ],
+  "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/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.npmignore
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.npmignore b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.npmignore
new file mode 100644
index 0000000..fea9ccc
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.npmignore
@@ -0,0 +1,30 @@
+# 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.
+
+bower_components/
+tests/
+tmp/
+dist/
+
+.bowerrc
+.editorconfig
+.ember-cli
+.travis.yml
+.npmignore
+**/.gitkeep
+bower.json
+Brocfile.js
+testem.json

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.travis.yml
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.travis.yml b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.travis.yml
new file mode 100644
index 0000000..dbc0990
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.travis.yml
@@ -0,0 +1,50 @@
+# 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.
+
+---
+language: node_js
+node_js:
+  - "0.12"
+
+sudo: false
+
+cache:
+  directories:
+    - node_modules
+
+env:
+  - EMBER_TRY_SCENARIO=default
+  - EMBER_TRY_SCENARIO=ember-release
+  - EMBER_TRY_SCENARIO=ember-beta
+  - EMBER_TRY_SCENARIO=ember-canary
+
+matrix:
+  fast_finish: true
+  allow_failures:
+    - env: EMBER_TRY_SCENARIO=ember-canary
+
+before_install:
+  - export PATH=/usr/local/phantomjs-2.0.0/bin:$PATH
+  - "npm config set spin false"
+  - "npm install -g npm@^2"
+
+install:
+  - npm install -g bower
+  - npm install
+  - bower install
+
+script:
+  - ember try $EMBER_TRY_SCENARIO test

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.watchmanconfig
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.watchmanconfig b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.watchmanconfig
new file mode 100644
index 0000000..6ec27cc
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/.watchmanconfig
@@ -0,0 +1,21 @@
+/**
+ * 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.
+ */
+
+{
+  "ignore_dirs": ["tmp", "dist"]
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/LICENSE.md
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/LICENSE.md b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/LICENSE.md
new file mode 100644
index 0000000..c1f9da4
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/LICENSE.md
@@ -0,0 +1,28 @@
+<!---
+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](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.
+-->
+
+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](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.
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/README.md
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/README.md b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/README.md
new file mode 100644
index 0000000..d383a93
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/README.md
@@ -0,0 +1,97 @@
+<!---
+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](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.
+-->
+
+# Hdfs-directory-viewer
+
+Ember Addon to view the HDFS file system.
+
+Different Ambari views can use this in their view. Common code should be usable in every view.
+
+# How to use it
+
+### Including it in dependant project
+Add the following code in package.json of the dependant view
+
+```javascript
+"name": "files",
+"ember-addon": {
+	"paths": [
+	  "../../../../../commons/src/main/resources/ui/hdfs-directory-viewer"
+	]
+}
+```
+
+`paths` is an array which includes all the addons shares in ```commons``` library. The entries should be the relative path to the addon in this ```commons``` repository.
+
+### Including the UI dependencies in the dependent project
+As we are going to include the component using the `ember-addon` config in `package.json` and not by the `ember install` way, the UI dependencies also has to be included in the dependent projects `bower.json` file if not already added.
+
+```
+"bootstrap": "~3.3.6",
+"bootstrap-treeview": "~1.2.0",
+"font-awesome": "~4.5.0"
+```
+
+### Overriding configs in dependant project
+
+Create a util object in `utils` directory using `ember generate util <object name>` and override it as follows:
+
+```javascript
+import ViewerConfig from 'hdfs-directory-viewer/utils/viewer-config';
+
+export default ViewerConfig.extend({
+  showOnlyDirectories: true,
+
+  expandIcon: 'fa fa-chevron-right',
+  collapseIcon: 'fa fa-chevron-down',
+
+  listDirectoryUrl(pathParams) {
+    return `/api/v1/views/FILES/versions/1.0.0/instances/files/resources/files/fileops/listdir?${pathParams}`;
+  }
+});
+```
+
+All the functions and attributes in `hdfs-directory-viewer/utils/viewer-config` can be overriden
+
+### Passing the object to the view template
+
+```javascript
+import Ember from 'ember';
+import MyViewerConfig from '../utils/my-viewer-config';
+
+export default Ember.Controller.extend({
+  config: MyViewerConfig.create(),
+  actions: {
+    viewerError: function() {
+      console.log("Failed to fetch the content!!!");
+    },
+    viewerSelectedPath: function(data) {
+      console.log(`User selected: path: ${data.path}, isDirectory: ${data.isDirectory}`);
+    }
+  }
+});
+```
+
+```html
+...
+<div class="directory-viewer-wrap">
+  {{directory-viewer
+    config=config
+    errorAction="viewerError"
+    pathSelectAction="viewerSelectedPath"
+  }}
+</div>
+...
+```

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/addon/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/addon/.gitkeep b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/addon/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/addon/components/directory-viewer.js
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/addon/components/directory-viewer.js b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/addon/components/directory-viewer.js
new file mode 100644
index 0000000..991d122
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/addon/components/directory-viewer.js
@@ -0,0 +1,196 @@
+/**
+ * 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 layout from '../templates/components/directory-viewer';
+
+export default Ember.Component.extend({
+  layout,
+  config: Ember.Object.create({}),
+  classNames: ['directory-viewer'],
+  startPath: '/',
+  treeData: Ember.A(),
+  currentPath: Ember.computed.oneWay('startPath'),
+  currentQueryParam: Ember.computed('currentPath', function() {
+    return Ember.$.param({path: this.get('currentPath')});
+  }),
+
+  startFetch: Ember.on('didInitAttrs', function() {
+    this.fetchData();
+  }),
+
+
+  fetchData: function() {
+    this.listPath(this.get('currentQueryParam')).then(
+      (response) => {
+        let list = this.filterDirectoriesIfRequired(response.files);
+        this.modifyTreeViewData(list);
+      }, (error) => {
+        this.sendAction('errorAction', error);
+      }
+    );
+  },
+
+  /**
+   * Makes a XHR call and returns a promise.
+   */
+  listPath: function(params) {
+    let config = this.get('config');
+    let listUrl = config.listDirectoryUrl(params);
+    let headers = config.getHeaders();
+    return Ember.$.ajax(listUrl, {
+      headers: headers
+    });
+  },
+
+  filterDirectoriesIfRequired: function(files) {
+    let showOnlyDirectories = this.get('config.showOnlyDirectories');
+    return files.filter((entry) => {
+      return (!(showOnlyDirectories) || entry.isDirectory);
+    });
+  },
+
+  modifyTreeViewData: function(response) {
+    let paths = response.map((entry) => {
+      let isDirectory = entry.isDirectory;
+      let icon = isDirectory ? this.get('config.folderIcon') : this.get('config.fileIcon');
+      let data = {
+        path: entry.path,
+        pathSegment: this.getNameForPath(entry.path),
+        isDirectory: isDirectory,
+        icon: icon,
+        text: this.getNameForPath(entry.path)
+      };
+      if(isDirectory) {
+        data.nodes = Ember.A();
+      }
+      return data;
+    });
+
+    var currentPath = this.get('currentPath');
+    var newTreeData = Ember.copy(this.get('treeData'), true);
+    if(currentPath === '/') {
+      newTreeData = paths;
+    } else {
+      this.insertPathToTreeData(newTreeData, paths, currentPath.substring(1));
+    }
+
+    this.set('treeData', newTreeData);
+    this.send('refreshTreeView');
+  },
+
+  insertPathToTreeData(treeData, paths, pathSegment) {
+    let firstPathSegment;
+    if (pathSegment.indexOf('/') !== -1) {
+      firstPathSegment = pathSegment.substring(0, pathSegment.indexOf('/'));
+    } else {
+      firstPathSegment = pathSegment;
+    }
+
+    if(treeData.length === 0) {
+      treeData.pushObjects(paths);
+    } else {
+      treeData.forEach((entry) => {
+        entry.state = {};
+        if (entry.pathSegment === firstPathSegment) {
+          entry.state.expanded = true;
+          if(entry.nodes.length === 0) {
+            paths.forEach((pathEntry) => {
+              entry.nodes.push(pathEntry);
+            });
+          } else {
+            this.insertPathToTreeData(entry.nodes, paths, pathSegment.substring(pathSegment.indexOf('/') + 1));
+          }
+        } else {
+          this.collapseAll(entry);
+        }
+      });
+    }
+  },
+
+  collapseAll: function(node) {
+    if (Ember.isNone(node.state)) {
+      node.state = {};
+    }
+    node.state.expanded = false;
+    if(!Ember.isNone(node.nodes)) {
+      node.nodes.forEach((entry) => {
+        this.collapseAll(entry);
+      });
+    }
+  },
+
+  getNameForPath: function(path) {
+    return path.substring(path.lastIndexOf("/") + 1);
+  },
+
+  collapseAllExceptPath: function(pathSegment) {
+    let collapseAll = function(nodes, pathSegment) {
+      var firstPathSegment;
+      if (pathSegment.indexOf('/') !== -1) {
+        firstPathSegment = pathSegment.substring(0, pathSegment.indexOf('/'));
+      } else {
+        firstPathSegment = pathSegment;
+      }
+
+      nodes.forEach((entry) => {
+        if (Ember.isNone(entry.state)) {
+          entry.state = {};
+        }
+        if(firstPathSegment !== entry.pathSegment) {
+          entry.state.expanded = false;
+        } else {
+          entry.state.expanded = true;
+          collapseAll(entry.nodes, pathSegment.substring(pathSegment.indexOf('/') + 1));
+        }
+      });
+    };
+    var newTreeData = this.get('treeData');
+    collapseAll(newTreeData, pathSegment);
+    this.set('treeData', newTreeData);
+    this.send('refreshTreeView');
+  },
+
+  actions: {
+    refreshTreeView() {
+      Ember.run.later(() => {
+        this.$().treeview({
+          data: this.get('treeData'),
+          expandIcon: this.get('config.expandIcon'),
+          collapseIcon: this.get('config.collapseIcon'),
+          //emptyIcon: "fa",
+          showBorder: false,
+          onNodeSelected: (event, data) => {
+            this.set('currentPath', data.path);
+            this.sendAction('pathSelectAction', {path: data.path, isDirectory: data.isDirectory});
+          },
+          onNodeExpanded: (event, data) => {
+            this.set('currentPath', data.path);
+            if (!Ember.isNone(data.nodes) && data.nodes.length === 0) {
+              var node = this.$().treeview('getNode', data.nodeId);
+              node.icon = "fa fa-refresh fa-spin";
+              this.fetchData();
+            } else {
+              this.collapseAllExceptPath(data.path.substring(1));
+            }
+          }
+        });
+      });
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/addon/templates/components/directory-viewer.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/addon/templates/components/directory-viewer.hbs b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/addon/templates/components/directory-viewer.hbs
new file mode 100644
index 0000000..75339c5
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/addon/templates/components/directory-viewer.hbs
@@ -0,0 +1,18 @@
+{{!
+* 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.
+}}
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/addon/utils/viewer-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/addon/utils/viewer-config.js b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/addon/utils/viewer-config.js
new file mode 100644
index 0000000..64773c6
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/addon/utils/viewer-config.js
@@ -0,0 +1,59 @@
+/**
+ * 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';
+
+export default Ember.Object.extend({
+
+  /**
+   * Set this to true, if only directory listing is required.
+   */
+  showOnlyDirectories: false,
+
+  /**
+   * Set this to true, if refresh of current path is required.
+   */
+  showRefreshButton: false,
+
+  /**
+   * Override these for different Icon. Refer https://github.com/jonmiles/bootstrap-treeview
+   */
+  expandIcon: "fa fa-plus",
+  collapseIcon: "fa fa-minus",
+  //Custom
+  fileIcon: "fa fa-file",
+  folderIcon: "fa fa-folder",
+
+  /**
+   * Override to return the headers add to the XHR call made for various operations.
+   * The Overriding object can also merge its result with the default in this object.
+   */
+  getHeaders() {
+    return {"X-Requested-By": "ambari"};
+  },
+
+  /**
+   * Return the URL endpoint for XHR call meant for listing Directories
+   * @param pathParams
+   * @returns {string}
+   */
+  listDirectoryUrl(pathParams) {
+    return `/listdir?${pathParams}`;
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/app/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/app/.gitkeep b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/app/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/app/components/directory-viewer.js
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/app/components/directory-viewer.js b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/app/components/directory-viewer.js
new file mode 100644
index 0000000..e704ef7
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/app/components/directory-viewer.js
@@ -0,0 +1,19 @@
+/**
+ * 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.
+ */
+
+export { default } from 'hdfs-directory-viewer/components/directory-viewer';

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/app/utils/viewer-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/app/utils/viewer-config.js b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/app/utils/viewer-config.js
new file mode 100644
index 0000000..f175b6c
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/app/utils/viewer-config.js
@@ -0,0 +1,19 @@
+/**
+ * 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.
+ */
+
+export { default } from 'hdfs-directory-viewer/utils/viewer-config';

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/bower.json
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/bower.json b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/bower.json
new file mode 100644
index 0000000..f016904
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/bower.json
@@ -0,0 +1,19 @@
+{
+  "name": "hdfs-directory-viewer",
+  "dependencies": {
+    "ember": "2.2.0",
+    "ember-cli-shims": "0.1.0",
+    "ember-cli-test-loader": "0.2.2",
+    "ember-load-initializers": "0.1.7",
+    "ember-qunit-notifications": "0.1.0",
+    "jquery": "1.11.3",
+    "loader.js": "^3.5.0",
+    "qunit": "~1.20.0",
+    "bootstrap": "~3.3.6",
+    "bootstrap-treeview": "~1.2.0",
+    "font-awesome": "~4.5.0"
+  },
+  "resolutions": {
+    "ember": "2.2.0"
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/config/ember-try.js
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/config/ember-try.js b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/config/ember-try.js
new file mode 100644
index 0000000..252dff2
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/config/ember-try.js
@@ -0,0 +1,54 @@
+/**
+ * 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.
+ */
+
+/*jshint node:true*/
+module.exports = {
+  scenarios: [
+    {
+      name: 'default',
+      dependencies: { }
+    },
+    {
+      name: 'ember-release',
+      dependencies: {
+        'ember': 'components/ember#release'
+      },
+      resolutions: {
+        'ember': 'release'
+      }
+    },
+    {
+      name: 'ember-beta',
+      dependencies: {
+        'ember': 'components/ember#beta'
+      },
+      resolutions: {
+        'ember': 'beta'
+      }
+    },
+    {
+      name: 'ember-canary',
+      dependencies: {
+        'ember': 'components/ember#canary'
+      },
+      resolutions: {
+        'ember': 'canary'
+      }
+    }
+  ]
+};

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/config/environment.js
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/config/environment.js b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/config/environment.js
new file mode 100644
index 0000000..4a4b263
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/config/environment.js
@@ -0,0 +1,24 @@
+/**
+ * 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.
+ */
+
+/*jshint node:true*/
+'use strict';
+
+module.exports = function(/* environment, appConfig */) {
+  return { };
+};

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/ember-cli-build.js
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/ember-cli-build.js b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/ember-cli-build.js
new file mode 100644
index 0000000..f6aac28
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/ember-cli-build.js
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ */
+
+/*jshint node:true*/
+/* global require, module */
+var EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
+
+module.exports = function(defaults) {
+  var app = new EmberAddon(defaults, {
+    // Add options here
+  });
+
+  /*
+    This build file specifies the options for the dummy test app of this
+    addon, located in `/tests/dummy`
+    This build file does *not* influence how the addon or the app using it
+    behave. You most likely want to be modifying `./index.js` or app's build file
+  */
+
+  return app.toTree();
+};

http://git-wip-us.apache.org/repos/asf/ambari/blob/281307fc/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/index.js
----------------------------------------------------------------------
diff --git a/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/index.js b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/index.js
new file mode 100644
index 0000000..dc074d7
--- /dev/null
+++ b/contrib/views/commons/src/main/resources/ui/hdfs-directory-viewer/index.js
@@ -0,0 +1,32 @@
+/**
+ * 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.
+ */
+
+/* jshint node: true */
+'use strict';
+
+module.exports = {
+  name: 'hdfs-directory-viewer',
+  included: function(app) {
+    this._super.included(app);
+
+    app.import(app.bowerDirectory + '/bootstrap/dist/css/bootstrap.css');
+    app.import(app.bowerDirectory + '/bootstrap/dist/js/bootstrap.js');
+    app.import(app.bowerDirectory + '/bootstrap-treeview/src/js/bootstrap-treeview.js');
+    app.import(app.bowerDirectory + '/bootstrap-treeview/dist/bootstrap-treeview.min.css');
+  }
+};