@Override
  public <E extends Event<ApplicationArchive>> void onBeforeOperation(
      E event, List<ProcessingEvent> events) throws EventNotificationException {

    ApplicationArchive archive = (ApplicationArchive) event.getPayload();
    boolean newUpload = archive.getNewFileUploaded() != null;
    ApplicationArchive ret = archive;
    if (newUpload && (ret = processApplicationArchiveFileUpload(archive, events)) == null) {
      throw new PersistenceException("Zip archive failed to process!");
    } else {
      event.setPayload(ret);
    }
  }
  @Override
  public <E extends Event<Map>> void handle(E event) throws EventHandlingException {

    if (logger.isTraceEnabled()) {
      logger.trace("entering handle()");
    }

    ApplicationArchive archive = (ApplicationArchive) event.getPayload().get("archive");
    File file = archive.getFile(getFileSystemStoragePathPrefix());

    if (file.exists()) {
      if (!file.delete()) {
        logger.error(
            "Failed to delete archive " + archive.getFile(getFileSystemStoragePathPrefix()));
      }
    } else {
      logger.warn(
          "Failed to find archive "
              + archive.getFile(getFileSystemStoragePathPrefix())
              + ".  It may have yet to be deployed.");
    }

    File directory = archive.getExplodedPath(getFileSystemStoragePathPrefix());
    if (directory.exists()) {
      try {
        FileUtils.deleteDirectory(directory);
      } catch (IOException ioe) {
        String msg = "Unable to delete directory " + directory;
        logger.error(msg);
        throw new EventHandlingException(msg, ioe);
      }
    }

    if (logger.isTraceEnabled()) {
      logger.trace("exiting handle()");
    }
  }
 @Override
 public List<ApplicationVersion> findVersionsByApplicationArchive(ApplicationArchive archive) {
   Query q =
       entityManager.createQuery(
           "select distinct av "
               + "from ApplicationVersion av "
               + "inner join fetch av.archive aa "
               + "where aa.id=:id ");
   q.setParameter("id", archive.getId());
   try {
     @SuppressWarnings(value = {"unchecked"})
     List<ApplicationVersion> versions = (List<ApplicationVersion>) q.getResultList();
     return versions;
   } catch (NoResultException nre) {
     return null;
   }
 }
 @Override
 public List<Deployment> findDeploymentsByApplicationArchive(ApplicationArchive archive) {
   Query q =
       entityManager.createQuery(
           "select distinct d "
               + "from Deployment d "
               + "inner join fetch d.applicationArchive aa "
               + "where aa.id=:id");
   q.setParameter("id", archive.getId());
   try {
     @SuppressWarnings(value = {"unchecked"})
     List<Deployment> deployments = (List<Deployment>) q.getResultList();
     return deployments;
   } catch (NoResultException nre) {
     return null;
   }
 }
  @SuppressWarnings("unchecked")
  private ApplicationArchive processApplicationArchiveFileUpload(
      ApplicationArchive archive, List<ProcessingEvent> events) {

    GlobalSettings settings = modelManager.getGlobalSettings();
    File tempFile = new File(archive.getNewFileUploaded());
    Long size = tempFile.length();

    String pathError = settings.validateTemporaryStoragePath();
    if (pathError != null) {
      logger.error(
          "There is an issue with the global settings temporary storage path: "
              + settings.validateTemporaryStoragePath()
              + "\n {}",
          pathError);
      events.add(
          new MessagesEvent(
              "There is an issue with the global settings temporary storage path: "
                  + settings.validateTemporaryStoragePath()
                  + " - "
                  + pathError));
      return null;
    }

    // determine the md5 hash of the uploaded file
    // and rename the temp file by the hash
    FileInputStream is = null;
    File destinationFile = null;
    try {

      // if the archive is pre-existing and not the same,
      // then determine if the web-view and zip should be deleted
      // that is, they are not used by any other versions
      if (archive.getId() != null) {
        ArchiveFileHelper.maintainFileSystemCleanliness(modelManager, fileManager, archive, events);
      }

      String hashValue = null;
      ApplicationArchive archiveExists = null;
      try {
        is = new FileInputStream(tempFile);
        hashValue = Utils.hashInputStream("MD5", is);
        archiveExists =
            modelManager
                .getModelService()
                .findApplicationArchiveByHashAndAlgorithm(
                    archive.getApplication(), hashValue, "MD5");
        if (archiveExists != null) {
          if (!tempFile.delete()) {
            String mesg = String.format("Failed to delete temporary file %s", tempFile.getName());
            logger.error(mesg);
            events.add(new MessagesEvent(mesg));
          }
          return archiveExists;
        } else {
          // if an archive of the hash/alg doesn't exist,
          // then we don't want to accidentally change an existing one.
          archive = archive.clone();
          archive.setId(null);
        }
      } catch (DigestException de) {
        throw new PersistenceException(de);
      } finally {
        is.close();
      }

      archive.setHashAlgorithm("MD5");
      archive.setHash(hashValue);

      destinationFile = archive.getFile(settings.getTemporaryStoragePath());

      // if the upload destination exists, then try to delete and overwrite
      // even though they are theoretically the same.
      if (destinationFile.exists() && !destinationFile.delete()) {
        String mesg =
            String.format(
                "Failed to delete old file (theoretically the same anyways, so proceeding) %s",
                destinationFile.getName());
        logger.error(mesg);
        events.add(new MessagesEvent(mesg));
        if (!tempFile.delete()) {
          mesg = String.format("Failed to delete temporary file %s", tempFile.getName());
          logger.error(mesg);
          events.add(new MessagesEvent(mesg));
        }
      }

      // if it didn't exist or it was successfully deleted,
      // then rename the upload to our destination and unzip it
      // into the web-view directory
      else if (tempFile.renameTo(destinationFile)) {

        String mesg =
            String.format(
                "Uploaded temporary file %s successfully renamed to %s",
                tempFile.getName(), destinationFile.getName());
        logger.debug(mesg);
        events.add(new MessagesEvent(mesg));
        ArchiveFileHelper.unzipFile(modelManager, fileManager, archive, destinationFile, events);
      } else {
        String mesg =
            String.format(
                "Failed to renamed file %s to %s", tempFile.getName(), destinationFile.getName());
        logger.error(mesg);
        events.add(new MessagesEvent(mesg));
        return null;
      }
    } catch (IOException ioe) {
      events.add(new MessagesEvent(ioe.getMessage()));
      return null;
    }

    // determine the compressed and uncompressed size of the zip archive
    try {
      archive.setBytesLength(size.intValue());
      ZipFile zipFile = null;
      try {
        zipFile = new ZipFile(destinationFile);
        Integer uncompressedSize = ZipUtils.getUncompressedSize(zipFile).intValue();
        archive.setBytesLengthUncompressed(new Long(uncompressedSize).intValue());
      } finally {
        if (zipFile != null) {
          zipFile.close();
        }
      }
    } catch (IOException ioe) {
      logger.error(
          "An exception occurred while calculating the uncompressed size of the archive: {}", ioe);
      events.add(
          new MessagesEvent(
              String.format(
                  "An exception occurred while calculating the uncompressed size of the archive: %s",
                  ioe.getMessage())));
      return null;
    }

    archive.setUrl(ApplicationArchive.URL_TEMPLATE);

    return archive;
  }