예제 #1
0
public class ImportServiceImpl implements ImportService {

  private static final Logger logger = LoggerFactory.getLogger(ImportServiceImpl.class);

  @Override
  public void importSite(String configLocation) {
    Document document = loadConfiguration(configLocation);
    if (document != null) {
      Element root = document.getRootElement();
      List<Node> siteNodes = root.selectNodes("site");
      if (siteNodes != null) {
        for (Node siteNode : siteNodes) {
          String name = siteNode.valueOf("name");
          String buildDataLocation = siteNode.valueOf("build-data-location");
          String publishingChannelGroup = siteNode.valueOf("publish-channel-group");
          String publishStr = siteNode.valueOf("publish");
          boolean publish =
              (!StringUtils.isEmpty(publishStr) && publishStr.equalsIgnoreCase("true"));
          String publishSize = siteNode.valueOf("publish-chunk-size");
          int chunkSize =
              (!StringUtils.isEmpty(publishSize) && StringUtils.isNumeric(publishSize))
                  ? Integer.valueOf(publishSize)
                  : -1;
          Node foldersNode = siteNode.selectSingleNode("folders");
          String sourceLocation = buildDataLocation + "/" + name;
          String delayIntervalStr = siteNode.valueOf("delay-interval");
          int delayInterval =
              (!StringUtils.isEmpty(delayIntervalStr) && StringUtils.isNumeric(delayIntervalStr))
                  ? Integer.valueOf(delayIntervalStr)
                  : -1;
          String delayLengthStr = siteNode.valueOf("delay-length");
          int delayLength =
              (!StringUtils.isEmpty(delayLengthStr) && StringUtils.isNumeric(delayLengthStr))
                  ? Integer.valueOf(delayLengthStr)
                  : -1;

          importFromConfigNode(
              name,
              publishingChannelGroup,
              foldersNode,
              sourceLocation,
              "/",
              publish,
              chunkSize,
              delayInterval,
              delayLength);
        }
      }
    }
  }

  protected Document loadConfiguration(String configLocation) {
    logger.debug("[IMPORT] loading " + configLocation);
    InputStream in = null;
    try {
      in = new FileInputStream(configLocation);
      if (in != null) {
        return ContentUtils.convertStreamToXml(in);
      }
    } catch (FileNotFoundException e) {
      logger.error("[IMPORT] failed to load configuration.", e);

    } catch (DocumentException e) {
      logger.error("[IMPORT] failed to load configuration.", e);

    } finally {
      ContentUtils.release(in);
    }
    return null;
  }

  private void importFromConfigNode(
      final String site,
      String publishChannelGroup,
      final Node node,
      final String fileRoot,
      final String targetRoot,
      boolean publish,
      int chunkSize,
      int delayInterval,
      int delayLength) {
    if (!inProgress) {
      inProgress = true;
      if (delayInterval > 0) pauseEanbeld = true;
      this.currentDelayInterval = delayInterval * 1000;
      this.currentDelayLength = delayLength * 1000;
      final Set<String> importedPaths = new HashSet<String>();
      final List<String> importedFullPaths = new ArrayList<String>();
      logger.info(
          "[IMPORT] started importing in "
              + site
              + ", pause enabled: "
              + pauseEanbeld
              + ", delay interval: "
              + this.currentDelayInterval
              + ", delay length: "
              + this.currentDelayLength);

      boolean overWrite = ContentFormatUtils.getBooleanValue(node.valueOf("@over-write"));
      final List<Node> folderNodes = node.selectNodes("folder");
      if (publish) {
        PublishingChannelGroupConfigTO configTO =
            siteService.getPublishingChannelGroupConfigs(site).get(publishChannelGroup);
        String user = securityService.getCurrentUser();
        List<PublishingChannel> channels = getChannels(site, configTO);
        logger.debug(
            "[IMPORT] publishing user: "******", publishing channel config: "
                + configTO.getName());

        this.nextStop = System.currentTimeMillis() + this.currentDelayInterval;
        createFolders(
            site,
            importedPaths,
            importedFullPaths,
            folderNodes,
            fileRoot,
            targetRoot,
            "",
            overWrite,
            channels,
            user);
        logger.info(
            "Starting Publish of Imported Files (Total "
                + importedFullPaths.size()
                + " On chunkSize of "
                + chunkSize
                + " )");
        publish(site, publishChannelGroup, targetRoot, importedFullPaths, chunkSize);
      } else {
        this.nextStop = System.currentTimeMillis() + this.currentDelayInterval;
        createFolders(
            site,
            importedPaths,
            importedFullPaths,
            folderNodes,
            fileRoot,
            targetRoot,
            "",
            overWrite,
            null,
            null);
      }
      inProgress = false;
    } else {
      logger.info("[IMPORT] an import process is currently running.");
    }
  }

