瀏覽代碼

AMBARI-6836. View: Files property checking should log more explicit failure.

Mahadev Konar 11 年之前
父節點
當前提交
221f0e511c

+ 121 - 80
contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/DownloadService.java

@@ -46,6 +46,8 @@ import javax.ws.rs.core.UriInfo;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElement;
 
 
 import com.google.gson.Gson;
 import com.google.gson.Gson;
+import org.apache.ambari.view.filebrowser.utils.NotFoundFormattedException;
+import org.apache.ambari.view.filebrowser.utils.ServiceFormattedException;
 import org.apache.hadoop.fs.FSDataInputStream;
 import org.apache.hadoop.fs.FSDataInputStream;
 import org.apache.hadoop.fs.FileStatus;
 import org.apache.hadoop.fs.FileStatus;
 import org.apache.ambari.view.ViewContext;
 import org.apache.ambari.view.ViewContext;
@@ -89,17 +91,16 @@ public class DownloadService extends HdfsService {
             "filename=\"" + status.getPath().getName() + "\"").type(mimeType);
             "filename=\"" + status.getPath().getName() + "\"").type(mimeType);
       }
       }
       return result.build();
       return result.build();
+    } catch (WebApplicationException ex) {
+      throw ex;
     } catch (FileNotFoundException ex) {
     } catch (FileNotFoundException ex) {
-      return Response.ok(Response.Status.NOT_FOUND.getStatusCode())
-          .entity(ex.getMessage()).build();
+      throw new NotFoundFormattedException(ex.getMessage(), ex);
     } catch (Exception ex) {
     } catch (Exception ex) {
-      return Response.ok(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode())
-          .entity(ex.getMessage()).build();
+      throw new ServiceFormattedException(ex.getMessage(), ex);
     }
     }
   }
   }
 
 
-  private void zipFile(ZipOutputStream zip, String path)
-      throws InterruptedException, Exception {
+  private void zipFile(ZipOutputStream zip, String path) throws InterruptedException, IOException {
     try {
     try {
       zip.putNextEntry(new ZipEntry(path.substring(1)));
       zip.putNextEntry(new ZipEntry(path.substring(1)));
       FSDataInputStream in = getApi(context).open(path);
       FSDataInputStream in = getApi(context).open(path);
@@ -108,22 +109,25 @@ public class DownloadService extends HdfsService {
         zip.write(chunk);
         zip.write(chunk);
       }
       }
     } catch (IOException ex) {
     } catch (IOException ex) {
-      logger.error("Error zipping file " + path.substring(1) + ": "
-          + ex.getMessage());
+      String msg = "Error zipping file " + path.substring(1) + ": "
+          + ex.getMessage();
+      logger.error(msg);
       zip.write(ex.getMessage().getBytes());
       zip.write(ex.getMessage().getBytes());
+      throw new ServiceFormattedException(ex.getMessage(), ex);
     } finally {
     } finally {
       zip.closeEntry();
       zip.closeEntry();
     }
     }
-
   }
   }
 
 
   private void zipDirectory(ZipOutputStream zip, String path) {
   private void zipDirectory(ZipOutputStream zip, String path) {
     try {
     try {
       zip.putNextEntry(new ZipEntry(path.substring(1) + "/"));
       zip.putNextEntry(new ZipEntry(path.substring(1) + "/"));
       zip.closeEntry();
       zip.closeEntry();
-    } catch (IOException e) {
-      logger.error("Error zipping directory " + path.substring(1) + "/" + ": "
-          + e.getMessage());
+    } catch (IOException ex) {
+      String msg = "Error zipping directory " + path.substring(1) + "/" + ": "
+          + ex.getMessage();
+      logger.error(msg);
+      throw new ServiceFormattedException(msg, ex);
     }
     }
   }
   }
 
 
