/** Performs the process of reloading the domain information from the repository */
  private void internalReloadDomains() {
    lock.writeLock().lock();
    try {
      metadataMapping.reset();

      // Reload the metadata about the metadata (that was fun to say)
      final List<RepositoryFile> children = repository.getChildren(getMetadataDir().getId(), "*");
      if (logger.isTraceEnabled()) {
        logger.trace("\tFound " + children.size() + " files in the repository");
      }
      for (final RepositoryFile child : children) {
        if (getAclHelper().canAccess(child, READ)) {
          // Get the metadata for this file
          final Map<String, Serializable> fileMetadata = repository.getFileMetadata(child.getId());
          if (fileMetadata == null
              || StringUtils.isEmpty((String) fileMetadata.get(PROPERTY_NAME_DOMAIN_ID))) {
            if (logger.isWarnEnabled()) {
              logger.warn(
                  messages.getString(
                      "PentahoMetadataDomainRepository.WARN_0001_FILE_WITHOUT_METADATA",
                      child.getName()));
            }
            continue;
          }
          final String domainId = (String) fileMetadata.get(PROPERTY_NAME_DOMAIN_ID);
          final String type = (String) fileMetadata.get(PROPERTY_NAME_TYPE);
          final String locale = (String) fileMetadata.get(PROPERTY_NAME_LOCALE);
          if (logger.isTraceEnabled()) {
            logger.trace(
                "\tprocessing file [type="
                    + type
                    + " : domainId="
                    + domainId
                    + " : locale="
                    + locale
                    + "]");
          }

          // Save the data in the map
          if (StringUtils.equals(type, TYPE_DOMAIN)) {
            metadataMapping.addDomain(domainId, child);
          } else if (StringUtils.equals(type, TYPE_LOCALE)) {
            metadataMapping.addLocale(domainId, locale, child);
          }
        }
      }

      needToReload = false;
    } finally {
      lock.writeLock().unlock();
    }
  }
  /*
   * retrieves the data streams for the metadata referenced by domainId. This could be a single .xmi file or an .xmi
   * file and multiple .properties files.
   */
  public Map<String, InputStream> getDomainFilesData(final String domainId) {
    Set<RepositoryFile> metadataFiles;
    lock.readLock().lock();
    try {
      metadataFiles = metadataMapping.getFiles(domainId);
    } finally {
      lock.readLock().unlock();
    }

    Map<String, InputStream> values = new HashMap<String, InputStream>(metadataFiles.size());
    for (RepositoryFile repoFile : metadataFiles) {
      RepositoryFileInputStream is;
      try {
        is = new RepositoryFileInputStream(repoFile);
      } catch (Exception e) {
        return null; // This pretty much ensures an exception will be thrown later and passed to the
        // client
      }
      String fileName =
          repoFile.getName().endsWith(".properties")
              ? repoFile.getName()
              : domainId + (domainId.endsWith(".xmi") ? "" : ".xmi");
      values.put(fileName, is);
    }
    return values;
  }
  @Override
  public void addLocalizationFile(
      final String domainId,
      final String locale,
      final InputStream inputStream,
      final boolean overwrite)
      throws DomainStorageException {
    if (logger.isDebugEnabled()) {
      logger.debug("addLocalizationFile(" + domainId + ", " + locale + ", inputStream)");
    }
    if (null != inputStream) {
      if (StringUtils.isEmpty(domainId) || StringUtils.isEmpty(locale)) {
        throw new IllegalArgumentException(
            messages.getErrorString(
                "PentahoMetadataDomainRepository.ERROR_0004_DOMAIN_ID_INVALID", domainId));
      }

      lock.writeLock().lock();
      try {
        // Check for duplicates
        final RepositoryFile localeFile = metadataMapping.getLocaleFile(domainId, locale);
        if (!overwrite && localeFile != null) {
          throw new DomainStorageException(
              messages.getErrorString(
                  "PentahoMetadataDomainRepository.ERROR_0009_LOCALE_ALREADY_EXISTS",
                  domainId,
                  locale),
              null);
        }

        final SimpleRepositoryFileData data =
            new SimpleRepositoryFileData(inputStream, DEFAULT_ENCODING, LOCALE_MIME_TYPE);
        if (localeFile == null) {
          final RepositoryFile newLocaleFile = createUniqueFile(domainId, locale, data);
          metadataMapping.addLocale(domainId, locale, newLocaleFile);
        } else {
          repository.updateFile(localeFile, data, null);
        }
        // This invalidates any cached information
        flushDomains();
      } finally {
        lock.writeLock().unlock();
      }
    }
  }
  /**
   * remove a domain from disk and memory.
   *
   * @param domainId
   */
  @Override
  public void removeDomain(final String domainId) {
    if (logger.isDebugEnabled()) {
      logger.debug("removeDomain(" + domainId + ")");
    }

    if (StringUtils.isEmpty(domainId)) {
      throw new IllegalArgumentException(
          messages.getErrorString(
              "PentahoMetadataDomainRepository.ERROR_0004_DOMAIN_ID_INVALID", domainId));
    }

    // Get the metadata domain file
    RepositoryFile domainFile;
    Set<RepositoryFile> domainFiles;
    lock.writeLock().lock();
    try {
      domainFiles = metadataMapping.getFiles(domainId);
      domainFile = metadataMapping.getDomainFile(domainId);
      metadataMapping.deleteDomain(domainId);
    } finally {
      lock.writeLock().unlock();
    }

    if (domainFile != null) {
      // it no node exists, nothing would happen
      getAclHelper().removeAclFor(domainFile);
    }

    for (final RepositoryFile file : domainFiles) {
      if (logger.isTraceEnabled()) {
        logger.trace("Deleting repository file " + toString(file));
      }
      repository.deleteFile(file.getId(), true, null);
    }

    // This invalidates any caching
    if (!domainFiles.isEmpty()) {
      flushDomains();
    }
  }
 protected void loadLocaleStrings(final String domainId, final Domain domain) {
   final Map<String, RepositoryFile> localeFiles = metadataMapping.getLocaleFiles(domainId);
   if (localeFiles != null) {
     for (final String locale : localeFiles.keySet()) {
       final RepositoryFile localeFile = localeFiles.get(locale);
       final Properties properties = loadProperties(localeFile);
       if (logger.isTraceEnabled()) {
         logger.trace("\tLoading properties [" + domain + " : " + locale + "]");
       }
       localizationUtil.importLocalizedProperties(domain, properties, locale);
     }
   }
 }
  /**
   * Accesses the metadata mapping (with 1 retry) to find the metadata file for the specified
   * domainId
   */
  protected RepositoryFile getMetadataRepositoryFile(final String domainId) {
    lock.readLock().lock();
    RepositoryFile domainFile;
    try {
      domainFile = metadataMapping.getDomainFile(domainId);
    } finally {
      lock.readLock().unlock();
    }

    if (domainFile == null) {

      if (logger.isDebugEnabled()) {
        logger.debug(
            "Requested Domain ("
                + domainId
                + ") wasn't found in Metadata Mapping. Domain cache will be reloaded");
      }
      lock.writeLock().lock();
      try {
        domainFile = metadataMapping.getDomainFile(domainId);
        if (domainFile == null) {
          reloadDomainsIfNeeded();
          domainFile = metadataMapping.getDomainFile(domainId);
        }
      } finally {
        lock.writeLock().unlock();
      }
    }

    if (domainFile == null && logger.isDebugEnabled()) {
      logger.debug(
          "Even after reloading all domains, the specified Domain wasn't found in the system: "
              + domainId);
    }

    return domainFile;
  }
  /**
   * return a list of all the domain ids in the repository. triggers a call to reloadDomains if
   * necessary.
   *
   * @return the domain Ids.
   */
  @Override
  public Set<String> getDomainIds() {
    logger.debug("getDomainIds()");
    reloadDomainsIfNeeded();

    Collection<String> domains;
    lock.readLock().lock();
    try {
      domains = new ArrayList<String>(metadataMapping.getDomainIds());
    } finally {
      lock.readLock().unlock();
    }
    Set<String> domainIds = new HashSet<String>(domains.size());
    for (String domain : domains) {
      if (hasAccessFor(domain)) {
        domainIds.add(domain);
      }
    }
    return domainIds;
  }