  /**
   * populate channel information
   *
   * @param configTO
   */
  private List<PublishingChannel> getChannels(
      String site, PublishingChannelGroupConfigTO configTO) {
    SiteService siteService = getSiteService();
    if (configTO.getChannels() != null) {
      List<PublishingChannel> channels = new ArrayList<PublishingChannel>();
      for (PublishingChannelConfigTO channelConfig : configTO.getChannels()) {
        DeploymentEndpointConfigTO endpointConfigTO =
            siteService.getDeploymentEndpoint(site, channelConfig.getName());
        if (endpointConfigTO != null) {
          PublishingChannel channel = new PublishingChannel();
          logger.debug(
              "[IMPORT] populating channel: "
                  + channelConfig.getName()
                  + ", id: "
                  + channel.getId());
          channel.setName(channelConfig.getName());
          String server = endpointConfigTO.getServerUrl();
          channel.setPassword(endpointConfigTO.getPassword());
          channel.setTarget(endpointConfigTO.getTarget());
          channel.setPublishMetadata(endpointConfigTO.isSendMetadata());
          try {
            URL channelUrl = new URL(server);
            channel.setUrl(channelUrl.toString());
          } catch (MalformedURLException e) {
            logger.error("[IMPORT] " + channelConfig.getName() + " has an invalid target URL.", e);
          }
          channels.add(channel);
        }
      }
      return channels;
    } else {
      return null;
    }
  }

  /**
   * create folders
   *
   * @param site site name
   * @param importedPaths a list of imported files
   * @param importedFullPaths
   * @param nodes nodes representing folders
   * @param fileRoot the root location of files/folders being imported
   * @param targetRoot the target location root
   * @param parentPath the target location to import to
   * @param overWrite overwrite contents?
   * @param channels
   * @param user
   */
  @SuppressWarnings("unchecked")
  private void createFolders(
      String site,
      Set<String> importedPaths,
      List<String> importedFullPaths,
      List<Node> nodes,
      String fileRoot,
      String targetRoot,
      String parentPath,
      boolean overWrite,
      List<PublishingChannel> channels,
      String user) {
    logger.info(
        "[IMPORT] createFolders : site["
            + site
            + "] "
            + "] fileRoot ["
            + fileRoot
            + "] targetRoot [ "
            + targetRoot
            + "] parentPath ["
            + parentPath
            + "] overwrite["
            + overWrite
            + "]");

    if (nodes != null) {
      for (Node node : nodes) {
        String name = node.valueOf("@name");
        String value = node.valueOf("@over-write");
        boolean folderOverWrite =
            (StringUtils.isEmpty(value)) ? overWrite : ContentFormatUtils.getBooleanValue(value);
        if (!StringUtils.isEmpty(name)) {
          String currentFilePath = fileRoot + "/" + name;
          String currentPath = parentPath + "/" + name;
          // check if the parent node exists and create the folder if
          // not
          boolean folderExists = contentService.contentExists(site, currentPath);
          if (!folderExists) {
            contentService.createFolder(site, parentPath, name);
          }
          boolean importAll = ContentFormatUtils.getBooleanValue(node.valueOf("@import-all"));
          if (importAll) {
            importRootFileList(
                site,
                importedPaths,
                importedFullPaths,
                fileRoot + "/" + name,
                targetRoot,
                currentPath,
                folderOverWrite,
                channels,
                user);

          } else {
            // create child folders
            List<Node> childFolders = node.selectNodes("folder");
            createFolders(
                site,
                importedPaths,
                importedFullPaths,
                childFolders,
                currentFilePath,
                targetRoot,
                currentPath,
                folderOverWrite,
                channels,
                user);
            // create child fiimportedPathsles
            List<Node> childFiles = node.selectNodes("file");
            createFiles(
                site,
                importedPaths,
                importedFullPaths,
                childFiles,
                currentFilePath,
                targetRoot,
                currentPath,
                folderOverWrite,
                channels,
                user);
          }
        }
      }
    }
  }