@@ -137,40 +141,47 @@ public class DownloadService extends HdfsService {
   @Consumes(MediaType.APPLICATION_JSON)
   @Consumes(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_OCTET_STREAM)
   @Produces(MediaType.APPLICATION_OCTET_STREAM)
   public Response downloadGZip(final DownloadRequest request) {
   public Response downloadGZip(final DownloadRequest request) {
-    StreamingOutput result = new StreamingOutput() {
-      public void write(OutputStream output) throws IOException,
-          WebApplicationException {
-        ZipOutputStream zip = new ZipOutputStream(output);
-        try {
-          HdfsApi api = getApi(context);
-          Queue<String> files = new LinkedList<String>();
-          for (String file : request.entries) {
-            files.add(file);
-          }
-          while (!files.isEmpty()) {
-            String path = files.poll();
-            FileStatus status = api.getFileStatus(path);
-            if (status.isDirectory()) {
-              FileStatus[] subdir = api.listdir(path);
-              for (FileStatus file : subdir) {
-                files.add(org.apache.hadoop.fs.Path
-                    .getPathWithoutSchemeAndAuthority(file.getPath())
-                    .toString());
+    try {
+      StreamingOutput result = new StreamingOutput() {
+        public void write(OutputStream output) throws IOException,
+            ServiceFormattedException {
+          ZipOutputStream zip = new ZipOutputStream(output);
+          try {
+            HdfsApi api = getApi(context);
+            Queue<String> files = new LinkedList<String>();
+            for (String file : request.entries) {
+              files.add(file);
+            }
+            while (!files.isEmpty()) {
+              String path = files.poll();
+              FileStatus status = api.getFileStatus(path);
+              if (status.isDirectory()) {
+                FileStatus[] subdir = api.listdir(path);
+                for (FileStatus file : subdir) {
+                  files.add(org.apache.hadoop.fs.Path
+                      .getPathWithoutSchemeAndAuthority(file.getPath())
+                      .toString());
+                }
+                zipDirectory(zip, path);
+              } else {
+                zipFile(zip, path);
               }
               }
-              zipDirectory(zip, path);
-            } else {
-              zipFile(zip, path);
             }
             }
+          } catch (Exception ex) {
+            logger.error("Error occurred: " + ex.getMessage());
+            throw new ServiceFormattedException(ex.getMessage(), ex);
+          } finally {
+            zip.close();
           }
           }
-        } catch (Exception ex) {
-          logger.error("Error occured: " + ex.getMessage());
-        } finally {
-          zip.close();
         }
         }
-      }
-    };
-    return Response.ok(result)
-        .header("Content-Disposition", "inline; filename=\"hdfs.zip\"").build();
+      };
+      return Response.ok(result)
+          .header("Content-Disposition", "inline; filename=\"hdfs.zip\"").build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
   }
   }
 
 
   /**
   /**
@@ -183,33 +194,39 @@ public class DownloadService extends HdfsService {
   @Consumes(MediaType.APPLICATION_JSON)
   @Consumes(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_OCTET_STREAM)
   @Produces(MediaType.APPLICATION_OCTET_STREAM)
   public Response concat(final DownloadRequest request) {
   public Response concat(final DownloadRequest request) {
-    StreamingOutput result = new StreamingOutput() {
-      public void write(OutputStream output) throws IOException,
-          WebApplicationException {
-        FSDataInputStream in = null;
-        for (String path : request.entries) {
-          try {
-            in = getApi(context).open(path);
-            byte[] chunk = new byte[1024];
-            while (in.read(chunk) != -1) {
-              output.write(chunk);
+    try {
+      StreamingOutput result = new StreamingOutput() {
+        public void write(OutputStream output) throws IOException,
+            ServiceFormattedException {
+          FSDataInputStream in = null;
+          for (String path : request.entries) {
+            try {
+              in = getApi(context).open(path);
+              byte[] chunk = new byte[1024];
+              while (in.read(chunk) != -1) {
+                output.write(chunk);
+              }
+            } catch (Exception ex) {
+              throw new ServiceFormattedException(ex.getMessage(), ex);
+            } finally {
+              if (in != null)
+                in.close();
             }
             }
-          } catch (Exception ex) {
-            ex.printStackTrace();
-          } finally {
-            if (in != null)
-              in.close();
           }
           }
         }
         }
+      };
+      ResponseBuilder response = Response.ok(result);
+      if (request.download) {
+        response.header("Content-Disposition", "inline; filename=\"concatResult.txt\"").type(MediaType.APPLICATION_OCTET_STREAM);
+      } else {
+        response.header("Content-Disposition", "filename=\"concatResult.txt\"").type(MediaType.TEXT_PLAIN);
       }
       }
-    };
-    ResponseBuilder response = Response.ok(result);
-    if (request.download){
-      response.header("Content-Disposition", "inline; filename=\"concatResult.txt\"").type(MediaType.APPLICATION_OCTET_STREAM);
-    } else {
-      response.header("Content-Disposition", "filename=\"concatResult.txt\"").type(MediaType.TEXT_PLAIN);
+      return response.build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
     }
     }
-    return response.build();
   }
   }
 
 
   // ===============================
   // ===============================
@@ -225,10 +242,16 @@ public class DownloadService extends HdfsService {
   @Consumes(MediaType.APPLICATION_JSON)
   @Consumes(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_OCTET_STREAM)
   @Produces(MediaType.APPLICATION_OCTET_STREAM)
   public Response zipByRequestId(@QueryParam("requestId") String requestId) {
   public Response zipByRequestId(@QueryParam("requestId") String requestId) {
-    String json = context.getInstanceData(requestId);
-    DownloadRequest request = gson.fromJson(json, DownloadRequest.class);
-    context.removeInstanceData(requestId);
-    return downloadGZip(request);
+    try {
+      String json = context.getInstanceData(requestId);
+      DownloadRequest request = gson.fromJson(json, DownloadRequest.class);
+      context.removeInstanceData(requestId);
+      return downloadGZip(request);
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
   }
   }
 
 
   /**
   /**
@@ -242,10 +265,16 @@ public class DownloadService extends HdfsService {
   @Consumes(MediaType.APPLICATION_JSON)
   @Consumes(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
   public Response zipGenerateLink(final DownloadRequest request) {
   public Response zipGenerateLink(final DownloadRequest request) {
-    String requestId = generateUniqueIdentifer(request);
-    JSONObject json = new JSONObject();
-    json.put("requestId", requestId);
-    return Response.ok(json).build();
+    try {
+      String requestId = generateUniqueIdentifer(request);
+      JSONObject json = new JSONObject();
+      json.put("requestId", requestId);
+      return Response.ok(json).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
   }
   }
 
 
   /**
   /**
@@ -258,10 +287,16 @@ public class DownloadService extends HdfsService {
   @Consumes(MediaType.APPLICATION_JSON)
   @Consumes(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_OCTET_STREAM)
   @Produces(MediaType.APPLICATION_OCTET_STREAM)
   public Response concatByRequestId(@QueryParam("requestId") String requestId) {
   public Response concatByRequestId(@QueryParam("requestId") String requestId) {
-    String json = context.getInstanceData(requestId);
-    DownloadRequest request = gson.fromJson(json, DownloadRequest.class);
-    context.removeInstanceData(requestId);
-    return concat(request);
+    try {
+      String json = context.getInstanceData(requestId);
+      DownloadRequest request = gson.fromJson(json, DownloadRequest.class);
+      context.removeInstanceData(requestId);
+      return concat(request);
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
   }
   }
 
 
   /**
   /**
@@ -275,10 +310,16 @@ public class DownloadService extends HdfsService {
   @Consumes(MediaType.APPLICATION_JSON)
   @Consumes(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
   public Response concatGenerateLink(final DownloadRequest request) {
   public Response concatGenerateLink(final DownloadRequest request) {
-    String requestId = generateUniqueIdentifer(request);
-    JSONObject json = new JSONObject();
-    json.put("requestId", requestId);
-    return Response.ok(json).build();
+    try {
+      String requestId = generateUniqueIdentifer(request);
+      JSONObject json = new JSONObject();
+      json.put("requestId", requestId);
+      return Response.ok(json).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
   }
   }
 
 
   private Gson gson = new Gson();
   private Gson gson = new Gson();

+ 92 - 77
contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/FileOperationService.java

@@ -19,16 +19,8 @@
 package org.apache.ambari.view.filebrowser;
 package org.apache.ambari.view.filebrowser;
 
 
 import java.io.FileNotFoundException;
 import java.io.FileNotFoundException;
-import java.io.IOException;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
+
+import javax.ws.rs.*;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MediaType;
@@ -39,6 +31,8 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
 
 import org.apache.ambari.view.ViewContext;
 import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.filebrowser.utils.NotFoundFormattedException;
+import org.apache.ambari.view.filebrowser.utils.ServiceFormattedException;
 
 
 /**
 /**
  * File operations service
  * File operations service
@@ -57,20 +51,20 @@ public class FileOperationService extends HdfsService {
    * List dir
    * List dir
    * @param path path
    * @param path path
    * @return response with dir content
    * @return response with dir content
-   * @throws Exception
    */
    */
   @GET
   @GET
   @Path("/listdir")
   @Path("/listdir")
   @Produces(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
-  public Response listdir(@QueryParam("path") String path) throws Exception {
+  public Response listdir(@QueryParam("path") String path) {
     try {
     try {
       return Response.ok(
       return Response.ok(
           HdfsApi.fileStatusToJSON(getApi(context).listdir(path))).build();
           HdfsApi.fileStatusToJSON(getApi(context).listdir(path))).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
     } catch (FileNotFoundException ex) {
     } catch (FileNotFoundException ex) {
-      return Response.ok(Response.Status.NOT_FOUND.getStatusCode())
-          .entity(ex.getMessage()).build();
-    } catch (Throwable ex) {
-      throw new Exception(ex.getMessage());
+      throw new NotFoundFormattedException(ex.getMessage(), ex);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
     }
     }
   }
   }
 
 
@@ -78,131 +72,152 @@ public class FileOperationService extends HdfsService {
    * Rename
    * Rename
    * @param request rename request
    * @param request rename request
    * @return response with success
    * @return response with success
-   * @throws IOException
-   * @throws Exception
    */
    */
   @POST
   @POST
   @Path("/rename")
   @Path("/rename")
   @Consumes(MediaType.APPLICATION_JSON)
   @Consumes(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
-  public Response rename(final SrcDstFileRequest request) throws IOException,
-      Exception {
-    HdfsApi api = getApi(context);
-    ResponseBuilder result;
-    if (api.rename(request.src, request.dst)) {
-      result = Response.ok(HdfsApi.fileStatusToJSON(api
-          .getFileStatus(request.dst)));
-    } else {
-      result = Response.ok(new BoolResult(false)).status(422);
+  public Response rename(final SrcDstFileRequest request) {
+    try {
+      HdfsApi api = getApi(context);
+      ResponseBuilder result;
+      if (api.rename(request.src, request.dst)) {
+        result = Response.ok(HdfsApi.fileStatusToJSON(api
+            .getFileStatus(request.dst)));
+      } else {
+        result = Response.ok(new BoolResult(false)).status(422);
+      }
+      return result.build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
     }
     }
-    return result.build();
   }
   }
 
 
   /**
   /**
    * Copy file
    * Copy file
    * @param request source and destination request
    * @param request source and destination request
    * @return response with success
    * @return response with success
-   * @throws IOException
-   * @throws Exception
    */
    */
   @POST
   @POST
   @Path("/copy")
   @Path("/copy")
   @Consumes(MediaType.APPLICATION_JSON)
   @Consumes(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
   public Response copy(final SrcDstFileRequest request,
   public Response copy(final SrcDstFileRequest request,
-                       @Context HttpHeaders headers, @Context UriInfo ui) throws IOException,
-      Exception {
-    HdfsApi api = getApi(context);
-    ResponseBuilder result;
-    if (api.copy(request.src, request.dst)) {
-      result = Response.ok(HdfsApi.fileStatusToJSON(api
-          .getFileStatus(request.dst)));
-    } else {
-      result = Response.ok(new BoolResult(false)).status(422);
+                       @Context HttpHeaders headers, @Context UriInfo ui) {
+    try {
+      HdfsApi api = getApi(context);
+      ResponseBuilder result;
+      if (api.copy(request.src, request.dst)) {
+        result = Response.ok(HdfsApi.fileStatusToJSON(api
+            .getFileStatus(request.dst)));
+      } else {
+        result = Response.ok(new BoolResult(false)).status(422);
+      }
+      return result.build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
     }
     }
-    return result.build();
   }
   }
 
 
   /**
   /**
    * Make directory
    * Make directory
    * @param request make directory request
    * @param request make directory request
    * @return response with success
    * @return response with success
-   * @throws IOException
-   * @throws Exception
    */
    */
   @PUT
   @PUT
   @Path("/mkdir")
   @Path("/mkdir")
   @Produces(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
-  public Response mkdir(final MkdirRequest request) throws IOException,
-      Exception {
-    HdfsApi api = getApi(context);
-    ResponseBuilder result;
-    if (api.mkdir(request.path)) {
-      result = Response.ok(HdfsApi.fileStatusToJSON(api.getFileStatus(request.path)));
-    } else {
-      result = Response.ok(new BoolResult(false)).status(422);
+  public Response mkdir(final MkdirRequest request) {
+    try{
+      HdfsApi api = getApi(context);
+      ResponseBuilder result;
+      if (api.mkdir(request.path)) {
+        result = Response.ok(HdfsApi.fileStatusToJSON(api.getFileStatus(request.path)));
+      } else {
+        result = Response.ok(new BoolResult(false)).status(422);
+      }
+      return result.build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
     }
     }
-    return result.build();
   }
   }
 
 
   /**
   /**
    * Empty trash
    * Empty trash
    * @return response with success
    * @return response with success
-   * @throws IOException
-   * @throws Exception
    */
    */
   @DELETE
   @DELETE
   @Path("/trash/emptyTrash")
   @Path("/trash/emptyTrash")
   @Produces(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
-  public Response emptyTrash() throws IOException, Exception {
-    HdfsApi api = getApi(context);
-    api.emptyTrash();
-    return Response.ok(new BoolResult(true)).build();
+  public Response emptyTrash() {
+    try {
+      HdfsApi api = getApi(context);
+      api.emptyTrash();
+      return Response.ok(new BoolResult(true)).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
   }
   }
 
 
   /**
   /**
    * Move to trash
    * Move to trash
    * @param request remove request
    * @param request remove request
    * @return response with success
    * @return response with success
-   * @throws IOException
-   * @throws Exception
    */
    */
   @DELETE
   @DELETE
   @Path("/moveToTrash")
   @Path("/moveToTrash")
   @Consumes(MediaType.APPLICATION_JSON)
   @Consumes(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
-  public Response moveToTrash(RemoveRequest request) throws IOException, Exception {
-    HdfsApi api = getApi(context);
-    ResponseBuilder result;
-    if (api.moveToTrash(request.path)){
-      result = Response.ok(new BoolResult(true)).status(204);
-    } else {
-      result = Response.ok(new BoolResult(false)).status(422);
+  public Response moveToTrash(RemoveRequest request) {
+    try {
+      HdfsApi api = getApi(context);
+      ResponseBuilder result;
+      if (api.moveToTrash(request.path)){
+        result = Response.ok(new BoolResult(true)).status(204);
+      } else {
+        result = Response.ok(new BoolResult(false)).status(422);
+      }
+      return result.build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
     }
     }
-    return result.build();
   }
   }
 
 
   /**
   /**
    * Remove
    * Remove
    * @param request remove request
    * @param request remove request
    * @return response with success
    * @return response with success
-   * @throws IOException
-   * @throws Exception
    */
    */
   @DELETE
   @DELETE
   @Path("/remove")
   @Path("/remove")
   @Consumes(MediaType.APPLICATION_JSON)
   @Consumes(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
   public Response remove(RemoveRequest request, @Context HttpHeaders headers,
   public Response remove(RemoveRequest request, @Context HttpHeaders headers,
-                         @Context UriInfo ui) throws IOException, Exception {
-    HdfsApi api = getApi(context);
-    ResponseBuilder result;
-    if (api.delete(request.path, request.recursive)){
-      result = Response.ok(new BoolResult(true)).status(204);
-    } else {
-      result = Response.ok(new BoolResult(false)).status(422);
+                         @Context UriInfo ui) {
+    try {
+      HdfsApi api = getApi(context);
+      ResponseBuilder result;
+      if (api.delete(request.path, request.recursive)) {
+        result = Response.ok(new BoolResult(true)).status(204);
+      } else {
+        result = Response.ok(new BoolResult(false)).status(422);
+      }
+      return result.build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
     }
     }
-    return result.build();
   }
   }
 
 
   /**
   /**

+ 11 - 7
contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HdfsService.java

@@ -18,11 +18,11 @@
 
 
 package org.apache.ambari.view.filebrowser;
 package org.apache.ambari.view.filebrowser;
 
 
-import java.io.IOException;
-
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
 
 import org.apache.ambari.view.ViewContext;
 import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.filebrowser.utils.MisconfigurationFormattedException;
+import org.apache.ambari.view.filebrowser.utils.ServiceFormattedException;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
 
 
@@ -60,13 +60,18 @@ public abstract class HdfsService {
    * Ger HdfsApi instance
    * Ger HdfsApi instance
    * @param context View Context instance
    * @param context View Context instance
    * @return HdfsApi business delegate
    * @return HdfsApi business delegate
-   * @throws IOException
-   * @throws Exception
    */
    */
-  public HdfsApi getApi(ViewContext context) throws IOException, Exception {
+  public HdfsApi getApi(ViewContext context) {
     if (_api == null) {
     if (_api == null) {
       Thread.currentThread().setContextClassLoader(null);
       Thread.currentThread().setContextClassLoader(null);
-      _api = new HdfsApi(context.getProperties().get("dataworker.defaultFs"), getUsername(context));
+      String defaultFs = context.getProperties().get("dataworker.defaultFs");
+      if (defaultFs == null)
+        throw new MisconfigurationFormattedException("dataworker.defaultFs");
+      try {
+        _api = new HdfsApi(defaultFs, getUsername(context));
+      } catch (Exception ex) {
+        throw new ServiceFormattedException("HdfsApi connection failed. Check \"dataworker.defaultFs\" property", ex);
+      }
     }
     }
     return _api;
     return _api;
   }
   }
@@ -82,5 +87,4 @@ public abstract class HdfsService {
       username = context.getUsername();
       username = context.getUsername();
     return username;
     return username;
   }
   }
-
 }
 }

+ 30 - 24
contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HelpService.java

@@ -19,19 +19,17 @@
 package org.apache.ambari.view.filebrowser;
 package org.apache.ambari.view.filebrowser;
 
 
 import java.io.FileNotFoundException;
 import java.io.FileNotFoundException;
-import java.io.IOException;
 
 
 import javax.ws.rs.GET;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
-import javax.ws.rs.core.UriInfo;
 
 
 import org.apache.ambari.view.ViewContext;
 import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.filebrowser.utils.NotFoundFormattedException;
+import org.apache.ambari.view.filebrowser.utils.ServiceFormattedException;
 
 
 /**
 /**
  * Help service
  * Help service
@@ -83,52 +81,60 @@ public class HelpService extends HdfsService {
   /**
   /**
    * Returns home directory
    * Returns home directory
    * @return home directory
    * @return home directory
-   * @throws Exception
    */
    */
   @GET
   @GET
   @Path("/home")
   @Path("/home")
   @Produces(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
-  public Response homeDir()
-      throws
-      Exception {
-    HdfsApi api = getApi(context);
-    return Response
-        .ok(HdfsApi.fileStatusToJSON(api.getFileStatus(api.getHomeDir()
-            .toString()))).build();
+  public Response homeDir() {
+    try {
+      HdfsApi api = getApi(context);
+      return Response
+          .ok(HdfsApi.fileStatusToJSON(api.getFileStatus(api.getHomeDir()
+              .toString()))).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
   }
   }
 
 
   /**
   /**
    * Is trash enabled
    * Is trash enabled
    * @return is trash enabled
    * @return is trash enabled
-   * @throws Exception
    */
    */
   @GET
   @GET
   @Path("/trash/enabled")
   @Path("/trash/enabled")
   @Produces(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
-  public Response trashEnabled()
-      throws Exception {
-    HdfsApi api = getApi(context);
-    return Response.ok(new BoolResult(api.trashEnabled())).build();
+  public Response trashEnabled() {
+    try {
+      HdfsApi api = getApi(context);
+      return Response.ok(new BoolResult(api.trashEnabled())).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
   }
   }
 
 
   /**
   /**
    * Trash dir
    * Trash dir
    * @return trash dir
    * @return trash dir
-   * @throws Exception
    */
    */
   @GET
   @GET
   @Path("/trashDir")
   @Path("/trashDir")
   @Produces(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
-  public Response trashdir()
-      throws Exception {
-    HdfsApi api = getApi(context);
+  public Response trashdir() {
     try {
     try {
+      HdfsApi api = getApi(context);
       return Response.ok(
       return Response.ok(
           HdfsApi.fileStatusToJSON(api.getFileStatus(api.getTrashDir()
           HdfsApi.fileStatusToJSON(api.getFileStatus(api.getTrashDir()
               .toString()))).build();
               .toString()))).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
     } catch (FileNotFoundException ex) {
     } catch (FileNotFoundException ex) {
-      return Response.ok(new BoolResult(false)).status(Status.NOT_FOUND)
-          .build();
+      throw new NotFoundFormattedException(ex.getMessage(), ex);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
     }
     }
   }
   }
 
 

+ 37 - 28
contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/UploadService.java

@@ -23,14 +23,12 @@ import java.io.InputStream;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 import java.util.zip.ZipInputStream;
 
 
-import javax.ws.rs.Consumes;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
+import javax.ws.rs.*;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response;
 
 
 import org.apache.ambari.view.ViewContext;
 import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.filebrowser.utils.ServiceFormattedException;
 import org.apache.hadoop.fs.FSDataOutputStream;
 import org.apache.hadoop.fs.FSDataOutputStream;
 
 
 import com.sun.jersey.core.header.FormDataContentDisposition;
 import com.sun.jersey.core.header.FormDataContentDisposition;
@@ -50,7 +48,7 @@ public class UploadService extends HdfsService {
   }
   }
 
 
   private void uploadFile(final String filePath, InputStream uploadedInputStream)
   private void uploadFile(final String filePath, InputStream uploadedInputStream)
-      throws IOException, Exception {
+      throws IOException, InterruptedException {
     byte[] chunk = new byte[1024];
     byte[] chunk = new byte[1024];
     FSDataOutputStream out = getApi(context).create(filePath, false);
     FSDataOutputStream out = getApi(context).create(filePath, false);
     while (uploadedInputStream.read(chunk) != -1) {
     while (uploadedInputStream.read(chunk) != -1) {
@@ -65,7 +63,6 @@ public class UploadService extends HdfsService {
    * @param contentDisposition content disposition
    * @param contentDisposition content disposition
    * @param path path
    * @param path path
    * @return file status
    * @return file status
-   * @throws Exception
    */
    */
   @PUT
   @PUT
   @Consumes(MediaType.MULTIPART_FORM_DATA)
   @Consumes(MediaType.MULTIPART_FORM_DATA)
@@ -73,14 +70,20 @@ public class UploadService extends HdfsService {
   public Response uploadFile(
   public Response uploadFile(
       @FormDataParam("file") InputStream uploadedInputStream,
       @FormDataParam("file") InputStream uploadedInputStream,
       @FormDataParam("file") FormDataContentDisposition contentDisposition,
       @FormDataParam("file") FormDataContentDisposition contentDisposition,
-      @FormDataParam("path") String path) throws Exception {
-    if (!path.endsWith("/"))
-      path = path + "/";
-    String filePath = path + contentDisposition.getFileName();
-    uploadFile(filePath, uploadedInputStream);
-    return Response.ok(
-        HdfsApi.fileStatusToJSON(getApi(context).getFileStatus(filePath)))
-        .build();
+      @FormDataParam("path") String path) {
+    try {
+      if (!path.endsWith("/"))
+        path = path + "/";
+      String filePath = path + contentDisposition.getFileName();
+      uploadFile(filePath, uploadedInputStream);
+      return Response.ok(
+          HdfsApi.fileStatusToJSON(getApi(context).getFileStatus(filePath)))
+          .build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
   }
   }
 
 
   /**
   /**
@@ -99,22 +102,28 @@ public class UploadService extends HdfsService {
   public Response uploadZip(
   public Response uploadZip(
       @FormDataParam("file") InputStream uploadedInputStream,
       @FormDataParam("file") InputStream uploadedInputStream,
       @FormDataParam("file") FormDataContentDisposition contentDisposition,
       @FormDataParam("file") FormDataContentDisposition contentDisposition,
-      @FormDataParam("path") String path) throws Exception {
-    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);
+      @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();
       }
       }
-      ze = zip.getNextEntry();
+      return Response.ok(HdfsApi.fileStatusToJSON(api.listdir(path))).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
     }
     }
-    return Response.ok(HdfsApi.fileStatusToJSON(api.listdir(path))).build();
   }
   }
 
 
 }
 }

+ 43 - 0
contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/utils/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.filebrowser.utils;
+
+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();
+  }
+}

+ 27 - 0
contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/utils/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.filebrowser.utils;
+
+public class NotFoundFormattedException extends ServiceFormattedException {
+  private final static int STATUS = 404;
+
+  public NotFoundFormattedException(String message, Throwable exception) {
+    super(message, exception, STATUS);
+  }
+}

+ 57 - 0
contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/utils/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.filebrowser.utils;
+
+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();
+  }
+}

+ 50 - 0
contrib/views/files/src/main/resources/ui/app/controllers/error.js

@@ -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.
+ */
+
+App.ErrorController = Ember.ObjectController.extend({
+  init:function () {
+    this._super();
+  },
+  actions: {
+    toggleStackTrace:function () {
+      var value = this.get('isExpanded');
+      this.set('isExpanded', !value);
+    },
+  },
+
+  isExpanded: false,
+
+  publicMessage:function () {
+    var content = this.get('content');
+    var text = content.statusText;
+    if (content && content.responseText) {
+      var json = JSON.parse(content.responseText);
+      text = json.message;
+    }
+    return text;
+  }.property('content'),
+  stackTrace:function () {
+    var content = this.get('content');
+    var trace = null;
+    if (content && content.responseText) {
+      var json = JSON.parse(content.responseText);
+      trace = json.trace;
+    }
+    return trace;
+  }.property('content'),
+});

+ 20 - 0
contrib/views/files/src/main/resources/ui/app/controllers/filesAlert.js

@@ -0,0 +1,20 @@
+/**
+ * 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.
+ */
+
+App.FilesAlertController = App.ErrorController.extend({
+});

+ 2 - 0
contrib/views/files/src/main/resources/ui/app/initialize.js

@@ -49,6 +49,8 @@ require('models/file');
 
 
 require('controllers/files');
 require('controllers/files');
 require('controllers/file');
 require('controllers/file');
+require('controllers/error');
+require('controllers/filesAlert');
 
 
 /////////////////////////////////
 /////////////////////////////////
 // Components
 // Components

+ 19 - 6
contrib/views/files/src/main/resources/ui/app/templates/error.hbs

@@ -6,9 +6,9 @@
    to you under the Apache License, Version 2.0 (the
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at
    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
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -17,8 +17,21 @@
 }}
 }}
 
 
 <div class="container">
 <div class="container">
-  <div class="alert alert-danger">
-    <strong>{{content.status}}</strong>
-    {{content.statusText}}
-  </div>
+    <div class="alert alert-danger collapse-group">
+        <strong>{{content.status}}</strong> {{publicMessage}}
+    </div>
+  {{#if stackTrace}}
+      <a href="#" {{action "toggleStackTrace" post}}>
+        {{#if isExpanded}}
+            <span class="glyphicon glyphicon-collapse-down"></span> Collapse Stack Trace
+        {{else}}
+            <span class="glyphicon glyphicon-expand"></span> Expand Stack Trace
+        {{/if}}
+      </a>
+    {{#if isExpanded}}
+        <pre class="prettyprint">
+{{stackTrace}}
+        </pre>
+    {{/if}}
+  {{/if}}
 </div>
 </div>

+ 17 - 2
contrib/views/files/src/main/resources/ui/app/templates/util/errorRow.hbs

@@ -16,9 +16,24 @@
    limitations under the License.
    limitations under the License.
 }}
 }}
 
 
-<div class="text-center">
+<div>
   <button {{action 'removeAlert'}} type="button" class="close" aria-hidden="true">&times;</button>
   <button {{action 'removeAlert'}} type="button" class="close" aria-hidden="true">&times;</button>
-  <strong>{{output.status}} </strong> {{output.message}}
+  <div class="text-center"><strong>{{content.status}} </strong> {{publicMessage}}
+    {{#if stackTrace}}<a href="#" {{action "toggleStackTrace" post}}>
+        {{#if isExpanded}}
+            <span class="glyphicon glyphicon-collapse-down"></span> Collapse Stack Trace
+        {{else}}
+            <span class="glyphicon glyphicon-expand"></span> Expand Stack Trace
+        {{/if}}
+      </a>
+    </div>
+    {{#if isExpanded}}
+        <pre class="prettyprint">
+{{publicMessage}}
+{{stackTrace}}
+        </pre>
+    {{/if}}
+  {{/if}}
 </div>
 </div>
   
   
 
 

+ 1 - 1
contrib/views/files/src/main/resources/ui/config.coffee

@@ -43,7 +43,7 @@ exports.config =
     addSourceURLs: true
     addSourceURLs: true
 
 
   paths:
   paths:
-    public: '/usr/lib/ambari-server/web/views-debug/FILES/FILES_1/'
+    public: '/usr/lib/ambari-server/web/views-debug/FILES/0.1.0/MyFiles/'
 
 
   overrides:
   overrides:
     production:
     production: