docs: public int export(HttpServletRequest req, HttpServletResponse res, CmsObject cms, CmsStaticExportData data)
      throws CmsException, IOException, ServletException, CmsStaticExportException {
  
          CmsResource resource = data.getResource();
          String vfsName = data.getVfsName();
          String rfsName;
          if (data.isDetailPage()) {
              rfsName = CmsStringUtil.joinPaths(data.getRfsName(), CmsStaticExportManager.DEFAULT_FILE);
          } else if (data.getParameters() != null) {
              rfsName = data.getRfsName();
          } else {
              rfsName = addDefaultFileNameToFolder(data.getRfsName(), resource.isFolder());
          }
  
          // cut the site root from the vfsName and switch to the correct site
          String siteRoot = OpenCms.getSiteManager().getSiteRoot(vfsName);
  
          CmsI18nInfo i18nInfo = OpenCms.getLocaleManager().getI18nInfo(
              req,
              cms.getRequestContext().getCurrentUser(),
              cms.getRequestContext().getCurrentProject(),
              vfsName);
  
          String remoteAddr = m_remoteAddr;
          if (remoteAddr == null) {
              remoteAddr = CmsContextInfo.LOCALHOST;
          }
  
          if (siteRoot != null) {
              vfsName = vfsName.substring(siteRoot.length());
          } else {
              siteRoot = "/";
          }
  
          if (LOG.isDebugEnabled()) {
              LOG.debug(Messages.get().getBundle().key(Messages.LOG_STATIC_EXPORT_SITE_ROOT_2, siteRoot, vfsName));
          }
  
          boolean usesSecureSite = (req != null) && OpenCms.getSiteManager().usesSecureSite(req);
          CmsContextInfo contextInfo = new CmsContextInfo(
              cms.getRequestContext().getCurrentUser(),
              cms.getRequestContext().getCurrentProject(),
              vfsName,
              cms.getRequestContext().getRequestMatcher(),
              siteRoot,
              usesSecureSite,
              i18nInfo.getLocale(),
              i18nInfo.getEncoding(),
              remoteAddr,
              CmsContextInfo.CURRENT_TIME,
              cms.getRequestContext().getOuFqn());
          CmsObject exportCms = OpenCms.initCmsObject(null, contextInfo);
  
          // only export those resources where the export property is set
          if (!isExportLink(exportCms, exportCms.getRequestContext().removeSiteRoot(data.getVfsName()))) {
              // the resource was not used for export, so return HttpServletResponse.SC_SEE_OTHER
              // as a signal for not exported resource
              return HttpServletResponse.SC_SEE_OTHER;
          }
  
          // this flag signals if the export method is used for "on demand" or "after publish".
          // if no request and result stream are available, it was called during "export on publish"
          boolean exportOnDemand = ((req != null) && (res != null));
          CmsStaticExportResponseWrapper wrapRes = null;
          if (res != null) {
              wrapRes = new CmsStaticExportResponseWrapper(res);
          }
          if (LOG.isDebugEnabled()) {
              LOG.debug(Messages.get().getBundle().key(Messages.LOG_SE_RESOURCE_START_1, data));
          }
  
          CmsFile file = exportCms.readFile(OpenCms.initResource(exportCms, vfsName, req, wrapRes));
          vfsName = exportCms.getSitePath(file);
  
          // check loader id for resource
          I_CmsResourceLoader loader = OpenCms.getResourceManager().getLoader(file);
          if ((loader == null) || (!loader.isStaticExportEnabled())) {
              Object[] arguments = new Object[] {vfsName, new Integer(file.getTypeId())};
              throw new CmsStaticExportException(
                  Messages.get().container(Messages.ERR_EXPORT_NOT_SUPPORTED_2, arguments));
          }
  
          // ensure we have exactly the same setup as if called "the usual way"
          // we only have to do this in case of the static export on demand
          if (exportOnDemand) {
              String mimetype = OpenCms.getResourceManager().getMimeType(
                  file.getName(),
                  exportCms.getRequestContext().getEncoding());
              if (wrapRes != null) {
                  wrapRes.setContentType(mimetype);
              }
              exportCms.getRequestContext().setUri(vfsName);
          }
  
          // do the export
          int status = -1;
          List<Locale> locales = OpenCms.getLocaleManager().getDefaultLocales(exportCms, vfsName);
          boolean exported = false;
          boolean matched = false;
          // iterate over all rules
          Iterator<CmsStaticExportRfsRule> it = getRfsRules().iterator();
          while (it.hasNext()) {
              CmsStaticExportRfsRule rule = it.next();
              // normal case
              boolean export = rule.getSource().matcher(siteRoot + vfsName).matches();
              matched |= export;
              // system folder case
              export |= ((OpenCms.getSiteManager().startsWithShared(vfsName)
                  || vfsName.startsWith(CmsWorkplace.VFS_PATH_SYSTEM)) && rule.match(vfsName));
              if (export) {
                  // the resource has to exported for this rule
                  CmsObject locCms = exportCms;
                  Locale locale = CmsLocaleManager.getLocale(rule.getName());
                  if (locales.contains(locale)) {
                      // if the locale is in the default locales for the resource
                      // so adjust the locale to use for exporting
                      CmsContextInfo ctxInfo = new CmsContextInfo(exportCms.getRequestContext());
                      ctxInfo.setLocale(locale);
                      locCms = OpenCms.initCmsObject(exportCms, ctxInfo);
                  }
                  // read the content in the matching locale
                  byte[] content = loader.export(locCms, new CmsFile(file), req, wrapRes);
                  if (content != null) {
                      // write to rfs
                      exported = true;
                      String locRfsName = rfsName;
                      // in case of the default locale, this would either be wrong or the identity substitution
                      if (!locale.equals(CmsLocaleManager.getDefaultLocale()) && locales.contains(locale)) {
                          locRfsName = rule.getLocalizedRfsName(rfsName, "/");
                      }
                      writeResource(req, rule.getExportPath(), locRfsName, resource, content);
                  }
              }
          }
          if (!matched) {
              // no rule matched
              String exportPath = getExportPath(siteRoot + vfsName);
              byte[] content = loader.export(exportCms, new CmsFile(file), req, wrapRes);
              if (content != null) {
                  exported = true;
                  writeResource(req, exportPath, rfsName, resource, content);
              }
          }
  
          if (exported) {
              // get the wrapper status that was set
              status = (wrapRes != null) ? wrapRes.getStatus() : -1;
              if (status < 0) {
                  // the status was not set, assume everything is o.k.
                  status = HttpServletResponse.SC_OK;
              }
          } else {
              // the resource was not written because it was not modified.
              // set the status to not modified
              status = HttpServletResponse.SC_NOT_MODIFIED;
          }
  
          return status;
      }