  /**
   * import all files from the given file root
   *
   * @param site
   * @param importedPaths
   * @param importedFullPaths
   * @param fileRoot
   * @param targetRoot the target location root
   * @param parentPath the target location to import to
   * @param overWrite
   * @param channels
   * @param user
   */
  protected void importRootFileList(
      String site,
      Set<String> importedPaths,
      List<String> importedFullPaths,
      String fileRoot,
      String targetRoot,
      String parentPath,
      boolean overWrite,
      List<PublishingChannel> channels,
      String user) {
    URL resourceUrl = getResourceUrl(fileRoot);
    if (resourceUrl != null) {
      String resourcePath = resourceUrl.getFile();
      File file = new File(resourcePath);
      if (file.isDirectory()) {
        String[] children = file.list();
        if (children != null && children.length > 0) {
          for (String childName : children) {
            File childFile = new File(resourcePath + "/" + childName);
            if (childFile.isDirectory()) {
              String currentPath = parentPath + "/" + childName;
              boolean folderExists = contentService.contentExists(site, currentPath);
              if (!folderExists) {
                contentService.createFolder(site, parentPath, childName);
              }
              logger.info("[IMPORT] Importing " + parentPath + "/" + childName);

              importFileList(
                  site,
                  importedPaths,
                  importedFullPaths,
                  fileRoot + "/" + childName,
                  targetRoot,
                  parentPath + "/" + childName,
                  overWrite,
                  channels,
                  user);
              logger.info("[IMPORT] Finished Importing " + parentPath + "/" + childName);
            } else {
              writeContentInTransaction(
                  site,
                  importedPaths,
                  importedFullPaths,
                  fileRoot,
                  targetRoot,
                  parentPath,
                  childName,
                  overWrite,
                  channels,
                  user);
            }
          }
        }
      }

    } else {
      logger.error("[IMPORT] " + fileRoot + " is not found.");
    }
  }

  /**
   * get the resource url for import
   *
   * @param filePath
   * @return
   */
  private URL getResourceUrl(String filePath) {
    try {
      return new File(filePath).toURI().toURL();
    } catch (MalformedURLException e) {
      throw new RuntimeException("Not able to find " + filePath);
    }
  }

