@RvdAuth
 @PUT
 @Path("{name}/rename")
 public Response renameProject(
     @PathParam("name") String projectName,
     @QueryParam("newName") String projectNewName,
     @QueryParam("ticket") String ticket)
     throws StorageException, ProjectDoesNotExist {
   if (!RvdUtils.isEmpty(projectName) && !RvdUtils.isEmpty(projectNewName)) {
     assertProjectAvailable(projectName);
     try {
       ProjectApplicationsApi applicationsApi =
           new ProjectApplicationsApi(servletContext, workspaceStorage, marshaler);
       applicationsApi.renameApplication(ticket, projectName, projectNewName);
       projectService.renameProject(projectName, projectNewName);
       return Response.ok().build();
     } catch (ProjectDirectoryAlreadyExists e) {
       logger.error(e.getMessage(), e);
       return Response.status(Status.CONFLICT).build();
     } catch (StorageException e) {
       return Response.status(Status.INTERNAL_SERVER_ERROR).build();
     } catch (ApplicationAlreadyExists e) {
       return Response.status(Status.CONFLICT).build();
     } catch (ApplicationsApiSyncException e) {
       logger.error(e.getMessage(), e);
       return Response.status(Status.INTERNAL_SERVER_ERROR).build();
     }
   } else return Response.status(Status.BAD_REQUEST).build();
 }
  @RvdAuth
  @GET
  @Produces(MediaType.APPLICATION_JSON)
  public Response listProjects(@Context HttpServletRequest request) {
    Principal loggedUser = securityContext.getUserPrincipal();
    List<ProjectItem> items;
    try {
      items = projectService.getAvailableProjectsByOwner(loggedUser.getName());
      projectService.fillStartUrlsForProjects(items, request);
    } catch (BadWorkspaceDirectoryStructure e) {
      logger.error(e.getMessage(), e);
      return Response.status(Status.INTERNAL_SERVER_ERROR).build();
    } catch (StorageException e) {
      logger.error(e.getMessage(), e);
      return Response.status(Status.INTERNAL_SERVER_ERROR).build();
    } catch (ProjectException e) {
      logger.error(e.getMessage(), e);
      return Response.status(Status.INTERNAL_SERVER_ERROR).build();
    }

    Gson gson = new Gson();
    return Response.ok(gson.toJson(items), MediaType.APPLICATION_JSON).build();
  }
  @RvdAuth
  @POST
  @Path("{name}/wavs")
  public Response uploadWavFile(
      @PathParam("name") String projectName, @Context HttpServletRequest request)
      throws StorageException, ProjectDoesNotExist {
    logger.info("running /uploadwav");
    assertProjectAvailable(projectName);
    try {
      if (request.getHeader("Content-Type") != null
          && request.getHeader("Content-Type").startsWith("multipart/form-data")) {
        Gson gson = new Gson();
        ServletFileUpload upload = new ServletFileUpload();
        FileItemIterator iterator = upload.getItemIterator(request);

        JsonArray fileinfos = new JsonArray();

        while (iterator.hasNext()) {
          FileItemStream item = iterator.next();
          JsonObject fileinfo = new JsonObject();
          fileinfo.addProperty("fieldName", item.getFieldName());

          // is this a file part (talking about multipart requests, there might be parts that are
          // not actual files).
          // They will be ignored
          if (item.getName() != null) {
            projectService.addWavToProject(projectName, item.getName(), item.openStream());
            fileinfo.addProperty("name", item.getName());
            // fileinfo.addProperty("size", size(item.openStream()));
          }
          if (item.getName() == null) {
            logger.warn("non-file part found in upload");
            fileinfo.addProperty("value", read(item.openStream()));
          }
          fileinfos.add(fileinfo);
        }

        return Response.ok(gson.toJson(fileinfos), MediaType.APPLICATION_JSON).build();

      } else {

        String json_response = "{\"result\":[{\"size\":" + size(request.getInputStream()) + "}]}";
        return Response.ok(json_response, MediaType.APPLICATION_JSON).build();
      }
    } catch (Exception e /* TODO - use a more specific type !!! */) {
      logger.error(e.getMessage(), e);
      return Response.status(Status.INTERNAL_SERVER_ERROR).build();
    }
  }
 @RvdAuth
 @DELETE
 @Path("{name}/wavs")
 public Response removeWavFile(
     @PathParam("name") String projectName,
     @QueryParam("filename") String wavname,
     @Context HttpServletRequest request)
     throws StorageException, ProjectDoesNotExist {
   assertProjectAvailable(projectName);
   try {
     projectService.removeWavFromProject(projectName, wavname);
     return Response.ok().build();
   } catch (WavItemDoesNotExist e) {
     logger.warn("Cannot delete " + wavname + " from " + projectName + " app");
     return Response.status(Status.NOT_FOUND).build();
   }
 }
  @RvdAuth
  @PUT
  @Path("{name}")
  public Response createProject(
      @PathParam("name") String name,
      @QueryParam("kind") String kind,
      @QueryParam("ticket") String ticket) {
    Principal loggedUser = securityContext.getUserPrincipal();
    ProjectApplicationsApi applicationsApi = null;

    logger.info("Creating project " + name);
    try {
      applicationsApi = new ProjectApplicationsApi(servletContext, workspaceStorage, marshaler);
      applicationsApi.createApplication(ticket, name, kind);
      ProjectState projectState = projectService.createProject(name, kind, loggedUser.getName());
      BuildService buildService = new BuildService(workspaceStorage);
      buildService.buildProject(name, projectState);
    } catch (ProjectAlreadyExists e) {
      logger.error(e.getMessage(), e);
      try {
        applicationsApi.rollbackCreateApplication(ticket, name);
      } catch (ApplicationsApiSyncException e1) {
        logger.error(e1.getMessage(), e1);
        return Response.status(Status.INTERNAL_SERVER_ERROR).build();
      }
      return Response.status(Status.CONFLICT).build();
    } catch (StorageException e) {
      logger.error(e.getMessage(), e);
      return Response.status(Status.INTERNAL_SERVER_ERROR).build();
    } catch (InvalidServiceParameters e) {
      logger.error(e);
      return Response.status(Status.BAD_REQUEST).build();
    } catch (ApplicationAlreadyExists e) {
      logger.error(e.getMessage(), e);
      return Response.status(Status.CONFLICT).build();
    } catch (ApplicationsApiSyncException e) {
      logger.error(e.getMessage(), e);
      return Response.status(Status.INTERNAL_SERVER_ERROR).build();
    } catch (UnsupportedEncodingException e) {
      logger.error(e.getMessage(), e);
      return Response.status(Status.INTERNAL_SERVER_ERROR).build();
    }

    return Response.ok().build();
  }
  @RvdAuth
  @GET
  @Path("{name}/wavs")
  @Produces(MediaType.APPLICATION_JSON)
  public Response listWavs(@PathParam("name") String name)
      throws StorageException, ProjectDoesNotExist {
    assertProjectAvailable(name);
    List<WavItem> items;
    try {

      items = projectService.getWavs(name);
      Gson gson = new Gson();
      return Response.ok(gson.toJson(items), MediaType.APPLICATION_JSON).build();
    } catch (BadWorkspaceDirectoryStructure e) {
      logger.error(e.getMessage(), e);
      return Response.status(Status.INTERNAL_SERVER_ERROR).build();
    } catch (StorageException e) {
      logger.error("Error getting wav list for project '" + name + "'", e);
      return Response.status(Status.INTERNAL_SERVER_ERROR).build();
    }
  }
 @RvdAuth
 @POST
 @Path("{name}")
 public Response updateProject(
     @Context HttpServletRequest request, @PathParam("name") String projectName) {
   if (projectName != null && !projectName.equals("")) {
     logger.info("Saving project " + projectName);
     try {
       ProjectState existingProject = FsProjectStorage.loadProject(projectName, workspaceStorage);
       Principal loggedUser = securityContext.getUserPrincipal();
       if (loggedUser.getName().equals(existingProject.getHeader().getOwner())
           || existingProject.getHeader().getOwner() == null) {
         projectService.updateProject(request, projectName, existingProject);
         return buildOkResponse();
       } else {
         throw new WebApplicationException(Response.Status.UNAUTHORIZED);
       }
     } catch (ValidationException e) {
       RvdResponse rvdResponse = new RvdResponse().setValidationException(e);
       return Response.status(Status.OK).entity(rvdResponse.asJson()).build();
       // return buildInvalidResponse(Status.OK, RvdResponse.Status.INVALID,e);
       // Gson gson = new Gson();
       // return Response.ok(gson.toJson(e.getValidationResult()),
       // MediaType.APPLICATION_JSON).build();
     } catch (IncompatibleProjectVersion e) {
       logger.error(e);
       return Response.status(Status.INTERNAL_SERVER_ERROR)
           .entity(e.asJson())
           .type(MediaType.APPLICATION_JSON)
           .build();
     } catch (RvdException e) {
       logger.error(e.getMessage(), e);
       return buildErrorResponse(Status.OK, RvdResponse.Status.ERROR, e);
       // return Response.status(Status.INTERNAL_SERVER_ERROR).build();
     }
   } else {
     logger.warn("Empty project name specified for updating");
     return Response.status(Status.BAD_REQUEST).build();
   }
 }
  @GET
  @RvdAuth
  @Path("{name}/archive")
  public Response downloadArchive(@PathParam("name") String projectName)
      throws StorageException, ProjectDoesNotExist, UnsupportedEncodingException, EncoderException {
    logger.debug("downloading raw archive for project " + projectName);
    assertProjectAvailable(projectName);

    InputStream archiveStream;
    try {
      archiveStream = projectService.archiveProject(projectName);
      String dispositionHeader =
          "attachment; filename*=UTF-8''" + RvdUtils.myUrlEncode(projectName + ".zip");
      return Response.ok(archiveStream, "application/zip")
          .header("Content-Disposition", dispositionHeader)
          .build();

    } catch (StorageException e) {
      logger.error(e, e);
      return null;
    }
  }
 @RvdAuth
 @DELETE
 @Path("{name}")
 public Response deleteProject(
     @PathParam("name") String projectName, @QueryParam("ticket") String ticket)
     throws ProjectDoesNotExist {
   if (!RvdUtils.isEmpty(projectName)) {
     try {
       ProjectApplicationsApi applicationsApi =
           new ProjectApplicationsApi(servletContext, workspaceStorage, marshaler);
       applicationsApi.removeApplication(ticket, projectName);
       projectService.deleteProject(projectName);
       return Response.ok().build();
     } catch (StorageException e) {
       logger.error("Error deleting project '" + projectName + "'", e);
       return Response.status(Status.INTERNAL_SERVER_ERROR).build();
     } catch (ApplicationsApiSyncException e) {
       logger.error("Error deleting project '" + projectName + "' through the API", e);
       return Response.status(Status.INTERNAL_SERVER_ERROR).build();
     }
   } else return Response.status(Status.BAD_REQUEST).build();
 }
  @RvdAuth
  @POST
  // @Path("{name}/archive")
  public Response importProjectArchive(
      @Context HttpServletRequest request, @QueryParam("ticket") String ticket) {
    logger.info("Importing project from raw archive");
    ProjectApplicationsApi applicationsApi = null;
    String projectName = null;

    try {
      if (request.getHeader("Content-Type") != null
          && request.getHeader("Content-Type").startsWith("multipart/form-data")) {
        Gson gson = new Gson();
        ServletFileUpload upload = new ServletFileUpload();
        FileItemIterator iterator = upload.getItemIterator(request);

        JsonArray fileinfos = new JsonArray();

        while (iterator.hasNext()) {
          FileItemStream item = iterator.next();
          JsonObject fileinfo = new JsonObject();
          fileinfo.addProperty("fieldName", item.getFieldName());

          // is this a file part (talking about multipart requests, there might be parts that are
          // not actual files).
          // They will be ignored
          if (item.getName() != null) {
            String effectiveProjectName =
                projectService.importProjectFromArchive(item.openStream(), item.getName());
            // buildService.buildProject(effectiveProjectName);

            // Load project kind
            String projectString =
                FsProjectStorage.loadProjectString(effectiveProjectName, workspaceStorage);
            ProjectState state = marshaler.toModel(projectString, ProjectState.class);
            String projectKind = state.getHeader().getProjectKind();
            projectName = effectiveProjectName;

            // Create application
            applicationsApi =
                new ProjectApplicationsApi(servletContext, workspaceStorage, marshaler);
            applicationsApi.createApplication(ticket, effectiveProjectName, projectKind);

            fileinfo.addProperty("name", item.getName());
            fileinfo.addProperty("projectName", effectiveProjectName);
          }
          if (item.getName() == null) {
            logger.warn("non-file part found in upload");
            fileinfo.addProperty("value", read(item.openStream()));
          }
          fileinfos.add(fileinfo);
        }
        return Response.ok(gson.toJson(fileinfos), MediaType.APPLICATION_JSON).build();
      } else {
        String json_response = "{\"result\":[{\"size\":" + size(request.getInputStream()) + "}]}";
        return Response.ok(json_response, MediaType.APPLICATION_JSON).build();
      }
    } catch (StorageException e) {
      logger.warn(e, e);
      logger.debug(e, e);
      return buildErrorResponse(Status.BAD_REQUEST, RvdResponse.Status.ERROR, e);
    } catch (ApplicationAlreadyExists e) {
      logger.warn(e, e);
      logger.debug(e, e);
      try {
        applicationsApi.rollbackCreateApplication(ticket, projectName);
      } catch (ApplicationsApiSyncException e1) {
        logger.error(e1.getMessage(), e1);
        return buildErrorResponse(Status.INTERNAL_SERVER_ERROR, RvdResponse.Status.ERROR, e);
      }
      return buildErrorResponse(Status.CONFLICT, RvdResponse.Status.ERROR, e);
    } catch (Exception e /* TODO - use a more specific type !!! */) {
      logger.error(e.getMessage(), e);
      return Response.status(Status.INTERNAL_SERVER_ERROR).build();
    }
  }