content: /*
   * This library is part of OpenCms -
   * the Open Source Content Management System
   *
   * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com)
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * Lesser General Public License for more details.
   *
   * For further information about Alkacon Software GmbH & Co. KG, please see the
   * company website: https://www.alkacon.com
   *
   * For further information about OpenCms, please see the
   * project website: https://www.opencms.org
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
  
  package org.opencms.staticexport;
  
  import org.opencms.ade.detailpage.CmsDetailPageUtil;
  import org.opencms.db.CmsPublishedResource;
  import org.opencms.file.CmsObject;
  import org.opencms.file.CmsResource;
  import org.opencms.file.CmsResourceFilter;
  import org.opencms.file.CmsVfsResourceNotFoundException;
  import org.opencms.loader.I_CmsResourceLoader;
  import org.opencms.main.CmsException;
  import org.opencms.main.CmsLog;
  import org.opencms.main.OpenCms;
  import org.opencms.report.I_CmsReport;
  import org.opencms.util.CmsFileUtil;
  import org.opencms.util.CmsRequestUtil;
  import org.opencms.util.CmsStringUtil;
  import org.opencms.util.CmsUUID;
  import org.opencms.workplace.CmsWorkplace;
  
  import java.io.File;
  import java.io.IOException;
  import java.net.HttpURLConnection;
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServletResponse;
  
  import org.apache.commons.logging.Log;
  
  /**
   * Implementation for the <code>{@link I_CmsStaticExportHandler}</code> interface.<p>
   *
   * This handler exports all changes immediately after something is published.<p>
   *
   * @since 6.0.0
   *
   * @see I_CmsStaticExportHandler
   */
  public class CmsAfterPublishStaticExportHandler extends A_CmsStaticExportHandler {
  
      /** Header field set-cookie constant. */
      private static final String HEADER_FIELD_SET_COOKIE = "Set-Cookie";
  
      /** The log object for this class. */
      private static final Log LOG = CmsLog.getLog(CmsAfterPublishStaticExportHandler.class);
  
      /** Request method get constant. */
      private static final String REQUEST_METHOD_GET = "GET";
  
      /** Request property cookie constant. */
      private static final String REQUEST_PROPERTY_COOKIE = "Cookie";
  
      /**
       * Does the actual static export.<p>
       *
       * @param resources a list of CmsPublishedREsources to start the static export with
       * @param report an <code>{@link I_CmsReport}</code> instance to print output message, or <code>null</code> to write messages to the log file
       *
       * @throws CmsException in case of errors accessing the VFS
       * @throws IOException in case of errors writing to the export output stream
       * @throws ServletException in case of errors accessing the servlet
       */
      public void doExportAfterPublish(List<CmsPublishedResource> resources, I_CmsReport report)
      throws CmsException, IOException, ServletException {
  
          boolean templatesFound;
  
          // export must be done in the context of the export user
          // this will always use the root site
          CmsObject cmsExportObject = OpenCms.initCmsObject(OpenCms.getDefaultUsers().getUserExport());
  
          List<CmsPublishedResource> resourcesToExport = getRelatedResources(cmsExportObject, resources);
          // first export all non-template resources
          templatesFound = exportNonTemplateResources(cmsExportObject, resourcesToExport, report);
          LOG.warn("finished exporting non-template resources. ");
  
          // export template resources (check "plainoptimization" setting)
          if ((templatesFound) || (!OpenCms.getStaticExportManager().getQuickPlainExport())) {
              CmsStaticExportManager manager = OpenCms.getStaticExportManager();
  
              // build resource filter set
              Set<String> resourceFilter = new HashSet<String>();
              for (CmsPublishedResource pubResource : resourcesToExport) {
                  String rfsName = manager.getRfsName(cmsExportObject, pubResource.getRootPath());
                  resourceFilter.add(rfsName.substring(manager.getRfsPrefixForRfsName(rfsName).length()));
              }
  
              long timestamp = 0;
              List<String> publishedTemplateResources;
              boolean newTemplateLinksFound;
              int linkMode = CmsStaticExportManager.EXPORT_LINK_WITHOUT_PARAMETER;
              do {
                  // get all template resources which are potential candidates for a static export
                  publishedTemplateResources = cmsExportObject.readStaticExportResources(linkMode, timestamp);
                  if (publishedTemplateResources == null) {
                      break;
                  }
                  newTemplateLinksFound = publishedTemplateResources.size() > 0;
                  if (newTemplateLinksFound) {
                      if (linkMode == CmsStaticExportManager.EXPORT_LINK_WITHOUT_PARAMETER) {
                          // first loop, switch mode to parameter links, leave the timestamp unchanged
                          linkMode = CmsStaticExportManager.EXPORT_LINK_WITH_PARAMETER;
                          // filter without parameter
                          publishedTemplateResources.retainAll(resourceFilter);
                      } else {
                          // second and subsequent loops, only look for links not already exported
                          // this can only be the case for a link with parameters
                          // that was present on a page also generated with parameters
                          timestamp = System.currentTimeMillis();
                          // filter with parameter
                          Iterator<String> itPubTemplates = publishedTemplateResources.iterator();
                          while (itPubTemplates.hasNext()) {
                              String rfsName = itPubTemplates.next();
                              if (!resourceFilter.contains(rfsName.substring(0, rfsName.lastIndexOf('_')))) {
                                  itPubTemplates.remove();
                              }
                          }
                      }
                      // leave if no template left
                      if (publishedTemplateResources.isEmpty()) {
                          break;
                      }
                      // export
                      LOG.warn("exporting template resources. ");
                      exportTemplateResources(cmsExportObject, publishedTemplateResources, report);
                  }
                  // if no new template links where found we are finished
              } while (newTemplateLinksFound);
          }
      }
  
      /**
       * Returns all resources within the current OpenCms site that are not marked as internal.<p>
       *
       * The result list contains objects of type {@link CmsPublishedResource}.<p>
       *
       * @param cms the cms context
       *
       * @return all resources within the current OpenCms site that are not marked as internal
       *
       * @throws CmsException if something goes wrong
       */
      public List<CmsPublishedResource> getAllResources(CmsObject cms) throws CmsException {
  
          if (LOG.isDebugEnabled()) {
              LOG.debug(Messages.get().getBundle().key(Messages.LOG_GET_ALL_RESOURCES_0));
          }
          // TODO: to improve performance, get here only the resources to render from the configuration
  
          // read all from the root path, exclude resources flagged as internal
          List<CmsResource> vfsResources = cms.readResources(
              "/",
              CmsResourceFilter.ALL.addExcludeFlags(CmsResource.FLAG_INTERNAL));
  
          CmsExportFolderMatcher matcher = OpenCms.getStaticExportManager().getExportFolderMatcher();
          // loop through the list and create the list of CmsPublishedResources
          List<CmsPublishedResource> resources = new ArrayList<CmsPublishedResource>(vfsResources.size());
          Iterator<CmsResource> i = vfsResources.iterator();
          while (i.hasNext()) {
              CmsResource resource = i.next();
              if (!matcher.match(resource.getRootPath())) {
                  // filter files that do not match the resources to render
                  continue;
              }
              CmsPublishedResource pubRes = new CmsPublishedResource(resource);
              if (LOG.isDebugEnabled()) {
                  LOG.debug(Messages.get().getBundle().key(Messages.LOG_PROCESSING_1, resource.getRootPath()));
              }
              resources.add(pubRes);
          }
  
          if (LOG.isDebugEnabled()) {
              LOG.debug(Messages.get().getBundle().key(Messages.LOG_NUM_RESOURCES_1, Integer.valueOf(resources.size())));
          }
          return resources;
      }
  
      /**
       * @see org.opencms.staticexport.I_CmsStaticExportHandler#performEventPublishProject(org.opencms.util.CmsUUID, org.opencms.report.I_CmsReport)
       */
      @Override
      public void performEventPublishProject(CmsUUID publishHistoryId, I_CmsReport report) {
  
          try {
              m_busy = true;
              exportAfterPublish(publishHistoryId, report);
          } catch (Throwable t) {
              if (LOG.isErrorEnabled()) {
                  LOG.error(Messages.get().getBundle().key(Messages.LOG_STATIC_EXPORT_ERROR_0), t);
              }
              if (report != null) {
                  report.addError(t);
              }
          } finally {
              m_busy = false;
          }
      }
  
      /**
       * Starts the static export on publish.<p>
       *
       * Exports all modified resources after a publish process into the real FS.<p>
       *
       * @param publishHistoryId the publichHistoryId of the published project
       * @param report an <code>{@link I_CmsReport}</code> instance to print output message, or <code>null</code> to write messages to the log file
       *
       * @throws CmsException in case of errors accessing the VFS
       * @throws IOException in case of errors writing to the export output stream
       * @throws ServletException in case of errors accessing the servlet
       */
      protected void exportAfterPublish(CmsUUID publishHistoryId, I_CmsReport report)
      throws CmsException, IOException, ServletException {
  
          // first check if the test resource was published already
          // if not, we must do a complete export of all static resources
          String rfsName = CmsFileUtil.normalizePath(
              OpenCms.getStaticExportManager().getExportPath(OpenCms.getStaticExportManager().getTestResource())
                  + OpenCms.getStaticExportManager().getTestResource());
  
          if (LOG.isDebugEnabled()) {
              LOG.debug(Messages.get().getBundle().key(Messages.LOG_CHECKING_TEST_RESOURCE_1, rfsName));
          }
          File file = new File(rfsName);
          if (!file.exists()) {
              if (LOG.isDebugEnabled()) {
                  LOG.debug(Messages.get().getBundle().key(Messages.LOG_TEST_RESOURCE_NOT_EXISTANT_0));
              }
              // the file is not there, so export everything
              OpenCms.getStaticExportManager().exportFullStaticRender(true, report);
          } else {
              if (LOG.isDebugEnabled()) {
                  LOG.debug(Messages.get().getBundle().key(Messages.LOG_TEST_RESOURCE_EXISTS_0));
              }
  
              // delete all resources deleted during the publish process, and retrieve the list of resources to actually export
              List<CmsPublishedResource> publishedResources = scrubExportFolders(publishHistoryId);
  
              // do the export
              doExportAfterPublish(publishedResources, report);
          }
  
      }
  
      /**
       * Exports all non template resources found in a list of published resources.<p>
       *
       * @param cms the current cms object
       * @param publishedResources the list of published resources
       * @param report an I_CmsReport instance to print output message, or null to write messages to the log file
       *
       * @return true if some template resources were found while looping the list of published resources
       *
       * @throws CmsException in case of errors accessing the VFS
       * @throws IOException in case of errors writing to the export output stream
       * @throws ServletException in case of errors accessing the servlet
       */
      protected boolean exportNonTemplateResources(
          CmsObject cms,
          List<CmsPublishedResource> publishedResources,
          I_CmsReport report)
      throws CmsException, IOException, ServletException {
  
          report.println(
              Messages.get().container(Messages.RPT_STATICEXPORT_NONTEMPLATE_RESOURCES_BEGIN_0),
              I_CmsReport.FORMAT_HEADLINE);
  
          if (LOG.isDebugEnabled()) {
              LOG.debug(
                  Messages.get().getBundle().key(
                      Messages.LOG_EXPORTING_NON_TEMPLATE_1,
                      Integer.valueOf(publishedResources.size())));
          }
  
          CmsStaticExportManager manager = OpenCms.getStaticExportManager();
          List<CmsStaticExportData> resourcesToExport = new ArrayList<CmsStaticExportData>();
          boolean templatesFound = readNonTemplateResourcesToExport(cms, publishedResources, resourcesToExport);
  
          int count = 1;
          int size = resourcesToExport.size();
          if (LOG.isDebugEnabled()) {
              LOG.debug(Messages.get().getBundle().key(Messages.LOG_NUM_EXPORT_1, Integer.valueOf(size)));
          }
          // now do the export
          Iterator<CmsStaticExportData> i = resourcesToExport.iterator();
          while (i.hasNext()) {
              CmsStaticExportData exportData = i.next();
              if (LOG.isDebugEnabled()) {
                  LOG.debug(
                      Messages.get().getBundle().key(
                          Messages.LOG_EXPORT_FILE_2,
                          exportData.getVfsName(),
                          exportData.getRfsName()));
              }
  
              report.print(
                  org.opencms.report.Messages.get().container(
                      org.opencms.report.Messages.RPT_SUCCESSION_2,
                      Integer.valueOf(count++),
                      Integer.valueOf(size)),
                  I_CmsReport.FORMAT_NOTE);
              report.print(Messages.get().container(Messages.RPT_EXPORTING_0), I_CmsReport.FORMAT_NOTE);
              report.print(
                  org.opencms.report.Messages.get().container(
                      org.opencms.report.Messages.RPT_ARGUMENT_1,
                      exportData.getVfsName()));
              report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0));
              int status = -1;
              try {
                  status = manager.export(null, null, cms, exportData);
                  if (status == HttpServletResponse.SC_OK) {
                      report.println(
                          org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
                          I_CmsReport.FORMAT_OK);
                  } else {
                      report.println(
                          org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_IGNORED_0),
                          I_CmsReport.FORMAT_NOTE);
                  }
              } catch (CmsStaticExportException e) {
                  LOG.warn(e.getLocalizedMessage(), e);
                  report.println(
                      org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_IGNORED_0),
                      I_CmsReport.FORMAT_NOTE);
              }
  
              if (LOG.isInfoEnabled()) {
                  Object[] arguments = new Object[] {
                      exportData.getVfsName(),
                      exportData.getRfsName(),
                      Integer.valueOf(status)};
                  LOG.info(Messages.get().getBundle().key(Messages.LOG_EXPORT_FILE_STATUS_3, arguments));
              }
              //don't lock up the CPU exclusively - allow other Threads to run as well
              Thread.yield();
          }
  
          resourcesToExport = null;
  
          report.println(
              Messages.get().container(Messages.RPT_STATICEXPORT_NONTEMPLATE_RESOURCES_END_0),
              I_CmsReport.FORMAT_HEADLINE);
  
          return templatesFound;
      }
  
      /**
       * Exports all sitemap resources found in a list of published resources.<p>
       *
       * @param entry the sitemap entry
       * @param data the export data
       * @param cookies cookies to keep the session
       *
       * @return the status of the http request used to perform the export
       *
       * @throws IOException if something goes wrong
       */
      //    protected int exportSitemapResource(CmsSitemapEntry entry, CmsStaticExportData data, StringBuffer cookies)
      //    throws IOException {
      //
      //        String vfsName = data.getVfsName();
      //        String rfsName = data.getRfsName();
      //        CmsStaticExportManager manager = OpenCms.getStaticExportManager();
      //
      //        // check if the resource to export is a detail page
      //        // TODO: later when the property concept is finished this info is unnecessary
      //        String path = vfsName;
      //        boolean exportPropertyAlreadyReadFromVFS = false;
      //        if (path.endsWith("/")) {
      //            path = path.substring(0, path.length() - 1);
      //            String detailId = CmsResource.getName(path);
      //            if (CmsUUID.isValidUUID(detailId)) {
      //                exportPropertyAlreadyReadFromVFS = true;
      //            }
      //        }
      //
      //        try {
      //            CmsObject exportCms = OpenCms.initCmsObject(OpenCms.getDefaultUsers().getUserExport());
      //            Map<String, String> props = entry.getProperties(true);
      //            // if a container page was found in the vfs and
      //            if (((props.get("export") != null) && props.get("export").equals("true"))
      //                || exportPropertyAlreadyReadFromVFS) {
      //                // calculate rfs name
      //                rfsName = manager.getRfsName(exportCms, entry.getRootPath());
      //
      //                String exportUrlStr;
      //                if (rfsName.contains(manager.getRfsPrefix(vfsName))) {
      //                    exportUrlStr = manager.getExportUrl() + rfsName;
      //                } else {
      //                    exportUrlStr = manager.getExportUrl() + manager.getRfsPrefix(vfsName) + rfsName;
      //                }
      //                if (LOG.isDebugEnabled()) {
      //                    LOG.debug(Messages.get().getBundle().key(Messages.LOG_SENDING_REQUEST_2, rfsName, exportUrlStr));
      //                }
      //                // setup the connection and request the resource
      //                URL exportUrl = new URL(exportUrlStr);
      //                HttpURLConnection.setFollowRedirects(false);
      //                HttpURLConnection urlcon = (HttpURLConnection)exportUrl.openConnection();
      //                // set request type to GET
      //                urlcon.setRequestMethod(REQUEST_METHOD_GET);
      //                // add special export header
      //                urlcon.setRequestProperty(CmsRequestUtil.HEADER_OPENCMS_EXPORT, CmsStringUtil.TRUE);
      //                // add additional headers if available
      //                if (manager.getAcceptLanguageHeader() != null) {
      //                    urlcon.setRequestProperty(CmsRequestUtil.HEADER_ACCEPT_LANGUAGE, manager.getAcceptLanguageHeader());
      //                } else {
      //                    urlcon.setRequestProperty(
      //                        CmsRequestUtil.HEADER_ACCEPT_LANGUAGE,
      //                        manager.getDefaultAcceptLanguageHeader());
      //                }
      //                if (manager.getAcceptCharsetHeader() != null) {
      //                    urlcon.setRequestProperty(CmsRequestUtil.HEADER_ACCEPT_CHARSET, manager.getAcceptCharsetHeader());
      //                } else {
      //                    urlcon.setRequestProperty(
      //                        CmsRequestUtil.HEADER_ACCEPT_CHARSET,
      //                        manager.getDefaultAcceptCharsetHeader());
      //                }
      //
      //                // get the last modified date and add it to the request
      //                String exportFileName = CmsFileUtil.normalizePath(manager.getExportPath(vfsName) + rfsName);
      //                File exportFile = new File(exportFileName);
      //                long dateLastModified = exportFile.lastModified();
      //                // system folder case
      //                if (vfsName.startsWith(CmsWorkplace.VFS_PATH_SYSTEM)) {
      //                    // iterate over all rules
      //                    for (CmsStaticExportRfsRule rule : manager.getRfsRules()) {
      //                        if (rule.match(vfsName)) {
      //                            exportFileName = CmsFileUtil.normalizePath(rule.getExportPath() + rfsName);
      //                            exportFile = new File(exportFileName);
      //                            if (dateLastModified > exportFile.lastModified()) {
      //                                dateLastModified = exportFile.lastModified();
      //                            }
      //                        }
      //                    }
      //                }
      //                urlcon.setIfModifiedSince(dateLastModified);
      //                if (LOG.isDebugEnabled()) {
      //                    LOG.debug(Messages.get().getBundle().key(
      //                        Messages.LOG_IF_MODIFIED_SINCE_SET_2,
      //                        exportFile.getName(),
      //                        Long.valueOf((dateLastModified / 1000) * 1000)));
      //                }
      //                if (cookies.length() > 0) {
      //                    // set the cookies, included the session id to keep the same session
      //                    urlcon.setRequestProperty(REQUEST_PROPERTY_COOKIE, cookies.toString());
      //                }
      //
      //                // now perform the request
      //                urlcon.connect();
      //                int status = urlcon.getResponseCode();
      //
      //                if (cookies.length() == 0) {
      //                    //Now retrieve the cookies. The jsessionid is here
      //                    cookies.append(urlcon.getHeaderField(HEADER_FIELD_SET_COOKIE));
      //                    if (LOG.isDebugEnabled()) {
      //                        LOG.debug(Messages.get().getBundle().key(Messages.LOG_STATICEXPORT_COOKIES_1, cookies));
      //                    }
      //                }
      //                urlcon.disconnect();
      //                if (LOG.isInfoEnabled()) {
      //                    LOG.info(Messages.get().getBundle().key(
      //                        Messages.LOG_REQUEST_RESULT_3,
      //                        rfsName,
      //                        exportUrlStr,
      //                        Integer.valueOf(status)));
      //                }
      //                return status;
      //            }
      //        } catch (CmsException e) {
      //            LOG.error(e.getLocalizedMessage(), e);
      //        }
      //        return HttpServletResponse.SC_SEE_OTHER;
      //    }
  
      /**
       * Exports a single (template) resource specified by its export data.<p>
       *
       * @param data the export data
       * @param cookies cookies to keep the session
       *
       * @return the status of the http request used to perform the export
       *
       * @throws IOException if the http request fails
       */
      protected int exportTemplateResource(CmsStaticExportData data, StringBuffer cookies) throws IOException {
  
          String vfsName = data.getVfsName();
          String rfsName = data.getRfsName();
          CmsStaticExportManager manager = OpenCms.getStaticExportManager();
  
          String exportUrlStr;
          if (rfsName.contains(manager.getRfsPrefix(vfsName))) {
              LOG.info("rfsName " + rfsName + " contains rfsPrefix " + manager.getRfsPrefix(vfsName));
              exportUrlStr = manager.getExportUrl() + rfsName;
          } else {
              exportUrlStr = manager.getExportUrl() + manager.getRfsPrefix(vfsName) + rfsName;
          }
          if (LOG.isDebugEnabled()) {
              LOG.debug(Messages.get().getBundle().key(Messages.LOG_SENDING_REQUEST_2, rfsName, exportUrlStr));
          }
          // setup the connection and request the resource
          URL exportUrl = new URL(exportUrlStr);
          HttpURLConnection.setFollowRedirects(false);
          HttpURLConnection urlcon = (HttpURLConnection)exportUrl.openConnection();
          // set request type to GET
          urlcon.setRequestMethod(REQUEST_METHOD_GET);
          // add special export header
          urlcon.setRequestProperty(CmsRequestUtil.HEADER_OPENCMS_EXPORT, CmsStringUtil.TRUE);
          // add additional headers if available
          if (manager.getAcceptLanguageHeader() != null) {
              urlcon.setRequestProperty(CmsRequestUtil.HEADER_ACCEPT_LANGUAGE, manager.getAcceptLanguageHeader());
          } else {
              urlcon.setRequestProperty(CmsRequestUtil.HEADER_ACCEPT_LANGUAGE, manager.getDefaultAcceptLanguageHeader());
          }
          if (manager.getAcceptCharsetHeader() != null) {
              urlcon.setRequestProperty(CmsRequestUtil.HEADER_ACCEPT_CHARSET, manager.getAcceptCharsetHeader());
          } else {
              urlcon.setRequestProperty(CmsRequestUtil.HEADER_ACCEPT_CHARSET, manager.getDefaultAcceptCharsetHeader());
          }
  
          // get the last modified date and add it to the request
          String exportFileName = CmsFileUtil.normalizePath(manager.getExportPath(vfsName) + rfsName);
          File exportFile = new File(exportFileName);
          long dateLastModified = exportFile.lastModified();
          // system folder case
          if (vfsName.startsWith(CmsWorkplace.VFS_PATH_SYSTEM) || OpenCms.getSiteManager().startsWithShared(vfsName)) {
              // iterate over all rules
              Iterator<CmsStaticExportRfsRule> it = manager.getRfsRules().iterator();
              while (it.hasNext()) {
                  CmsStaticExportRfsRule rule = it.next();
                  if (rule.match(vfsName)) {
                      exportFileName = CmsFileUtil.normalizePath(rule.getExportPath() + rfsName);
                      exportFile = new File(exportFileName);
                      if (dateLastModified > exportFile.lastModified()) {
                          dateLastModified = exportFile.lastModified();
                      }
                  }
              }
          }
          urlcon.setIfModifiedSince(dateLastModified);
          if (LOG.isDebugEnabled()) {
              LOG.debug(
                  Messages.get().getBundle().key(
                      Messages.LOG_IF_MODIFIED_SINCE_SET_2,
                      exportFile.getName(),
                      Long.valueOf((dateLastModified / 1000) * 1000)));
          }
          if (cookies.length() > 0) {
              // set the cookies, included the session id to keep the same session
              urlcon.setRequestProperty(REQUEST_PROPERTY_COOKIE, cookies.toString());
          }
  
          // now perform the request
          urlcon.connect();
          int status = urlcon.getResponseCode();
  
          if (cookies.length() == 0) {
              //Now retrieve the cookies. The jsessionid is here
              cookies.append(urlcon.getHeaderField(HEADER_FIELD_SET_COOKIE));
              if (LOG.isDebugEnabled()) {
                  LOG.debug(Messages.get().getBundle().key(Messages.LOG_STATICEXPORT_COOKIES_1, cookies));
              }
          }
          urlcon.disconnect();
          if (LOG.isInfoEnabled()) {
              LOG.info(
                  Messages.get().getBundle().key(
                      Messages.LOG_REQUEST_RESULT_3,
                      rfsName,
                      exportUrlStr,
                      Integer.valueOf(status)));
          }
          return status;
      }
  
      /**
       * Exports all template resources found in a list of published resources.<p>
       *
       * @param cms the cms context, in the root site as Export user
       * @param publishedTemplateResources list of potential candidates to export
       * @param report an I_CmsReport instance to print output message, or null to write messages to the log file
       */
      protected void exportTemplateResources(CmsObject cms, List<String> publishedTemplateResources, I_CmsReport report) {
  
          CmsStaticExportManager manager = OpenCms.getStaticExportManager();
          int size = publishedTemplateResources.size();
          int count = 1;
  
          if (LOG.isDebugEnabled()) {
              LOG.debug(Messages.get().getBundle().key(Messages.LOG_EXPORT_TEMPLATES_1, Integer.valueOf(size)));
          }
          report.println(
              Messages.get().container(Messages.RPT_STATICEXPORT_TEMPLATE_RESOURCES_BEGIN_0),
              I_CmsReport.FORMAT_HEADLINE);
  
          StringBuffer cookies = new StringBuffer();
          // now loop through all of them and request them from the server
          Iterator<String> i = publishedTemplateResources.iterator();
          while (i.hasNext()) {
              String rfsName = i.next();
              CmsStaticExportData data = null;
              try {
                  data = manager.getVfsNameInternal(cms, rfsName);
              } catch (CmsVfsResourceNotFoundException e) {
                  String rfsBaseName = rfsName;
                  int pos = rfsName.lastIndexOf('_');
                  if (pos >= 0) {
                      rfsBaseName = rfsName.substring(0, pos);
                  }
                  try {
                      data = manager.getVfsNameInternal(cms, rfsBaseName);
                  } catch (CmsVfsResourceNotFoundException e2) {
                      if (LOG.isInfoEnabled()) {
                          LOG.info(
                              Messages.get().getBundle().key(
                                  Messages.LOG_NO_INTERNAL_VFS_RESOURCE_FOUND_1,
                                  new String[] {rfsName}));
                      }
                  }
              }
              if (data != null) {
                  data.setRfsName(rfsName);
                  report.print(
                      org.opencms.report.Messages.get().container(
                          org.opencms.report.Messages.RPT_SUCCESSION_2,
                          Integer.valueOf(count++),
                          Integer.valueOf(size)),
                      I_CmsReport.FORMAT_NOTE);
                  report.print(Messages.get().container(Messages.RPT_EXPORTING_0), I_CmsReport.FORMAT_NOTE);
                  report.print(
                      org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_ARGUMENT_1, rfsName));
                  report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0));
              } else {
                  // no valid resource found for rfs name (already deleted), skip it
                  continue;
              }
  
              try {
                  CmsResource resource = data.getResource();
                  try {
                      Collection<String> detailPages = CmsDetailPageUtil.getAllDetailPagesWithUrlName(cms, resource);
                      for (String detailPageUri : detailPages) {
                          String altRfsName = manager.getRfsName(cms, detailPageUri);
                          CmsStaticExportData detailData = new CmsStaticExportData(
                              data.getVfsName(),
                              altRfsName,
                              data.getResource(),
                              data.getParameters());
                          exportTemplateResource(detailData, cookies);
                      }
                  } catch (CmsException e) {
                      LOG.error(e.getLocalizedMessage(), e);
                  }
  
                  int status = exportTemplateResource(data, cookies);
  
                  // write the report
                  if (status == HttpServletResponse.SC_OK) {
                      report.println(
                          org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
                          I_CmsReport.FORMAT_OK);
                  } else if (status == HttpServletResponse.SC_NOT_MODIFIED) {
                      report.println(
                          org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_SKIPPED_0),
                          I_CmsReport.FORMAT_NOTE);
                  } else if (status == HttpServletResponse.SC_SEE_OTHER) {
                      report.println(
                          org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_IGNORED_0),
                          I_CmsReport.FORMAT_NOTE);
                  } else {
                      report.println(
                          org.opencms.report.Messages.get().container(
                              org.opencms.report.Messages.RPT_ARGUMENT_1,
                              Integer.valueOf(status)),
                          I_CmsReport.FORMAT_OK);
                  }
              } catch (IOException e) {
                  report.println(e);
              }
              //don't lock up the CPU exclusively - allow other Threads to run as well
              Thread.yield();
          }
          report.println(
              Messages.get().container(Messages.RPT_STATICEXPORT_TEMPLATE_RESOURCES_END_0),
              I_CmsReport.FORMAT_HEADLINE);
      }
  
      /**
       * @see org.opencms.staticexport.A_CmsStaticExportHandler#getRelatedFilesToPurge(java.lang.String, java.lang.String)
       */
      @Override
      protected List<File> getRelatedFilesToPurge(String exportFileName, String vfsName) {
  
          return Collections.emptyList();
      }
  
      /**
       * Creates a list of <code>{@link org.opencms.db.CmsPublishedResource}</code> objects containing all related resources of the VFS tree.<p>
       *
       * If the static export has been triggered by the OpenCms workplace, publishedResources is null and all resources in the VFS tree are returned.<p>
       * If really an after publish static export is triggered, then only the related resources are returned.<p>
       *
       * @param cms the current cms object
       * @param publishedResources the list of published resources
       *
       * @return list of CmsPulishedResource objects containing all resources of the VFS tree
       *
       * @throws CmsException in case of errors accessing the VFS
       */
      protected List<CmsPublishedResource> getRelatedResources(
          CmsObject cms,
          List<CmsPublishedResource> publishedResources)
      throws CmsException {
  
          String storedSiteRoot = cms.getRequestContext().getSiteRoot();
          try {
              // switch to root site
              cms.getRequestContext().setSiteRoot("/");
              if (publishedResources == null) {
                  // full static export
                  return getAllResources(cms);
              } else {
                  // after publish export
                  Map<String, CmsPublishedResource> resourceMap = new HashMap<String, CmsPublishedResource>();
                  Iterator<CmsPublishedResource> itPubRes = publishedResources.iterator();
                  while (itPubRes.hasNext()) {
                      CmsPublishedResource pubResource = itPubRes.next();
                      // check the internal flag if the resource does still exist
                      // we cannot export with an internal flag
                      if (cms.existsResource(pubResource.getRootPath())) {
                          CmsResource vfsResource = cms.readResource(pubResource.getRootPath());
                          if (!vfsResource.isInternal()) {
                              // add only if not internal
                              // additionally, add all siblings of the resource
                              Iterator<CmsPublishedResource> itSiblings = getSiblings(cms, pubResource).iterator();
                              while (itSiblings.hasNext()) {
                                  CmsPublishedResource sibling = itSiblings.next();
                                  resourceMap.put(sibling.getRootPath(), sibling);
                              }
                          }
                      } else {
                          // the resource does not exist, so add them for deletion in the static export
                          resourceMap.put(pubResource.getRootPath(), pubResource);
                      }
  
                      boolean match = false;
                      Iterator<CmsStaticExportExportRule> itExportRules = OpenCms.getStaticExportManager().getExportRules().iterator();
                      while (itExportRules.hasNext()) {
                          CmsStaticExportExportRule rule = itExportRules.next();
                          Set<CmsPublishedResource> relatedResources = rule.getRelatedResources(cms, pubResource);
                          if (relatedResources != null) {
                              Iterator<CmsPublishedResource> itRelatedRes = relatedResources.iterator();
                              while (itRelatedRes.hasNext()) {
                                  CmsPublishedResource relatedRes = itRelatedRes.next();
                                  resourceMap.put(relatedRes.getRootPath(), relatedRes);
                              }
                              match = true;
                          }
                      }
                      // if one res does not match any rule, then export all files
                      if (!match) {
                          return getAllResources(cms);
                      }
                  }
                  return new ArrayList<CmsPublishedResource>(resourceMap.values());
              }
          } finally {
              cms.getRequestContext().setSiteRoot(storedSiteRoot);
          }
      }
  
      /**
       * Returns all siblings of the published resource as list of <code>CmsPublishedResource</code>.<p>
       *
       * @param cms the cms object
       * @param pubResource the published resource
       *
       * @return all siblings of the published resource
       *
       * @throws CmsException if something goes wrong
       */
      protected Set<CmsPublishedResource> getSiblings(CmsObject cms, CmsPublishedResource pubResource)
      throws CmsException {
  
          Set<CmsPublishedResource> siblings = new HashSet<CmsPublishedResource>();
          for (Iterator<String> i = getSiblingsList(cms, pubResource.getRootPath()).iterator(); i.hasNext();) {
              String sibling = i.next();
              siblings.add(new CmsPublishedResource(cms.readResource(sibling)));
          }
          return siblings;
      }
  
      /**
       * Returns all non template resources found in a list of published resources.<p>
       *
       * @param cms the current cms object
       * @param publishedResources the list of published resources
       * @param resourcesToExport the list of non-template resources
       *
       * @return <code>true</code> if some template resources were found while looping the list of published resources
       *
       * @throws CmsException in case of errors accessing the VFS
       */
      protected boolean readNonTemplateResourcesToExport(
          CmsObject cms,
          List<CmsPublishedResource> publishedResources,
          List<CmsStaticExportData> resourcesToExport)
      throws CmsException {
  
          CmsStaticExportManager manager = OpenCms.getStaticExportManager();
          boolean templatesFound = false;
          // loop through all resources
          Iterator<CmsPublishedResource> i = publishedResources.iterator();
          while (i.hasNext()) {
              CmsPublishedResource pubRes = i.next();
              String vfsName = pubRes.getRootPath();
              // only process this resource, if it is within the tree of allowed folders for static export
              if (manager.getExportFolderMatcher().match(vfsName)) {
                  // get the export data object, if null is returned, this resource cannot be exported
                  CmsStaticExportData exportData = manager.getVfsExportData(cms, vfsName);
                  if (exportData != null) {
                      CmsResource resource = null;
                      if (pubRes.isFile()) {
                          resource = exportData.getResource();
                      } else {
                          // the resource is a folder, check if PROPERTY_DEFAULT_FILE is set on folder
                          try {
                              resource = cms.readDefaultFile(vfsName);
                              //                            String defaultFileName = cms.readPropertyObject(
                              //                                vfsName,
                              //                                CmsPropertyDefinition.PROPERTY_DEFAULT_FILE,
                              //                                false).getValue();
                              //                            if (defaultFileName != null) {
                              //                                resource = cms.readResource(vfsName + defaultFileName);
                              //                            }
                          } catch (CmsException e) {
                              // resource is (still) a folder, check default files specified in configuration
                              for (int j = 0; j < OpenCms.getDefaultFiles().size(); j++) {
                                  String tmpResourceName = vfsName + OpenCms.getDefaultFiles().get(j);
                                  try {
                                      resource = cms.readResource(tmpResourceName);
                                      break;
                                  } catch (CmsException e1) {
                                      // ignore all other exceptions and continue the lookup process
                                  }
                              }
                          }
                      }
                      if ((resource != null) && resource.isFile()) {
                          // check loader for current resource if it must be processed before exported
                          I_CmsResourceLoader loader = OpenCms.getResourceManager().getLoader(resource);
                          if (!loader.isStaticExportProcessable()) {
                              // this resource must not be processed, so export it (if it's not marked as deleted)
                              if (!pubRes.getState().isDeleted()) {
                                  // mark the resource for export to the real file system
                                  resourcesToExport.add(exportData);
                              }
                          } else {
                              // the resource is a template resource or a folder, so store the name of it in the DB for further use
                              templatesFound = true;
                              cms.writeStaticExportPublishedResource(
                                  exportData.getRfsName(),
                                  CmsStaticExportManager.EXPORT_LINK_WITHOUT_PARAMETER,
                                  "",
                                  System.currentTimeMillis());
                          }
                      }
                  }
              }
          }
  
          return templatesFound;
      }
  }