  /**
   * import files and folders at the given fileRoot path
   *
   * @param site
   * @param importedPaths
   * @param importedFullPaths
   * @param fileRoot
   * @param targetRoot the target location root
   * @param parentPath the target location to import to
   * @param overWrite
   * @param channels
   * @param user
   */
  protected void importFileList(
      String site,
      Set<String> importedPaths,
      List<String> importedFullPaths,
      String fileRoot,
      String targetRoot,
      String parentPath,
      boolean overWrite,
      List<PublishingChannel> channels,
      String user) {
    logger.info(
        "[IMPORT] importFileList: fileRoot ["
            + fileRoot
            + "] name ["
            + targetRoot
            + "] overwrite["
            + overWrite
            + "]");
    URL resourceUrl = getResourceUrl(fileRoot);
    if (resourceUrl != null) {
      String resourcePath = resourceUrl.getFile();
      File file = new File(resourcePath);
      if (file.isDirectory()) {
        String[] children = file.list();
        if (children != null && children.length > 0) {
          for (String childName : children) {
            File childFile = new File(resourcePath + "/" + childName);
            if (childFile.isDirectory()) {
              String currentPath = parentPath + "/" + childName;
              boolean folderExists = contentService.contentExists(site, currentPath);
              if (!folderExists) {
                contentService.createFolder(site, parentPath, childName);
              }
              importFileList(
                  site,
                  importedPaths,
                  importedFullPaths,
                  fileRoot + "/" + childName,
                  targetRoot,
                  parentPath + "/" + childName,
                  overWrite,
                  channels,
                  user);
            } else {
              writeContentInTransaction(
                  site,
                  importedPaths,
                  importedFullPaths,
                  fileRoot,
                  targetRoot,
                  parentPath,
                  childName,
                  overWrite,
                  channels,
                  user);
            }
          }
        }
      }
    } else {
      logger.error("[IMPORT] " + fileRoot + " is not found.");
    }
  }

  /**
   * write content
   *
   * @param site
   * @param importedPaths
   * @param importedFullPaths
   * @param fileRoot
   * @param parentPath
   * @param name
   * @param overWrite
   * @param channels
   * @param user
   */
  protected void writeContentInTransaction(
      final String site,
      final Set<String> importedPaths,
      final List<String> importedFullPaths,
      final String fileRoot,
      final String targetRoot,
      final String parentPath,
      final String name,
      final boolean overWrite,
      final List<PublishingChannel> channels,
      final String user) {
    long startTimeWrite = System.currentTimeMillis();
    logger.debug("[IMPORT] writing file in transaction: " + parentPath + "/" + name);
    writeContent(
        site, importedPaths, importedFullPaths, fileRoot, targetRoot, parentPath, name, overWrite);
    logger.debug(
        "[IMPORT] done writing file in transaction: "
            + parentPath
            + "/"
            + name
            + ", time: "
            + (System.currentTimeMillis() - startTimeWrite));
    pause();
  }

  /**
   * write content
   *
   * @param site
   * @param importedPaths
   * @param importedFullPaths
   * @param fileRoot
   * @param parentPath
   * @param name
   * @param overWrite
   */
  protected void writeContent(
      String site,
      Set<String> importedPaths,
      List<String> importedFullPaths,
      String fileRoot,
      String targetRoot,
      String parentPath,
      String name,
      boolean overWrite) {
    boolean isXml = true;
    String processChain = this.xmlChainName;
    if (!name.endsWith(".xml")) {
      isXml = false;
      processChain = this.assetChainName;
    }
    InputStream in = null;
    String filePath = parentPath + "/" + name;
    String fileSystemPath = fileRoot + "/" + name;
    logger.info(
        "[IMPORT] writeContent: fileRoot ["
            + fileRoot
            + "] fullPath ["
            + filePath
            + "] overwrite["
            + overWrite
            + "] process chain [ "
            + processChain
            + "]");
    long startTimeWrite = System.currentTimeMillis();
    logger.debug("[IMPORT] writing file: " + parentPath + "/" + name);

    try {
      File file = new File(fileSystemPath);
      if (file.exists()) {
        in = new FileInputStream(file);
        String currentPath = parentPath + "/" + name;
        boolean contentExists = contentService.contentExists(site, currentPath);
        // create parameters
        Map<String, String> params = createParams(site, isXml, targetRoot, parentPath, name);
        String id = site + ":" + filePath + ":" + name;
        // write content only it is new or overwrite is set to true for
        // existing
        if (!contentExists || overWrite) {
          String fullPath = targetRoot + filePath;
          objectStateService.setSystemProcessing(site, currentPath, true);
          // write the content
          contentService.processContent(id, in, isXml, params, processChain);
          ContentItemTO item = contentService.getContentItem(site, currentPath);
          // update state
          if (item != null) {
            objectStateService.transition(site, item, TransitionEvent.SAVE);
            objectStateService.setSystemProcessing(site, currentPath, false);
          } else {
            ObjectState state = objectStateService.getObjectState(site, currentPath);
            if (state == null) {
              objectStateService.insertNewEntry(site, currentPath);
            }
          }

          importedPaths.add(filePath);
          importedFullPaths.add(fullPath);
        } else {
          logger.debug(
              "[IMPORT] " + filePath + " exists and set to not to overrwite. skipping this file.");
        }
      }
    } catch (FileNotFoundException e) {
      logger.warn("[IMPORT] " + filePath + " does not exist.");

    } catch (ServiceException e) {
      logger.error("[IMPORT] failed to import " + filePath, e);
    } finally {
      ContentUtils.release(in);
    }
    logger.debug(
        "[IMPORT] done writing file: "
            + parentPath
            + "/"
            + name
            + ", time: "
            + (System.currentTimeMillis() - startTimeWrite));
  }

