/** @return Returns true if the pattern is present, otherwise false. */
  public boolean like(
      NodeRef nodeRef, QName propertyQName, String sqlLikePattern, boolean includeFTS) {
    if (propertyQName == null) {
      throw new IllegalArgumentException("Property QName is mandatory for the like expression");
    }

    StringBuilder sb = new StringBuilder(sqlLikePattern.length() * 3);

    if (includeFTS) {
      // convert the SQL-like pattern into a Lucene-compatible string
      String pattern =
          SearchLanguageConversion.convertXPathLikeToLucene(sqlLikePattern.toLowerCase());

      // build Lucene search string specific to the node
      sb = new StringBuilder();
      sb.append("+ID:\"").append(nodeRef.toString()).append("\" +(");
      // FTS or attribute matches
      if (includeFTS) {
        sb.append("TEXT:(").append(pattern).append(") ");
      }
      if (propertyQName != null) {
        sb.append(" @")
            .append(
                SearchLanguageConversion.escapeLuceneQuery(
                    QName.createQName(
                            propertyQName.getNamespaceURI(),
                            ISO9075.encode(propertyQName.getLocalName()))
                        .toString()))
            .append(":(")
            .append(pattern)
            .append(")");
      }
      sb.append(")");

      ResultSet resultSet = null;
      try {
        resultSet = this.query(nodeRef.getStoreRef(), "lucene", sb.toString());
        boolean answer = resultSet.length() > 0;
        return answer;
      } finally {
        if (resultSet != null) {
          resultSet.close();
        }
      }
    } else {
      // convert the SQL-like pattern into a Lucene-compatible string
      String pattern =
          SearchLanguageConversion.convertXPathLikeToRegex(sqlLikePattern.toLowerCase());

      Serializable property = nodeService.getProperty(nodeRef, propertyQName);
      if (property == null) {
        return false;
      } else {
        String propertyString =
            DefaultTypeConverter.INSTANCE.convert(
                String.class, nodeService.getProperty(nodeRef, propertyQName));
        return propertyString.toLowerCase().matches(pattern);
      }
    }
  }
  /** @return Returns true if the pattern is present, otherwise false. */
  public boolean contains(
      NodeRef nodeRef,
      QName propertyQName,
      String googleLikePattern,
      SearchParameters.Operator defaultOperator) {
    ResultSet resultSet = null;
    try {
      // build Lucene search string specific to the node
      StringBuilder sb = new StringBuilder();
      sb.append("+ID:\"")
          .append(nodeRef.toString())
          .append("\" +(TEXT:(")
          .append(googleLikePattern.toLowerCase())
          .append(") ");
      if (propertyQName != null) {
        sb.append(" OR @")
            .append(
                SearchLanguageConversion.escapeLuceneQuery(
                    QName.createQName(
                            propertyQName.getNamespaceURI(),
                            ISO9075.encode(propertyQName.getLocalName()))
                        .toString()));
        sb.append(":(").append(googleLikePattern.toLowerCase()).append(")");
      } else {
        for (QName key : nodeService.getProperties(nodeRef).keySet()) {
          sb.append(" OR @")
              .append(
                  SearchLanguageConversion.escapeLuceneQuery(
                      QName.createQName(key.getNamespaceURI(), ISO9075.encode(key.getLocalName()))
                          .toString()));
          sb.append(":(").append(googleLikePattern.toLowerCase()).append(")");
        }
      }
      sb.append(")");

      SearchParameters sp = new SearchParameters();
      sp.setLanguage(SearchService.LANGUAGE_LUCENE);
      sp.setQuery(sb.toString());
      sp.setDefaultOperator(defaultOperator);
      sp.addStore(nodeRef.getStoreRef());

      resultSet = this.query(sp);
      boolean answer = resultSet.length() > 0;
      return answer;
    } finally {
      if (resultSet != null) {
        resultSet.close();
      }
    }
  }
 /** Searches for the node or nodes that match the path element for the given parent node */
 private List<NodeRef> getDirectDescendents(NodeRef pathRootNodeRef, String pathElement) {
   if (logger.isDebugEnabled()) {
     logger.debug(
         "Getting direct descendents: \n"
             + "   Path Root: "
             + pathRootNodeRef
             + "\n"
             + "   Path Element: "
             + pathElement);
   }
   List<NodeRef> results = null;
   // if this contains no wildcards, then we can fasttrack it
   if (!WildCard.containsWildcards(pathElement)) {
     // a specific name is required
     NodeRef foundNodeRef = fileFolderService.searchSimple(pathRootNodeRef, pathElement);
     if (foundNodeRef == null) {
       results = Collections.emptyList();
     } else {
       results = Collections.singletonList(foundNodeRef);
     }
   } else {
     // escape for the Lucene syntax search
     String escapedPathElement = SearchLanguageConversion.convertCifsToLucene(pathElement);
     // do the lookup
     List<org.alfresco.service.cmr.model.FileInfo> childInfos =
         fileFolderService.search(pathRootNodeRef, escapedPathElement, false);
     // convert to noderefs
     results = new ArrayList<NodeRef>(childInfos.size());
     for (org.alfresco.service.cmr.model.FileInfo info : childInfos) {
       results.add(info.getNodeRef());
     }
   }
   // done
   return results;
 }