/**
   * Downloads a Bundle file for a given bundle id.
   *
   * @param request HttpRequest
   * @param response HttpResponse
   * @throws IOException If fails sending back to the user response information
   */
  public void downloadBundle(HttpServletRequest request, HttpServletResponse response)
      throws IOException {
    try {
      if (!APILocator.getLayoutAPI()
          .doesUserHaveAccessToPortlet("EXT_CONTENT_PUBLISHING_TOOL", getUser())) {
        response.sendError(401);
        return;
      }
    } catch (DotDataException e1) {
      Logger.error(RemotePublishAjaxAction.class, e1.getMessage(), e1);
      response.sendError(401);
      return;
    }
    Map<String, String> map = getURIParams();
    response.setContentType("application/x-tgz");

    String bid = map.get("bid");

    PublisherConfig config = new PublisherConfig();
    config.setId(bid);
    File bundleRoot = BundlerUtil.getBundleRoot(config);

    ArrayList<File> list = new ArrayList<File>(1);
    list.add(bundleRoot);
    File bundle =
        new File(bundleRoot + File.separator + ".." + File.separator + config.getId() + ".tar.gz");
    if (!bundle.exists()) {
      response.sendError(500, "No Bundle Found");
      return;
    }

    response.setHeader("Content-Disposition", "attachment; filename=" + config.getId() + ".tar.gz");
    BufferedInputStream in = null;
    try {
      in = new BufferedInputStream(new FileInputStream(bundle));
      byte[] buf = new byte[4096];
      int len;

      while ((len = in.read(buf, 0, buf.length)) != -1) {
        response.getOutputStream().write(buf, 0, len);
      }
    } catch (Exception e) {
      Logger.warn(this.getClass(), "Error Downloading Bundle.", e);
    } finally {
      try {
        in.close();
      } catch (Exception ex) {
        Logger.warn(this.getClass(), "Error Closing Stream.", ex);
      }
    }
    return;
  }
  /**
   * Publish a given Bundle file
   *
   * @param request HttpRequest
   * @param response HttpResponse
   * @throws FileUploadException If fails uploading the file
   * @throws IOException If fails reading the given File content or sending back to the user a
   *     response
   */
  public void uploadBundle(HttpServletRequest request, HttpServletResponse response)
      throws FileUploadException, IOException {

    try {
      if (!APILocator.getLayoutAPI()
          .doesUserHaveAccessToPortlet("EXT_CONTENT_PUBLISHING_TOOL", getUser())) {
        response.sendError(401);
        return;
      }
    } catch (DotDataException e1) {
      Logger.error(RemotePublishAjaxAction.class, e1.getMessage(), e1);
      response.sendError(401);
      return;
    }

    FileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload upload = new ServletFileUpload(factory);
    @SuppressWarnings("unchecked")
    List<FileItem> items = (List<FileItem>) upload.parseRequest(request);

    InputStream bundle = items.get(0).getInputStream();
    String bundleName = items.get(0).getName();
    String bundlePath = ConfigUtils.getBundlePath() + File.separator;
    String bundleFolder = bundleName.substring(0, bundleName.indexOf(".tar.gz"));
    String endpointId = getUser().getUserId();
    response.setContentType("text/html; charset=utf-8");
    PrintWriter out = response.getWriter();

    PublishAuditStatus status;
    try {
      status = PublishAuditAPI.getInstance().updateAuditTable(endpointId, null, bundleFolder);

      // Write file on FS
      FileUtil.writeToFile(bundle, bundlePath + bundleName);

      if (!status.getStatus().equals(Status.PUBLISHING_BUNDLE)) {
        new Thread(new PublishThread(bundleName, null, endpointId, status)).start();
      }

      out.print(
          "<html><head><script>isLoaded = true;</script></head><body><textarea>{'status':'success'}</textarea></body></html>");

    } catch (DotPublisherException e) {
      // TODO Auto-generated catch block
      out.print(
          "<html><head><script>isLoaded = true;</script></head><body><textarea>{'status':'error'}</textarea></body></html>");
    }
  }
  /** Returns the list of ids the user is trying to remote publish. */
  private List<String> getIdsToPush(
      List<String> assetIds, String _contentFilterDate, SimpleDateFormat dateFormat)
      throws ParseException, DotDataException {

    List<String> ids = new ArrayList<String>();

    for (String _assetId : assetIds) {

      if (_assetId != null && !_assetId.trim().isEmpty()) {

        if (ids.contains(_assetId)) {
          continue;
        }

        // check for the categories
        if (_assetId.contains("user_") || _assetId.contains("users_")) { // Trying to publish users
          // If we are trying to push users a filter date must be available
          if (_assetId.contains("users_")) {
            Date filteringDate = dateFormat.parse(_contentFilterDate);
            // Get users where createdate >= ?
            List<String> usersIds =
                APILocator.getUserAPI().getUsersIdsByCreationDate(filteringDate, 0, -1);
            if (usersIds != null) {
              for (String id : usersIds) {
                ids.add("user_" + id);
              }
            }
          } else {
            ids.add(_assetId);
          }
        } else if (_assetId.equals("CAT")) {
          ids.add(_assetId);
        } else if (_assetId.contains(".jar")) { // Check for OSGI jar bundles
          ids.add(_assetId);
        } else {
          // if the asset is a folder put the inode instead of the identifier
          try {
            Folder folder = null;
            try {
              folder = APILocator.getFolderAPI().find(_assetId, getUser(), false);
            } catch (DotSecurityException e) {
              Logger.error(
                  getClass(),
                  "User: "******" does not have permission to access folder. Folder identifier: "
                      + _assetId);
            } catch (DotDataException e) {
              Logger.info(getClass(), "FolderAPI.find(): Identifier is null");
            }

            if (folder != null && UtilMethods.isSet(folder.getInode())) {
              ids.add(_assetId);
            } else {
              // if the asset is not a folder and has identifier, put it, if not, put the inode
              Identifier iden = APILocator.getIdentifierAPI().findFromInode(_assetId);
              if (!ids.contains(iden.getId())) { // Multiples languages have the same identifier
                ids.add(iden.getId());
              }
            }

          } catch (DotStateException e) {
            ids.add(_assetId);
          }
        }
      }
    }

    return ids;
  }
  /**
   * Updates the assets in the given bundle with the publish/expire dates and destination
   * environments and set them ready to be pushed
   *
   * @param request HttpRequest
   * @param response HttpResponse
   * @throws WorkflowActionFailureException If fails trying to Publish the bundle contents
   */
  public void pushBundle(HttpServletRequest request, HttpServletResponse response)
      throws WorkflowActionFailureException, IOException {
    response.setContentType("text/plain");
    try {

      PublisherAPI publisherAPI = PublisherAPI.getInstance();

      // Read the form values
      String bundleId = request.getParameter("assetIdentifier");
      String _contentPushPublishDate = request.getParameter("remotePublishDate");
      String _contentPushPublishTime = request.getParameter("remotePublishTime");
      String _contentPushExpireDate = request.getParameter("remotePublishExpireDate");
      String _contentPushExpireTime = request.getParameter("remotePublishExpireTime");
      String _iWantTo = request.getParameter("iWantTo");
      String whoToSendTmp = request.getParameter("whoToSend");
      List<String> whereToSend = Arrays.asList(whoToSendTmp.split(","));
      List<Environment> envsToSendTo = new ArrayList<Environment>();

      // Lists of Environments to push to
      for (String envId : whereToSend) {
        Environment e = APILocator.getEnvironmentAPI().findEnvironmentById(envId);

        if (e != null
            && APILocator.getPermissionAPI()
                .doesUserHavePermission(e, PermissionAPI.PERMISSION_USE, getUser())) {
          envsToSendTo.add(e);
        }
      }

      if (envsToSendTo.isEmpty()) {
        response.sendError(HttpServletResponse.SC_FORBIDDEN);
        return;
      }

      // Put the selected environments in session in order to have the list of the last selected
      // environments
      request.getSession().setAttribute(WebKeys.SELECTED_ENVIRONMENTS, envsToSendTo);
      // Clean up the selected bundle
      request.getSession().removeAttribute(WebKeys.SELECTED_BUNDLE);

      SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-H-m");
      Date publishDate = dateFormat.parse(_contentPushPublishDate + "-" + _contentPushPublishTime);
      Bundle bundle = APILocator.getBundleAPI().getBundleById(bundleId);
      APILocator.getBundleAPI().saveBundleEnvironments(bundle, envsToSendTo);

      if (_iWantTo.equals(RemotePublishAjaxAction.DIALOG_ACTION_PUBLISH)) {
        bundle.setPublishDate(publishDate);
        APILocator.getBundleAPI().updateBundle(bundle);

        publisherAPI.publishBundleAssets(bundle.getId(), publishDate);

      } else if (_iWantTo.equals(RemotePublishAjaxAction.DIALOG_ACTION_EXPIRE)) {
        if ((!"".equals(_contentPushExpireDate.trim())
            && !"".equals(_contentPushExpireTime.trim()))) {
          Date expireDate = dateFormat.parse(_contentPushExpireDate + "-" + _contentPushExpireTime);
          bundle.setExpireDate(expireDate);
          APILocator.getBundleAPI().updateBundle(bundle);

          publisherAPI.unpublishBundleAssets(bundle.getId(), expireDate);
        }

      } else if (_iWantTo.equals(RemotePublishAjaxAction.DIALOG_ACTION_PUBLISH_AND_EXPIRE)) {
        if ((!"".equals(_contentPushExpireDate.trim())
            && !"".equals(_contentPushExpireTime.trim()))) {
          Date expireDate = dateFormat.parse(_contentPushExpireDate + "-" + _contentPushExpireTime);
          bundle.setPublishDate(publishDate);
          bundle.setExpireDate(expireDate);
          APILocator.getBundleAPI().updateBundle(bundle);

          publisherAPI.publishAndExpireBundleAssets(
              bundle.getId(), publishDate, expireDate, getUser());
        }
      }

    } catch (Exception e) {
      Logger.error(RemotePublishAjaxAction.class, e.getMessage(), e);
      response.sendError(
          HttpStatus.SC_INTERNAL_SERVER_ERROR, "Error Push Publishing Bundle: " + e.getMessage());
    }
  }
  /**
   * Adds to an specific given bundle a given asset. <br>
   * If the given bundle does not exist a new onw will be created with that name
   *
   * @param request HttpRequest
   * @param response HttpResponse
   */
  public void addToBundle(HttpServletRequest request, HttpServletResponse response)
      throws IOException {

    PublisherAPI publisherAPI = PublisherAPI.getInstance();
    String _assetId = request.getParameter("assetIdentifier");
    String _contentFilterDate = request.getParameter("remoteFilterDate");
    String bundleName = request.getParameter("bundleName");
    String bundleId = request.getParameter("bundleSelect");

    try {
      Bundle bundle;

      if (bundleId == null || bundleName.equals(bundleId)) {
        // if the user has a unsent bundle with that name just add to it
        bundle = null;
        for (Bundle b :
            APILocator.getBundleAPI()
                .getUnsendBundlesByName(getUser().getUserId(), bundleName, 1000, 0)) {
          if (b.getName().equalsIgnoreCase(bundleName)) {
            bundle = b;
          }
        }

        if (bundle == null) {
          bundle = new Bundle(bundleName, null, null, getUser().getUserId());
          APILocator.getBundleAPI().saveBundle(bundle);
        }
      } else {
        bundle = APILocator.getBundleAPI().getBundleById(bundleId);
      }

      // Put the selected bundle in session in order to have last one selected
      request.getSession().setAttribute(WebKeys.SELECTED_BUNDLE, bundle);

      List<String> ids;
      if (_assetId.startsWith("query_")) { // Support for lucene queries

        String luceneQuery = _assetId.replace("query_", "");
        List<String> queries = new ArrayList<String>();
        queries.add(luceneQuery);
        ids = PublisherUtil.getContentIds(queries);

      } else {

        String[] _assetsIds =
            _assetId.split(","); // Support for multiple ids in the assetIdentifier parameter
        List<String> assetsIds = Arrays.asList(_assetsIds);

        ids = getIdsToPush(assetsIds, _contentFilterDate, new SimpleDateFormat("yyyy-MM-dd-H-m"));
      }

      Map<String, Object> responseMap =
          publisherAPI.saveBundleAssets(ids, bundle.getId(), getUser());

      // If we have errors lets return them in order to feedback the user
      if (responseMap != null && !responseMap.isEmpty()) {

        // Error messages
        JSONArray jsonErrors = new JSONArray((ArrayList) responseMap.get("errorMessages"));

        // Prepare the Json response
        JSONObject jsonResponse = new JSONObject();
        jsonResponse.put("errorMessages", jsonErrors.toArray());
        jsonResponse.put("errors", responseMap.get("errors"));
        jsonResponse.put("total", responseMap.get("total"));

        // And send it back to the user
        response.getWriter().println(jsonResponse.toString());
      }
    } catch (Exception e) {
      Logger.error(RemotePublishAjaxAction.class, e.getMessage(), e);
      response.sendError(
          HttpStatus.SC_INTERNAL_SERVER_ERROR, "Error Adding content to Bundle: " + e.getMessage());
    }
  }
  @Override
  public void service(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    Map<String, String> map = getURIParams();
    String cmd = map.get("cmd");
    Method dispatchMethod = null;

    User user = getUser();

    try {
      // Check permissions if the user has access to the CMS Maintenance Portlet
      if (user == null) {
        String userName =
            map.get("u") != null ? map.get("u") : map.get("user") != null ? map.get("user") : null;

        String password =
            map.get("p") != null
                ? map.get("p")
                : map.get("passwd") != null ? map.get("passwd") : null;

        LoginFactory.doLogin(userName, password, false, request, response);
        user = (User) request.getSession().getAttribute(WebKeys.CMS_USER);
        // Set the logged user in order to make it available from this action using the getUser()
        // method
        if (user != null) {
          setUser(user);
        }

        if (user == null) {
          setUser(request);
          user = getUser();
        }
        if (user == null) {
          response.sendError(401);
          return;
        }
      }
    } catch (Exception e) {
      Logger.error(this.getClass(), e.getMessage());
      response.sendError(401);
      return;
    }

    if (null != cmd) {
      try {
        dispatchMethod =
            this.getClass()
                .getMethod(cmd, new Class[] {HttpServletRequest.class, HttpServletResponse.class});
      } catch (Exception e) {
        try {
          dispatchMethod =
              this.getClass()
                  .getMethod(
                      "action", new Class[] {HttpServletRequest.class, HttpServletResponse.class});
        } catch (Exception e1) {
          Logger.error(this.getClass(), "Trying to get method:" + cmd);
          Logger.error(this.getClass(), e1.getMessage(), e1.getCause());
          throw new DotRuntimeException(e1.getMessage());
        }
      }
      try {
        dispatchMethod.invoke(this, new Object[] {request, response});
      } catch (Exception e) {
        Logger.error(this.getClass(), "Trying to invoke method:" + cmd);
        Logger.error(this.getClass(), e.getMessage(), e.getCause());
        throw new DotRuntimeException(e.getMessage());
      }
    }
  }
  /**
   * Generates and flush an Unpublish bundle for a given bundle id and operation (publish/unpublish)
   *
   * @param request HttpRequest
   * @param response HttpResponse
   * @throws IOException If fails sending back to the user response information
   */
  public void downloadUnpushedBundle(HttpServletRequest request, HttpServletResponse response)
      throws IOException {
    try {
      if (!APILocator.getLayoutAPI()
          .doesUserHaveAccessToPortlet("EXT_CONTENT_PUBLISHING_TOOL", getUser())) {
        response.sendError(401);
        return;
      }
    } catch (DotDataException e1) {
      Logger.error(RemotePublishAjaxAction.class, e1.getMessage(), e1);
      response.sendError(401);
      return;
    }
    // Read the parameters
    Map<String, String> map = getURIParams();
    String bundleId = map.get("bundleId");
    String paramOperation = map.get("operation");
    if (bundleId == null || bundleId.isEmpty()) {
      Logger.error(this.getClass(), "No Bundle Found with id: " + bundleId);
      response.sendError(500, "No Bundle Found with id: " + bundleId);
      return;
    }

    // What we want to do with this bundle
    PushPublisherConfig.Operation operation = PushPublisherConfig.Operation.PUBLISH;
    if (paramOperation != null && paramOperation.equalsIgnoreCase("unpublish")) {
      operation = PushPublisherConfig.Operation.UNPUBLISH;
    }

    File bundle;
    String generatedBundleId;
    try {
      // Generate the bundle file for this given operation
      Map<String, Object> bundleData = generateBundle(bundleId, operation);
      bundle = (File) bundleData.get("file");
      generatedBundleId = (String) bundleData.get("id");
    } catch (Exception e) {
      Logger.error(this.getClass(), "Error trying to generate bundle with id: " + bundleId, e);
      response.sendError(500, "Error trying to generate bundle with id: " + bundleId);
      return;
    }

    response.setContentType("application/x-tgz");
    response.setHeader("Content-Disposition", "attachment; filename=" + bundle.getName());
    BufferedInputStream in = null;
    try {
      in = new BufferedInputStream(new FileInputStream(bundle));
      byte[] buf = new byte[4096];
      int len;

      while ((len = in.read(buf, 0, buf.length)) != -1) {
        response.getOutputStream().write(buf, 0, len);
      }
    } catch (Exception e) {
      Logger.error(this.getClass(), "Error reading bundle stream for bundle id: " + bundleId, e);
      response.sendError(500, "Error reading bundle stream for bundle id: " + bundleId);
    } finally {
      try {
        in.close();
      } catch (Exception ex) {
        Logger.error(this.getClass(), "Error closing Stream for bundle: " + bundleId, ex);
      }

      // Clean the just created bundle because on each download we will generate a new bundle file
      // with a new id in order to avoid conflicts with ids
      File bundleRoot = BundlerUtil.getBundleRoot(generatedBundleId);
      File compressedBundle =
          new File(ConfigUtils.getBundlePath() + File.separator + generatedBundleId + ".tar.gz");
      if (compressedBundle.exists()) {
        compressedBundle.delete();
        if (bundleRoot.exists()) {
          com.liferay.util.FileUtil.deltree(bundleRoot);
        }
      }
    }
  }
  /**
   * Allow the user to send or try to send again failed and successfully sent bundles, in order to
   * do that<br>
   * we send the bundle again to que publisher queue job which will try to remote publish again the
   * bundle.
   *
   * @param request HttpRequest
   * @param response HttpResponse
   * @throws IOException If fails sending back to the user a proper response
   * @throws DotPublisherException If fails retrieving the Bundle related information like elements
   *     on it and statuses
   * @throws LanguageException If fails using i18 messages
   */
  public void retry(HttpServletRequest request, HttpServletResponse response)
      throws IOException, DotPublisherException, LanguageException {

    PublisherAPI publisherAPI = PublisherAPI.getInstance();
    PublishAuditAPI publishAuditAPI = PublishAuditAPI.getInstance();

    // Read the parameters
    String bundlesIds = request.getParameter("bundlesIds");
    String[] ids = bundlesIds.split(",");

    StringBuilder responseMessage = new StringBuilder();

    for (String bundleId : ids) {

      if (bundleId.trim().isEmpty()) {
        continue;
      }

      PublisherConfig basicConfig = new PublisherConfig();
      basicConfig.setId(bundleId);
      File bundleRoot = BundlerUtil.getBundleRoot(basicConfig);

      // Get the audit records related to this bundle
      PublishAuditStatus status = PublishAuditAPI.getInstance().getPublishAuditStatus(bundleId);
      String pojo_string = status.getStatusPojo().getSerialized();
      PublishAuditHistory auditHistory = PublishAuditHistory.getObjectFromString(pojo_string);

      // First we need to verify is this bundle is already in the queue job
      List<PublishQueueElement> foundBundles = publisherAPI.getQueueElementsByBundleId(bundleId);
      if (foundBundles != null && !foundBundles.isEmpty()) {
        appendMessage(responseMessage, "publisher_retry.error.already.in.queue", bundleId, true);
        continue;
      }

      // We will be able to retry failed and successfully bundles
      if (!(status.getStatus().equals(Status.FAILED_TO_PUBLISH)
          || status.getStatus().equals(Status.SUCCESS))) {
        appendMessage(responseMessage, "publisher_retry.error.only.failed.publish", bundleId, true);
        continue;
      }

      /*
      Verify if the bundle exist and was created correctly..., meaning, if there is not a .tar.gz file is because
      something happened on the creation of the bundle.
       */
      File bundleFile =
          new File(
              bundleRoot
                  + File.separator
                  + ".."
                  + File.separator
                  + basicConfig.getId()
                  + ".tar.gz");
      if (!bundleFile.exists()) {
        Logger.error(this.getClass(), "No Bundle with id: " + bundleId + " found.");
        appendMessage(responseMessage, "publisher_retry.error.not.found", bundleId, true);
        continue;
      }

      if (!BundlerUtil.bundleExists(basicConfig)) {
        Logger.error(
            this.getClass(), "No Bundle Descriptor for bundle id: " + bundleId + " found.");
        appendMessage(
            responseMessage, "publisher_retry.error.not.descriptor.found", bundleId, true);
        continue;
      }

      try {

        // Read the bundle to see what kind of configuration we need to apply
        String bundlePath = ConfigUtils.getBundlePath() + File.separator + basicConfig.getId();
        File xml = new File(bundlePath + File.separator + "bundle.xml");
        PushPublisherConfig config = (PushPublisherConfig) BundlerUtil.xmlToObject(xml);

        // We can not retry Received Bundles, just bundles that we are trying to send
        Boolean sending = sendingBundle(request, config, bundleId);
        if (!sending) {
          appendMessage(
              responseMessage, "publisher_retry.error.cannot.retry.received", bundleId, true);
          continue;
        }

        if (status.getStatus().equals(Status.SUCCESS)) {

          // Get the bundle
          Bundle bundle = APILocator.getBundleAPI().getBundleById(bundleId);
          if (bundle == null) {
            Logger.error(this.getClass(), "No Bundle with id: " + bundleId + " found.");
            appendMessage(responseMessage, "publisher_retry.error.not.found", bundleId, true);
            continue;
          }
          bundle.setForcePush(true);
          APILocator.getBundleAPI().updateBundle(bundle);
        }

        // Clean the number of tries, we want to try it again
        auditHistory.setNumTries(0);
        publishAuditAPI.updatePublishAuditStatus(
            config.getId(), status.getStatus(), auditHistory, true);

        // Get the identifiers on this bundle
        HashSet<String> identifiers = new HashSet<String>();
        List<PublishQueueElement> assets = config.getAssets();
        if (config.getLuceneQueries() != null && !config.getLuceneQueries().isEmpty()) {
          identifiers.addAll(PublisherUtil.getContentIds(config.getLuceneQueries()));
        }
        if (assets != null && !assets.isEmpty()) {
          for (PublishQueueElement asset : assets) {
            identifiers.add(asset.getAsset());
          }
        }

        // Now depending of the operation lets add it to the queue job
        if (config.getOperation().equals(PushPublisherConfig.Operation.PUBLISH)) {
          publisherAPI.addContentsToPublish(
              new ArrayList<String>(identifiers), bundleId, new Date(), getUser());
        } else {
          publisherAPI.addContentsToUnpublish(
              new ArrayList<String>(identifiers), bundleId, new Date(), getUser());
        }

        // Success...
        appendMessage(responseMessage, "publisher_retry.success", bundleId, false);
      } catch (Exception e) {
        Logger.error(
            this.getClass(),
            "Error trying to add bundle id: " + bundleId + " to the Publishing Queue.",
            e);
        appendMessage(responseMessage, "publisher_retry.error.adding.to.queue", bundleId, true);
      }
    }

    response.getWriter().println(responseMessage.toString());
  }
  /**
   * Send to the publisher queue a list of assets for a given Operation (Publish/Unpublish) and
   * {@link Environment Environment}
   *
   * @param request HttpRequest
   * @param response HttpResponse
   * @throws WorkflowActionFailureException If fails adding the content for Publish
   * @see com.dotcms.publisher.business.PublisherQueueJob
   * @see Environment
   */
  public void publish(HttpServletRequest request, HttpServletResponse response)
      throws IOException, WorkflowActionFailureException {

    try {

      PublisherAPI publisherAPI = PublisherAPI.getInstance();

      // Read the form values
      String _assetId = request.getParameter("assetIdentifier");
      String _contentPushPublishDate = request.getParameter("remotePublishDate");
      String _contentPushPublishTime = request.getParameter("remotePublishTime");
      String _contentPushExpireDate = request.getParameter("remotePublishExpireDate");
      String _contentPushExpireTime = request.getParameter("remotePublishExpireTime");
      String _contentFilterDate = request.getParameter("remoteFilterDate");
      String _iWantTo = request.getParameter("iWantTo");
      String whoToSendTmp = request.getParameter("whoToSend");
      String forcePushStr = request.getParameter("forcePush");
      boolean forcePush = (forcePushStr != null && forcePushStr.equals("true"));
      List<String> whereToSend = Arrays.asList(whoToSendTmp.split(","));
      List<Environment> envsToSendTo = new ArrayList<Environment>();

      // Lists of Environments to push to
      for (String envId : whereToSend) {
        Environment e = APILocator.getEnvironmentAPI().findEnvironmentById(envId);

        if (e != null) {
          envsToSendTo.add(e);
        }
      }

      // Put the selected environments in session in order to have the list of the last selected
      // environments
      request.getSession().setAttribute(WebKeys.SELECTED_ENVIRONMENTS, envsToSendTo);

      SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-H-m");
      Date publishDate = dateFormat.parse(_contentPushPublishDate + "-" + _contentPushPublishTime);

      List<String> ids;
      if (_assetId.startsWith("query_")) { // Support for lucene queries

        String luceneQuery = _assetId.replace("query_", "");
        List<String> queries = new ArrayList<String>();
        queries.add(luceneQuery);
        ids = PublisherUtil.getContentIds(queries);

      } else {

        String[] _assetsIds =
            _assetId.split(","); // Support for multiple ids in the assetIdentifier parameter
        List<String> assetsIds = Arrays.asList(_assetsIds);

        ids = getIdsToPush(assetsIds, _contentFilterDate, dateFormat);
      }

      // Response map with the status of the addContents operation (error messages and counts )
      Map<String, Object> responseMap = null;

      if (_iWantTo.equals(RemotePublishAjaxAction.DIALOG_ACTION_PUBLISH)
          || _iWantTo.equals(RemotePublishAjaxAction.DIALOG_ACTION_PUBLISH_AND_EXPIRE)) {
        Bundle bundle = new Bundle(null, publishDate, null, getUser().getUserId(), forcePush);
        APILocator.getBundleAPI().saveBundle(bundle, envsToSendTo);

        responseMap =
            publisherAPI.addContentsToPublish(ids, bundle.getId(), publishDate, getUser());
      }
      if (_iWantTo.equals(RemotePublishAjaxAction.DIALOG_ACTION_EXPIRE)
          || _iWantTo.equals(RemotePublishAjaxAction.DIALOG_ACTION_PUBLISH_AND_EXPIRE)) {
        if ((!"".equals(_contentPushExpireDate.trim())
            && !"".equals(_contentPushExpireTime.trim()))) {
          Date expireDate = dateFormat.parse(_contentPushExpireDate + "-" + _contentPushExpireTime);

          Bundle bundle =
              new Bundle(null, publishDate, expireDate, getUser().getUserId(), forcePush);
          APILocator.getBundleAPI().saveBundle(bundle, envsToSendTo);

          responseMap =
              publisherAPI.addContentsToUnpublish(ids, bundle.getId(), expireDate, getUser());
        }
      }

      // If we have errors lets return them in order to feedback the user
      if (responseMap != null && !responseMap.isEmpty()) {

        // Error messages
        JSONArray jsonErrors = new JSONArray((ArrayList) responseMap.get("errorMessages"));

        // Prepare the Json response
        JSONObject jsonResponse = new JSONObject();
        jsonResponse.put("errorMessages", jsonErrors.toArray());
        jsonResponse.put("errors", responseMap.get("errors"));
        jsonResponse.put("total", responseMap.get("total"));
        jsonResponse.put("bundleId", responseMap.get("bundleId"));

        // And send it back to the user
        response.getWriter().println(jsonResponse.toString());
      }
    } catch (Exception e) {
      Logger.error(RemotePublishAjaxAction.class, e.getMessage(), e);
      response.sendError(
          HttpStatus.SC_INTERNAL_SERVER_ERROR, "Error Publishing Bundle: " + e.getMessage());
    }
  }