@Override
  public void synchronizeImage(ImageFile imageFile) {
    // If the file already exist in DB, keep current Image, replace ImageFile
    List<ImageFileImpl> imageFiles =
        this.entityManager
            .createQuery(
                "SELECT i FROM IMAGE_FILE i WHERE i.absolutePath = ?1", ImageFileImpl.class)
            .setParameter(1, imageFile.getAbsolutePath())
            .getResultList();
    if (imageFiles != null && imageFiles.size() == 1) {
      imageFiles.get(0).getImage().setOriginalFile(imageFile);
    }

    // Delete old ImageFiles
    this.entityManager
        .createQuery("DELETE FROM IMAGE_FILE i WHERE i.absolutePath = ?1")
        .setParameter(1, imageFile.getAbsolutePath())
        .executeUpdate();

    // Merge/Persist Image/ImageFile into DB
    if (imageFile.getImage() != null) {
      this.entityManager.merge(imageFile.getImage());
    } else {
      // TODO: Should use factory here
      Image image = new ImageImpl();
      image.setOriginalFile(imageFile);
      image.setAlbum(
          FilenameUtils.getName(FilenameUtils.getFullPathNoEndSeparator(imageFile.getFilePath())));
      image.setTitle(FilenameUtils.removeExtension(imageFile.getFileName()));
      this.entityManager.merge(image);
    }

    // Delete empty Images
    this.entityManager
        .createQuery("DELETE FROM IMAGE i WHERE i.originalFile IS NULL")
        .executeUpdate();
  }
  /**
   * @return a collection of files found inside a given folder for a search uri which contains a
   *     wildcard.
   */
  private Collection<File> findMatchedFiles(final String uri, final File folder)
      throws IOException {
    if (uri == null || folder == null || !folder.isDirectory()) {
      final StringBuffer message = new StringBuffer("Invalid folder provided");
      if (folder != null) {
        message.append(", with path: " + folder.getPath());
      }
      message.append(", with fileNameWithWildcard: " + uri);
      throw new IOException(message.toString());
    }
    if (!hasWildcard(uri)) {
      throw new IOException("No wildcard detected for the uri: " + uri);
    }

    final String wildcard = FilenameUtils.getName(uri);
    LOG.debug("uri: {}", uri);
    LOG.debug("folder: {}", folder.getPath());
    LOG.debug("wildcard: {}", wildcard);

    // maps resource uri's and corresponding file
    // this map has to be ordered
    final Map<String, File> uriToFileMap = new TreeMap<String, File>();
    /**
     * Holds a list of all files (also folders, not only resources). This is useful for wildcard
     * expander processing.
     */
    final List<File> allFiles = new ArrayList<File>();

    final String uriFolder = FilenameUtils.getFullPathNoEndSeparator(uri);
    final String parentFolderPath = folder.getPath();

    final IOFileFilter fileFilter =
        new IOFileFilterDecorator(new WildcardFileFilter(wildcard)) {
          @Override
          public boolean accept(final File file) {
            final boolean accept = super.accept(file);
            if (accept) {
              allFiles.add(file);
              if (!file.isDirectory()) {
                final String relativeFilePath = file.getPath().replace(parentFolderPath, "");
                final String resourceUri = uriFolder + relativeFilePath.replace('\\', '/');
                uriToFileMap.put(resourceUri, file);
                LOG.debug("\tfoundUri: {}", resourceUri);
              }
            }
            return accept;
          }
        };
    FileUtils.listFiles(folder, fileFilter, getFolderFilter(wildcard));

    // TODO remove duplicates if needed:
    LOG.debug("map files: {}", uriToFileMap.keySet());

    final Collection<File> files = uriToFileMap.values();
    if (files.isEmpty()) {
      LOG.warn("No files found inside the {} for wildcard: {}", folder.getPath(), wildcard);
    }
    handleFoundResources(files);
    // trigger wildcardExpander processing
    handleFoundAllFiles(allFiles);
    return files;
  }
  public void run() throws IOException {
    IClearCaseAdapter cc = ClearCaseAdapterFactory.create();
    cc.setViewPath(new File(getViewPath()));

    // Find changed files between now and 'history days' back.
    List changedFiles =
        cc.findChangedFiles(
            DateOnlyUtil.addDays(new Date(), -getHistoryDays()),
            new Date(),
            new SuffixFileFilter("*"));

    // Build up the list of audits to run...
    List audits = new ArrayList();
    audits.add(new MissingCommentAudit());
    audits.add(new ContainsTabsAudit());
    List finalResults = new ArrayList();

    // Run the audits
    for (Iterator iter = audits.iterator(); iter.hasNext(); ) {
      IAudit audit = (IAudit) iter.next();
      finalResults.addAll(audit.audit(changedFiles));
    }

    // Sort the audit results
    Comparator sortByUser = new ObjectComparator("username", "filename");
    Collections.sort(finalResults, sortByUser);

    // Find the max length of the data in the results so the output looks
    // nice and lined up
    int maxUsername = getMaxLength(finalResults, "username");
    int maxFilename = getMaxLength(finalResults, "fileOnly");
    int maxReason = getMaxLength(finalResults, "reason");
    int maxDate = getMaxLength(finalResults, "date");

    // Create header row
    StringBuffer sb = new StringBuffer();
    sb.append(StringUtils.repeat("=", 80));
    sb.append("\n");
    sb.append(StringUtils.rightPad("User", maxUsername));
    sb.append(StringUtils.rightPad("File", maxFilename));
    sb.append(StringUtils.rightPad("Reason", maxReason));
    sb.append(StringUtils.rightPad("Timestamp", maxDate));
    sb.append("Dir\n");
    sb.append(StringUtils.repeat("=", 80));
    sb.append("\n");

    // Format the audit results
    for (ListIterator iter = finalResults.listIterator(); iter.hasNext(); ) {
      IAuditResult result = (IAuditResult) iter.next();

      sb.append(StringUtils.rightPad(getAlias(result.getUsername()), maxUsername));

      sb.append(StringUtils.rightPad(result.getFileOnly(), maxFilename));
      sb.append(StringUtils.rightPad(result.getReason(), maxReason));
      sb.append(StringUtils.rightPad(result.getDate(), maxDate));
      sb.append(FilenameUtils.getFullPathNoEndSeparator(result.getFilename()));
      sb.append("\n");
    }

    System.out.println(sb);
  }
  private int parseResourceDefinitions(final Node actionRootNode, final ILogger logger) {

    resourceDefinitions = new ListOrderedMap();

    try {
      List resources = actionRootNode.selectNodes("resources/*"); // $NON-NLS-1$

      // TODO create objects to represent the types
      // TODO need source variable list
      Iterator resourcesIterator = resources.iterator();

      Node resourceNode;
      String resourceName;
      String resourceTypeName;
      String resourceMimeType;
      int resourceType;
      ActionSequenceResource resource;
      Node typeNode, mimeNode;
      while (resourcesIterator.hasNext()) {
        resourceNode = (Node) resourcesIterator.next();
        typeNode = resourceNode.selectSingleNode("./*"); // $NON-NLS-1$
        if (typeNode != null) {
          resourceName = resourceNode.getName();
          resourceTypeName = typeNode.getName();
          resourceType = ActionSequenceResource.getResourceType(resourceTypeName);
          String resourceLocation = XmlDom4JHelper.getNodeText("location", typeNode); // $NON-NLS-1$
          if ((resourceType == IActionSequenceResource.SOLUTION_FILE_RESOURCE)
              || (resourceType == IActionSequenceResource.FILE_RESOURCE)) {
            if (resourceLocation == null) {
              logger.error(
                  Messages.getInstance()
                      .getErrorString(
                          "SequenceDefinition.ERROR_0008_RESOURCE_NO_LOCATION",
                          resourceName)); //$NON-NLS-1$
              continue;
            }
          } else if (resourceType == IActionSequenceResource.STRING) {
            resourceLocation = XmlDom4JHelper.getNodeText("string", resourceNode); // $NON-NLS-1$
          } else if (resourceType == IActionSequenceResource.XML) {
            // resourceLocation = XmlHelper.getNodeText("xml", resourceNode); //$NON-NLS-1$
            Node xmlNode = typeNode.selectSingleNode("./location/*"); // $NON-NLS-1$
            // Danger, we have now lost the character encoding of the XML in this node
            // see BISERVER-895
            resourceLocation = (xmlNode == null) ? "" : xmlNode.asXML(); // $NON-NLS-1$
          }
          mimeNode = typeNode.selectSingleNode("mime-type"); // $NON-NLS-1$
          if (mimeNode != null) {
            resourceMimeType = mimeNode.getText();
            if ((resourceType == IActionSequenceResource.SOLUTION_FILE_RESOURCE)
                || (resourceType == IActionSequenceResource.FILE_RESOURCE)) {
              resourceLocation = FilenameUtils.separatorsToUnix(resourceLocation);
              if (!resourceLocation.startsWith("/")) { // $NON-NLS-1$
                String parentDir = FilenameUtils.getFullPathNoEndSeparator(xactionPath);
                if (parentDir.length() == 0) {
                  parentDir = RepositoryFile.SEPARATOR;
                }
                resourceLocation =
                    FilenameUtils.separatorsToUnix(
                        FilenameUtils.concat(parentDir, resourceLocation));
              }
            }
            resource =
                new ActionSequenceResource(
                    resourceName, resourceType, resourceMimeType, resourceLocation);
            resourceDefinitions.put(resourceName, resource);
          } else {
            logger.error(
                Messages.getInstance()
                    .getErrorString(
                        "SequenceDefinition.ERROR_0007_RESOURCE_NO_MIME_TYPE",
                        resourceName)); //$NON-NLS-1$
          }
        }
        // input = new ActionParameter( resourceName, resourceType, null
        // );
        // resourceDefinitions.put( inputName, input );
      }
      return ISequenceDefinition.ACTION_SEQUENCE_DEFINITION_OK;
    } catch (Exception e) {
      logger.error(
          Messages.getInstance().getErrorString("SequenceDefinition.ERROR_0006_PARSING_RESOURCE"),
          e); //$NON-NLS-1$
    }
    return ISequenceDefinition.ACTION_SEQUENCE_DEFINITION_INVALID_ACTION_DOC;
  }