docs: public void run(CmsResource source, CmsResource target, String targetName)
      throws CmsException, NoCustomReplacementException {
  
          LOG.info(
              "Starting page copy process: page='"
                  + source.getRootPath()
                  + "', targetFolder='"
                  + target.getRootPath()
                  + "'");
          CmsObject rootCms = getRootCms();
          if (m_copyMode == CopyMode.automatic) {
              Locale sourceLocale = OpenCms.getLocaleManager().getDefaultLocale(rootCms, source);
              Locale targetLocale = OpenCms.getLocaleManager().getDefaultLocale(rootCms, target);
              // if same locale, copy elements, otherwise use configured setting
              LOG.debug(
                  "copy mode automatic: source="
                      + sourceLocale
                      + " target="
                      + targetLocale
                      + " reuseConfig="
                      + OpenCms.getLocaleManager().shouldReuseElements()
                      + "");
              if (sourceLocale.equals(targetLocale)) {
                  m_copyMode = CopyMode.smartCopyAndChangeLocale;
              } else {
                  if (OpenCms.getLocaleManager().shouldReuseElements()) {
                      m_copyMode = CopyMode.reuse;
                  } else {
                      m_copyMode = CopyMode.smartCopyAndChangeLocale;
                  }
              }
          }
  
          if (source.isFolder()) {
              if (source.equals(target)) {
                  throw new CmsException(Messages.get().container(Messages.ERR_PAGECOPY_SOURCE_IS_TARGET_0));
              }
              CmsResource page = m_cms.readDefaultFile(source, CmsResourceFilter.IGNORE_EXPIRATION);
              if ((page == null) || !CmsResourceTypeXmlContainerPage.isContainerPage(page)) {
                  throw new CmsException(Messages.get().container(Messages.ERR_PAGECOPY_INVALID_PAGE_0));
              }
              List<CmsProperty> properties = Lists.newArrayList(m_cms.readPropertyObjects(source, false));
              Iterator<CmsProperty> iterator = properties.iterator();
              while (iterator.hasNext()) {
                  CmsProperty prop = iterator.next();
                  // copied folder may be root of a locale subtree, but since we may want to copy to a different locale,
                  // we don't want the locale property in the copy
                  if (prop.getName().equals(CmsPropertyDefinition.PROPERTY_LOCALE)
                      || prop.getName().equals(CmsPropertyDefinition.PROPERTY_ELEMENT_REPLACEMENTS)) {
                      iterator.remove();
                  }
              }
  
              I_CmsFileNameGenerator nameGen = OpenCms.getResourceManager().getNameGenerator();
              String copyPath;
              if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(targetName)) {
                  copyPath = CmsStringUtil.joinPaths(target.getRootPath(), targetName);
                  if (rootCms.existsResource(copyPath)) {
                      CmsResource existingResource = rootCms.readResource(copyPath);
                      // only overwrite the existing resource if it's a folder, otherwise find the next non-existing 'numbered' target path
                      if (!existingResource.isFolder()) {
                          copyPath = nameGen.getNewFileName(rootCms, copyPath + "%(number)", 4, true);
                      }
                  }
              } else {
                  copyPath = CmsFileUtil.removeTrailingSeparator(
                      CmsStringUtil.joinPaths(target.getRootPath(), source.getName()));
                  copyPath = nameGen.getNewFileName(rootCms, copyPath + "%(number)", 4, true);
              }
              Double maxNavPosObj = readMaxNavPos(target);
              double maxNavpos = maxNavPosObj == null ? 0 : maxNavPosObj.doubleValue();
              boolean hasNavpos = maxNavPosObj != null;
              CmsResource copiedFolder = null;
              CmsLockActionRecord lockRecord = null;
              if (rootCms.existsResource(copyPath)) {
                  copiedFolder = rootCms.readResource(copyPath);
                  lockRecord = CmsLockUtil.ensureLock(rootCms, copiedFolder);
                  rootCms.writePropertyObjects(copyPath, properties);
              } else {
                  copiedFolder = rootCms.createResource(
                      copyPath,
                      OpenCms.getResourceManager().getResourceType(CmsResourceTypeFolder.RESOURCE_TYPE_NAME),
                      null,
                      properties);
              }
              if (hasNavpos) {
                  String newNavPosStr = "" + (maxNavpos + 10);
                  rootCms.writePropertyObject(
                      copiedFolder.getRootPath(),
                      new CmsProperty(CmsPropertyDefinition.PROPERTY_NAVPOS, newNavPosStr, null));
              }
              String pageCopyPath = CmsStringUtil.joinPaths(copiedFolder.getRootPath(), page.getName());
              m_originalPage = page;
              m_targetFolder = target;
              m_copiedFolderOrPage = copiedFolder;
              if (rootCms.existsResource(pageCopyPath, CmsResourceFilter.IGNORE_EXPIRATION)) {
                  rootCms.deleteResource(pageCopyPath, CmsResource.DELETE_PRESERVE_SIBLINGS);
              }
              rootCms.copyResource(page.getRootPath(), pageCopyPath);
  
              CmsResource copiedPage = rootCms.readResource(pageCopyPath, CmsResourceFilter.IGNORE_EXPIRATION);
  
              replaceElements(copiedPage);
              attachLocaleGroups(copiedPage);
              if ((lockRecord == null) || (lockRecord.getChange() == LockChange.locked)) {
                  tryUnlock(copiedFolder);
              }
          } else {
              CmsResource page = source;
              if (!CmsResourceTypeXmlContainerPage.isContainerPage(page)) {
                  throw new CmsException(Messages.get().container(Messages.ERR_PAGECOPY_INVALID_PAGE_0));
              }
              I_CmsFileNameGenerator nameGen = OpenCms.getResourceManager().getNameGenerator();
              String copyPath = CmsFileUtil.removeTrailingSeparator(
                  CmsStringUtil.joinPaths(target.getRootPath(), source.getName()));
              int lastDot = copyPath.lastIndexOf(".");
              int lastSlash = copyPath.lastIndexOf("/");
              if (lastDot > lastSlash) { // path has an extension
                  String macroPath = copyPath.substring(0, lastDot) + "%(number)" + copyPath.substring(lastDot);
                  copyPath = nameGen.getNewFileName(rootCms, macroPath, 4, true);
              } else {
                  copyPath = nameGen.getNewFileName(rootCms, copyPath + "%(number)", 4, true);
              }
              Double maxNavPosObj = readMaxNavPos(target);
              double maxNavpos = maxNavPosObj == null ? 0 : maxNavPosObj.doubleValue();
              boolean hasNavpos = maxNavPosObj != null;
              rootCms.copyResource(page.getRootPath(), copyPath);
              if (hasNavpos) {
                  String newNavPosStr = "" + (maxNavpos + 10);
                  rootCms.writePropertyObject(
                      copyPath,
                      new CmsProperty(CmsPropertyDefinition.PROPERTY_NAVPOS, newNavPosStr, null));
              }
              CmsResource copiedPage = rootCms.readResource(copyPath);
              m_originalPage = page;
              m_targetFolder = target;
              m_copiedFolderOrPage = copiedPage;
              replaceElements(copiedPage);
              attachLocaleGroups(copiedPage);
              tryUnlock(copiedPage);
  
          }
      }