  /**
   * create write process parameters
   *
   * @param site
   * @param isXml
   * @param targetRoot
   * @param parentPath
   * @param name
   * @return
   */
  private Map<String, String> createParams(
      String site, boolean isXml, String targetRoot, String parentPath, String name) {
    Map<String, String> params = new HashMap<String, String>();
    String filePath = parentPath + "/" + name;
    String path = (isXml) ? filePath : parentPath;
    String fullPath = targetRoot + filePath;
    params.put(DmConstants.KEY_SITE, site);
    params.put(DmConstants.KEY_PATH, path);
    params.put(DmConstants.KEY_FULL_PATH, fullPath);
    params.put(DmConstants.KEY_FILE_NAME, name);
    params.put(DmConstants.KEY_USER, this.assignee);
    params.put(DmConstants.KEY_CREATE_FOLDERS, "true");
    params.put(DmConstants.KEY_UNLOCK, "true");
    logger.debug("[IMPORT] creating/updating " + filePath);
    return params;
  }

  /** pause the process if it reached the interval */
  protected void pause() {
    if (this.pauseEanbeld) {
      if (System.currentTimeMillis() >= this.nextStop) {
        logger.debug("[IMPORT] pausing import process.");
        try {
          Thread.sleep(this.currentDelayLength);
          this.nextStop = System.currentTimeMillis() + this.currentDelayInterval;
        } catch (InterruptedException e) {
          logger.error("[IMPORT] error while pausing import process.", e);
        }
        logger.debug("[IMPORT] done pausing import process.");
      }
    }
  }

  /**
   * create files from a list
   *
   * @param site
   * @param importedPaths
   * @param importedFullPaths
   * @param nodes
   * @param fileRoot
   * @param targetRoot the target location root
   * @param parentPath the target location to import to
   * @param overWrite
   * @param channels
   * @param user
   */
  protected void createFiles(
      String site,
      Set<String> importedPaths,
      List<String> importedFullPaths,
      List<Node> nodes,
      String fileRoot,
      String targetRoot,
      String parentPath,
      boolean overWrite,
      List<PublishingChannel> channels,
      String user) {
    logger.info(
        "[IMPORT] createFiles: fileRoot ["
            + fileRoot
            + "] parentFullPath ["
            + parentPath
            + "] overwrite["
            + overWrite
            + "]");
    if (nodes != null) {
      for (Node node : nodes) {
        String name = node.valueOf("@name");
        String value = node.valueOf("@over-write");
        boolean fileOverwrite =
            (StringUtils.isEmpty(value)) ? overWrite : ContentFormatUtils.getBooleanValue(value);
        if (!StringUtils.isEmpty(name)) {
          writeContentInTransaction(
              site,
              importedPaths,
              importedFullPaths,
              fileRoot,
              targetRoot,
              parentPath,
              name,
              fileOverwrite,
              channels,
              user);
        }
      }
    }
  }

