@Override
 public void deleteTag(Tag tag, boolean autoSave) throws AccessControlException {
   try {
     resourceResolver.delete(tag.adaptTo(Resource.class));
     if (autoSave) {
       resourceResolver.commit();
       resourceResolver.refresh();
     }
   } catch (PersistenceException e) {
     log.error("error deleting tag", e);
   }
 }
  private List<String> makeTags(
      final TagManager tagManager,
      final List<TagDataConverter> tagDataConverters,
      final Iterator<String[]> rows)
      throws InvalidTagFormatException, RepositoryException {

    final Set<String> result = new LinkedHashSet<String>();

    while (rows.hasNext()) {
      final String[] row = rows.next();

      log.debug("Processing data from row {}", Arrays.asList(row));

      String tagId = null;

      for (int i = 0; i < row.length; i++) {
        TagData tagData = null;

        final String element = StringUtils.trimToNull(row[i]);

        if (element == null) {
          log.warn("Element is null skipping this row [ {} ]", tagId);
          break;
        }

        for (final TagDataConverter tagDataConverter : tagDataConverters) {
          if (tagDataConverter.accepts(element)) {
            tagData = tagDataConverter.convert(element);
            break;
          }
        }

        if (tagData == null) {
          log.warn(
              "Could not find a Tag Data Converter that accepts CSV element [ {} ]; skipping...");
          break;
        } else if (!tagData.isValid()) {
          log.warn("Could not convert CSV element [ {} ] into valid Tag Data; skipping...");
          break;
        }
        if (i == 0) {
          // Tag Namespace
          tagId = tagData.getName() + TagConstants.NAMESPACE_DELIMITER;
        } else if (i == 1) {
          // First Tag under Namespace
          tagId += tagData.getName();
        } else {
          // Subsequent Tags
          tagId += "/" + tagData.getName();
        }

        final Tag tag = tagManager.createTag(tagId, tagData.getTitle(), tagData.getDescription());
        log.trace("Created Tag [ {} ] with Title [ {} ]", tag.getTagID(), tagData.getTitle());

        result.add(tagId);
      }
    }

    if (tagManager.getSession().hasPendingChanges()) {
      final long start = System.currentTimeMillis();
      tagManager.getSession().save();
      log.info("Persisting tags to JCR in {} ms", System.currentTimeMillis() - start);
    }

    return new ArrayList<String>(result);
  }
  @Override
  public RangeIterator<Resource> find(String basePath, String[] tagIDs, boolean oneMatchIsEnough) {
    Resource base = resourceResolver.getResource(basePath);
    if (base == null) {
      return new CollectionRangeIterator<Resource>(Collections.<Resource>emptyList());
    }

    Collection<String> tagPaths = new HashSet<String>(tagIDs.length);
    for (String tagID : tagIDs) {
      Tag tag = resolve(tagID);
      // clause - if tag does not exist, should return null.
      if (tag == null) {
        return null;
      }
      tagPaths.add(tag.adaptTo(Resource.class).getPath());
    }

    Queue<Resource> searchResources = new LinkedList<Resource>();
    searchResources.add(base);

    Collection<Resource> matchedResources = new ArrayList<Resource>();

    while (!searchResources.isEmpty()) {
      Resource resource = searchResources.poll();
      // add the children to search the entire tree
      CollectionUtils.addAll(searchResources, resource.listChildren());

      // now process the tags
      String[] resourceTags = resource.getValueMap().get(TagConstants.PN_TAGS, String[].class);
      if (resourceTags == null) {
        continue;
      }

      List<String> resourceTagPaths = new ArrayList<String>(resourceTags.length);
      try {
        for (String resourceTag : resourceTags) {
          resourceTagPaths.add(getPathFromID(resourceTag));
        }
      } catch (InvalidTagFormatException e) {
        log.error("invalid tag id encountered", e);
      }

      if (resourceTagPaths.isEmpty()) {
        continue;
      }

      boolean matches = false;
      if (oneMatchIsEnough) {
        // this is essentially an OR list, so break out on the first positive
        oneMatched:
        for (String tagPath : tagPaths) {
          for (String resourceTagPath : resourceTagPaths) {
            matches = doTagsMatch(resourceTagPath, tagPath);
            if (matches) {
              break oneMatched;
            }
          }
        }
      } else {
        // this is essentially an AND list, so break out on the first failure
        matches = true;
        for (String tagPath : tagPaths) {
          boolean tagMatched = false;
          for (Iterator<String> resourceTagPathIter = resourceTagPaths.iterator();
              !tagMatched && resourceTagPathIter.hasNext(); ) {
            String resourceTagPath = resourceTagPathIter.next();
            tagMatched = doTagsMatch(resourceTagPath, tagPath);
          }
          // if no tag on the resource matched the current search tag, it fails the search
          if (!tagMatched) {
            matches = false;
            break;
          }
        }
      }

      if (matches) {
        matchedResources.add(resource);
      }
    }

    return new CollectionRangeIterator<Resource>(matchedResources);
  }