  /**
   * publish items
   *
   * @param site
   * @param publishChannelGroup
   * @param targetRoot
   * @param fullPaths
   * @param chunkSize
   */
  protected void publish(
      String site,
      String publishChannelGroup,
      String targetRoot,
      List<String> fullPaths,
      int chunkSize) {
    if (chunkSize < 1) {
      logger.info("[IMPORT] publising chunk size not defined. publishing all together.");
      submitToGoLive(site, publishChannelGroup, fullPaths);
    } else {
      int total = fullPaths.size();
      int count = 0;
      // group pages in a small chucks
      Set<String> goLiveItemPaths = new HashSet<String>(chunkSize);
      List<String> goLiveItemFullPaths = new ArrayList<String>(chunkSize);
      for (String importedFullPath : fullPaths) {
        logger.debug("		" + importedFullPath);
        if (goLiveItemFullPaths.size() < chunkSize) {
          goLiveItemFullPaths.add(importedFullPath);
          String goLiveItemPath = importedFullPath.replaceFirst(targetRoot, "");
          goLiveItemPaths.add(goLiveItemPath);
          count++;
        }
        if (goLiveItemPaths.size() == chunkSize) {
          logger.info(
              "[IMPORT] submitting "
                  + chunkSize
                  + " imported files to "
                  + publishChannelGroup
                  + " ("
                  + count
                  + "/"
                  + total
                  + ")");

          submitToGoLive(site, publishChannelGroup, goLiveItemFullPaths);
          goLiveItemPaths = new HashSet<String>(chunkSize);
          goLiveItemFullPaths = new ArrayList<String>(chunkSize);
        }
      }
      // submit the last set
      if (goLiveItemPaths.size() < chunkSize) {
        logger.info(
            "[IMPORT] submitting "
                + chunkSize
                + " imported files to "
                + publishChannelGroup
                + " ("
                + count
                + "/"
                + total
                + ")");
        submitToGoLive(site, publishChannelGroup, goLiveItemFullPaths);
        goLiveItemPaths = new HashSet<String>(chunkSize);
        goLiveItemFullPaths = new ArrayList<String>(chunkSize);
      }
    }
  }

  /**
   * submit imported items to go live
   *
   * @param site
   * @param publishChannelGroup
   * @param importedFullPaths
   */
  protected void submitToGoLive(
      String site, String publishChannelGroup, List<String> importedFullPaths) {
    MultiChannelPublishingContext mcpContext =
        new MultiChannelPublishingContext(publishChannelGroup, "", "Import Service");
    dmPublishService.publish(site, importedFullPaths, null, mcpContext);
    logger.info("All files have been submitted to be publish");
  }

  public SiteService getSiteService() {
    return siteService;
  }

  public void setSiteService(SiteService siteService) {
    this.siteService = siteService;
  }

  public SecurityService getSecurityService() {
    return securityService;
  }

  public void setSecurityService(SecurityService securityService) {
    this.securityService = securityService;
  }

  public ContentRepository getContentRepository() {
    return contentRepository;
  }

  public void setContentRepository(ContentRepository contentRepository) {
    this.contentRepository = contentRepository;
  }

  public ContentService getContentService() {
    return contentService;
  }

  public void setContentService(ContentService contentService) {
    this.contentService = contentService;
  }

  public ObjectStateService getObjectStateService() {
    return objectStateService;
  }

  public void setObjectStateService(ObjectStateService objectStateService) {
    this.objectStateService = objectStateService;
  }

  public DmPublishService getDmPublishService() {
    return dmPublishService;
  }

  public void setDmPublishService(DmPublishService dmPublishService) {
    this.dmPublishService = dmPublishService;
  }

  public String getXmlChainName() {
    return xmlChainName;
  }

  public void setXmlChainName(String xmlChainName) {
    this.xmlChainName = xmlChainName;
  }

  public String getAssetChainName() {
    return assetChainName;
  }

  public void setAssetChainName(String assetChainName) {
    this.assetChainName = assetChainName;
  }

  public String getAssignee() {
    return assignee;
  }

  public void setAssignee(String assignee) {
    this.assignee = assignee;
  }

  protected SiteService siteService;
  protected SecurityService securityService;
  protected ContentRepository contentRepository;
  protected ContentService contentService;
  protected ObjectStateService objectStateService;
  protected DmPublishService dmPublishService;

  protected String xmlChainName;
  protected String assetChainName;
  protected String assignee;

  /** is import in progress? */
  private boolean inProgress = false;

  /** going to pause import process? * */
  private boolean pauseEanbeld = false;
  /** next pause time * */
  private long nextStop;
  /** import delay interval * */
  private long currentDelayInterval;
  /** import delay time * */
  private long currentDelayLength;

  /**
   * publishing channel
   *
   * @author hyanghee
   */
  public class PublishingChannel {

    private String id;
    private String name;
    private String url;
    private String password;
    private String target;
    private boolean publishMetadata;

    public PublishingChannel() {}

    public PublishingChannel(
        String id,
        String name,
        String url,
        String password,
        String target,
        boolean publishMetadata) {
      this.id = id;
      this.name = name;
      this.url = url;
      this.password = password;
      this.target = target;
      this.publishMetadata = publishMetadata;
    }

    /** @return the url */
    public String getUrl() {
      return url;
    }
    /** @param url the url to set */
    public void setUrl(String url) {
      this.url = url;
    }
    /** @return the password */
    public String getPassword() {
      return password;
    }
    /** @param password the password to set */
    public void setPassword(String password) {
      this.password = password;
    }
    /** @return the target */
    public String getTarget() {
      return target;
    }
    /** @param target the target to set */
    public void setTarget(String target) {
      this.target = target;
    }
    /** @return the publishMetadata */
    public boolean isPublishMetadata() {
      return publishMetadata;
    }
    /** @param publishMetadata the publishMetadata to set */
    public void setPublishMetadata(boolean publishMetadata) {
      this.publishMetadata = publishMetadata;
    }

    /** @return the id */
    public String getId() {
      return id;
    }

    /** @param id the id to set */
    public void setId(String id) {
      this.id = id;
    }

    /** @return the name */
    public String getName() {
      return name;
    }

    /** @param name the name to set */
    public void setName(String name) {
      this.name = name;
    }
  }
}
/**
 * Map repository paths to specific repositories
 *
 * @author russdanner
 *     <p>From RD: We may want to change the data stucture of the map so that you can more
 *     predictably order the patterns which may help in some cases. The basic assumption of this
 *     implementation is that patterns are basic and the repositories are neatly split
 */
public class PathMappedContentRepository extends AbstractContentRepository {

  private static final Logger logger = LoggerFactory.getLogger(PathMappedContentRepository.class);
  private ContentRepository defaultRepo;
  private Map<String, ContentRepository> pathRepoMap;

  public ContentRepository getDefaultRepository() {
    return defaultRepo;
  }

  public void setDefaultRepository(ContentRepository repo) {
    defaultRepo = repo;
  }

  public Map<String, ContentRepository> getPathRepositoryMap() {
    return pathRepoMap;
  }

  public void setPathRepositoryMap(Map<String, ContentRepository> repoMap) {
    pathRepoMap = repoMap;
  }

  /** default constructor */
  public PathMappedContentRepository() {
    setPathRepositoryMap(new HashMap<String, ContentRepository>());
  }

  /**
   * given a path look up the repository that content should be directed
   *
   * @param path the path for the content request
   */
  protected ContentRepository lookupRepo(String path) {
    ContentRepository retRepo = defaultRepo;
    Set<String> pathRegexs = pathRepoMap.keySet();

    for (String pathRegex : pathRegexs) {
      try {
        // note this can be optimized by compiling at startup
        Matcher m = Pattern.compile(pathRegex).matcher(path);
        if (m.find()) {
          // path must match first group. Sub groups don't make sense in this context
          retRepo = pathRepoMap.get(pathRegex);
          break;
        }
      } catch (Exception regexErr) {
        logger.error(
            "error looking up repo with regex '{0}' and path '{1}'", regexErr, pathRegex, path);
      }
    }

    if (retRepo == null) {
      logger.error(
          "Repo is null, cannot complete operation.  No default set and '{0}' does not match any mapped repository,",
          path);
      throw new RuntimeException("Repo is null, cannot complete operation.");
    }

    return retRepo;
  }

  @Override
  public InputStream getContent(String path) throws ContentNotFoundException {
    ContentRepository repo = lookupRepo(path);
    return repo.getContent(path);
  }

  @Override
  public boolean contentExists(String path) {
    ContentRepository repo = lookupRepo(path);
    return repo.contentExists(path);
  }

  @Override
  public boolean writeContent(String path, InputStream content) {
    ContentRepository repo = lookupRepo(path);
    return repo.writeContent(path, content);
  }

  @Override
  public boolean createFolder(String path, String name) {
    ContentRepository repo = lookupRepo(path);
    return repo.createFolder(path, name);
  }

  @Override
  public boolean deleteContent(String path) {
    ContentRepository repo = lookupRepo(path);
    return repo.deleteContent(path);
  }

  @Override
  public boolean copyContent(String fromPath, String toPath) {
    ContentRepository fromRepo = lookupRepo(fromPath);
    ContentRepository toRepo = lookupRepo(toPath);

    if (fromRepo != toRepo) {
      logger.error(
          "From repository for path '{0}' and To repository for path '{1}' do not match",
          fromPath, toPath);
      throw new RuntimeException("cross repo copy operation not supported");
    }

    return fromRepo.copyContent(fromPath, toPath);
  }

  @Override
  public boolean moveContent(String fromPath, String toPath) {
    ContentRepository fromRepo = lookupRepo(fromPath);
    ContentRepository toRepo = lookupRepo(toPath);

    if (fromRepo != toRepo) {
      logger.error(
          "From repository for path '{0}' and To repository for path '{1}' do not match",
          fromPath, toPath);
      throw new RuntimeException("cross repo move operation not supported");
    }

    return fromRepo.moveContent(fromPath, toPath);
  }

  @Override
  public boolean moveContent(String fromPath, String toPath, String newName) {
    ContentRepository fromRepo = lookupRepo(fromPath);
    ContentRepository toRepo = lookupRepo(toPath);

    if (fromRepo != toRepo) {
      logger.error(
          "From repository for path '{0}' and To repository for path '{1}' do not match",
          fromPath, toPath);
      throw new RuntimeException("cross repo move operation not supported");
    }

    return fromRepo.moveContent(fromPath, toPath, newName);
  }

  @Override
  public RepositoryItem[] getContentChildren(String path) {
    ContentRepository repo = lookupRepo(path);
    return repo.getContentChildren(path);
  }

  @Override
  public VersionTO[] getContentVersionHistory(String path) {
    ContentRepository repo = lookupRepo(path);
    return repo.getContentVersionHistory(path);
  }

  @Override
  public String createVersion(String path, boolean majorVersion) {
    ContentRepository repo = lookupRepo(path);
    return repo.createVersion(path, majorVersion);
  }

  @Override
  public String createVersion(String path, String comment, boolean majorVersion) {
    ContentRepository repo = lookupRepo(path);
    return repo.createVersion(path, comment, majorVersion);
  }

  @Override
  public boolean revertContent(String path, String label, boolean major, String comment) {
    ContentRepository repo = lookupRepo(path);
    return repo.revertContent(path, label, major, comment);
  }

  @Override
  public void lockItem(String site, String path) {
    ContentRepository repo = lookupRepo(path);
    repo.lockItem(site, path);
  }

  @Override
  public void unLockItem(String site, String path) {
    ContentRepository repo = lookupRepo(path);
    repo.unLockItem(site, path);
  }

  @Override
  public Date getModifiedDate(String path) {
    ContentRepository repo = lookupRepo(path);
    return repo.getModifiedDate(path);
  }
}