Пример #1
0
 /** Test Going betwwen a NodeRef and a version, path pair. */
 public void testTranslate() {
   String avmPath = "main:/";
   int version = 2;
   NodeRef nodeRef = AVMNodeConverter.ToNodeRef(version, avmPath);
   System.out.println(nodeRef);
   Pair<Integer, String> backOut = AVMNodeConverter.ToAVMVersionPath(nodeRef);
   assertEquals(2, backOut.getFirst().intValue());
   assertEquals(avmPath, backOut.getSecond());
   avmPath = "main:/fista/mista/wisticuff";
   version = -1;
   nodeRef = AVMNodeConverter.ToNodeRef(version, avmPath);
   System.out.println(nodeRef);
   backOut = AVMNodeConverter.ToAVMVersionPath(nodeRef);
   assertEquals(-1, backOut.getFirst().intValue());
   assertEquals(avmPath, backOut.getSecond());
 }
  /**
   * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
   */
  public boolean evaluate(final Node node) {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    AVMService avmService = Repository.getServiceRegistry(facesContext).getAVMService();

    Pair<Integer, String> p = AVMNodeConverter.ToAVMVersionPath(node.getNodeRef());
    AVMNodeDescriptor nodeDesc = avmService.lookup(-1, p.getSecond());

    // don't allow action if its a 'layeredfolder' and a primary indirection
    return !(nodeDesc.getType() == AVMNodeType.LAYERED_DIRECTORY && nodeDesc.isPrimary());
  }
  /**
   * Returns the Ticket in the form used for HTTP Basic Authentication. This should be added as the
   * value to a HTTP Request Header with key Authorization
   */
  public String getAsHTTPAuthorization() {
    // Build from the Username and Password
    Pair<String, String> userPass = getAsUsernameAndPassword();
    Credentials credentials =
        new UsernamePasswordCredentials(userPass.getFirst(), userPass.getSecond());

    // Encode it into the required format
    String credentialsEncoded =
        Base64.encodeBytes(credentials.toString().getBytes(utf8), Base64.DONT_BREAK_LINES);

    // Mark it as Basic, and we're done
    return "Basic " + credentialsEncoded;
  }
  private String getAclTenant(long aclId) {
    List<Long> nodeIds = aclDAO.getADMNodesByAcl(aclId, 1);
    if (nodeIds.size() == 0) {
      return null;
    }

    nodeDAO.setCheckNodeConsistency();
    Pair<Long, NodeRef> nodePair = nodeDAO.getNodePair(nodeIds.get(0));
    if (nodePair == null) {
      return null;
    }

    return tenantService.getDomain(nodePair.getSecond().getStoreRef().getIdentifier());
  }
  /**
   * Helper method to set all values associated with the {@link #setChildNodeName(String) child node
   * name}.
   *
   * @param dictionaryService the service that determines how the CRC values are generated. If this
   *     is <tt>null</tt> then the CRC values are generated assuming that positive enforcement of
   *     the name constraint is required.
   * @param childNodeName the child node name
   */
  public void setChildNodeNameAll(
      DictionaryService dictionaryService, QName typeQName, String childNodeName) {
    ParameterCheck.mandatory("childNodeName", childNodeName);

    if (dictionaryService != null) {
      ParameterCheck.mandatory("typeQName", typeQName);

      Pair<String, Long> childNameUnique =
          ChildAssocEntity.getChildNameUnique(dictionaryService, typeQName, childNodeName);
      this.childNodeName = childNameUnique.getFirst();
      this.childNodeNameCrc = childNameUnique.getSecond();
    } else {
      String childNameNewLower = childNodeName.toLowerCase();
      this.childNodeName = ChildAssocEntity.getChildNodeNameShort(childNameNewLower);
      this.childNodeNameCrc = ChildAssocEntity.getChildNodeNameCrc(childNameNewLower);
    }
  }
  /**
   * Executes a solr query for statistics
   *
   * @param searchParameters StatsParameters
   * @return SolrStatsResult
   */
  public SolrStatsResult executeStatsQuery(final StatsParameters searchParameters) {
    if (repositoryState.isBootstrapping()) {
      throw new AlfrescoRuntimeException(
          "SOLR stats queries can not be executed while the repository is bootstrapping");
    }

    try {
      StoreRef store = extractStoreRef(searchParameters);
      SolrStoreMappingWrapper mapping = extractMapping(store);
      Locale locale = extractLocale(searchParameters);

      Pair<HttpClient, String> httpClientAndBaseUrl = mapping.getHttpClientAndBaseUrl();
      HttpClient httpClient = httpClientAndBaseUrl.getFirst();
      String url = buildStatsUrl(searchParameters, httpClientAndBaseUrl.getSecond(), locale);
      JSONObject body =
          buildStatsBody(searchParameters, tenantService.getCurrentUserDomain(), locale);

      if (httpClient == null) {
        throw new AlfrescoRuntimeException("No http client for store " + store.toString());
      }

      return (SolrStatsResult)
          postSolrQuery(
              httpClient,
              url,
              body,
              new SolrJsonProcessor<SolrStatsResult>() {

                @Override
                public SolrStatsResult getResult(JSONObject json) {
                  return new SolrStatsResult(json, searchParameters.isDateSearch());
                }
              });

    } catch (UnsupportedEncodingException e) {
      throw new LuceneQueryParserException("stats", e);
    } catch (HttpException e) {
      throw new LuceneQueryParserException("stats", e);
    } catch (IOException e) {
      throw new LuceneQueryParserException("stats", e);
    } catch (JSONException e) {
      throw new LuceneQueryParserException("stats", e);
    }
  }
  public ResultSet executeQuery(final SearchParameters searchParameters, String language) {
    if (repositoryState.isBootstrapping()) {
      throw new AlfrescoRuntimeException(
          "SOLR queries can not be executed while the repository is bootstrapping");
    }

    try {
      StoreRef store = extractStoreRef(searchParameters);
      SolrStoreMappingWrapper mapping = extractMapping(store);
      Locale locale = extractLocale(searchParameters);

      URLCodec encoder = new URLCodec();
      StringBuilder url = new StringBuilder();

      Pair<HttpClient, String> httpClientAndBaseUrl = mapping.getHttpClientAndBaseUrl();
      HttpClient httpClient = httpClientAndBaseUrl.getFirst();

      url.append(httpClientAndBaseUrl.getSecond());

      String languageUrlFragment = extractLanguageFragment(language);
      url.append("/").append(languageUrlFragment);

      // Send the query in JSON only
      // url.append("?q=");
      // url.append(encoder.encode(searchParameters.getQuery(), "UTF-8"));
      url.append("?wt=").append(encoder.encode("json", "UTF-8"));
      url.append("&fl=").append(encoder.encode("DBID,score", "UTF-8"));

      if ((searchParameters.getStores().size() > 1) || (mapping.isSharded())) {
        boolean requiresSeparator = false;
        url.append("&shards=");
        for (StoreRef storeRef : searchParameters.getStores()) {
          SolrStoreMappingWrapper storeMapping = extractMapping(storeRef);

          if (requiresSeparator) {
            url.append(',');
          } else {
            requiresSeparator = true;
          }

          url.append(storeMapping.getShards());
        }
      }

      // Emulate old limiting behaviour and metadata
      final LimitBy limitBy;
      int maxResults = -1;
      if (searchParameters.getMaxItems() >= 0) {
        maxResults = searchParameters.getMaxItems();
        limitBy = LimitBy.FINAL_SIZE;
      } else if (searchParameters.getLimitBy() == LimitBy.FINAL_SIZE
          && searchParameters.getLimit() >= 0) {
        maxResults = searchParameters.getLimit();
        limitBy = LimitBy.FINAL_SIZE;
      } else {
        maxResults = searchParameters.getMaxPermissionChecks();
        if (maxResults < 0) {
          maxResults = maximumResultsFromUnlimitedQuery;
        }
        limitBy = LimitBy.NUMBER_OF_PERMISSION_EVALUATIONS;
      }
      url.append("&rows=").append(String.valueOf(maxResults));

      url.append("&df=").append(encoder.encode(searchParameters.getDefaultFieldName(), "UTF-8"));
      url.append("&start=").append(encoder.encode("" + searchParameters.getSkipCount(), "UTF-8"));

      url.append("&locale=");
      url.append(encoder.encode(locale.toString(), "UTF-8"));
      url.append("&")
          .append(SearchParameters.ALTERNATIVE_DICTIONARY)
          .append("=")
          .append(alternativeDictionary);
      for (String paramName : searchParameters.getExtraParameters().keySet()) {
        url.append("&")
            .append(paramName)
            .append("=")
            .append(searchParameters.getExtraParameters().get(paramName));
      }
      StringBuffer sortBuffer = buildSortParameters(searchParameters, encoder);
      url.append(sortBuffer);

      if (searchParameters.getPermissionEvaluation() != PermissionEvaluationMode.NONE) {
        url.append("&fq=").append(encoder.encode("{!afts}AUTHORITY_FILTER_FROM_JSON", "UTF-8"));
      }

      if (searchParameters.getExcludeTenantFilter() == false) {
        url.append("&fq=").append(encoder.encode("{!afts}TENANT_FILTER_FROM_JSON", "UTF-8"));
      }

      if (searchParameters.getFieldFacets().size() > 0) {
        url.append("&facet=").append(encoder.encode("true", "UTF-8"));
        for (FieldFacet facet : searchParameters.getFieldFacets()) {
          url.append("&facet.field=").append(encoder.encode(facet.getField(), "UTF-8"));
          if (facet.getEnumMethodCacheMinDF() != 0) {
            url.append("&")
                .append(
                    encoder.encode("f." + facet.getField() + ".facet.enum.cache.minDf", "UTF-8"))
                .append("=")
                .append(encoder.encode("" + facet.getEnumMethodCacheMinDF(), "UTF-8"));
          }
          url.append("&")
              .append(encoder.encode("f." + facet.getField() + ".facet.limit", "UTF-8"))
              .append("=")
              .append(encoder.encode("" + facet.getLimit(), "UTF-8"));
          if (facet.getMethod() != null) {
            url.append("&")
                .append(encoder.encode("f." + facet.getField() + ".facet.method", "UTF-8"))
                .append("=")
                .append(
                    encoder.encode(
                        facet.getMethod() == FieldFacetMethod.ENUM ? "enum" : "fc", "UTF-8"));
          }
          if (facet.getMinCount() != 0) {
            url.append("&")
                .append(encoder.encode("f." + facet.getField() + ".facet.mincount", "UTF-8"))
                .append("=")
                .append(encoder.encode("" + facet.getMinCount(), "UTF-8"));
          }
          if (facet.getOffset() != 0) {
            url.append("&")
                .append(encoder.encode("f." + facet.getField() + ".facet.offset", "UTF-8"))
                .append("=")
                .append(encoder.encode("" + facet.getOffset(), "UTF-8"));
          }
          if (facet.getPrefix() != null) {
            url.append("&")
                .append(encoder.encode("f." + facet.getField() + ".facet.prefix", "UTF-8"))
                .append("=")
                .append(encoder.encode("" + facet.getPrefix(), "UTF-8"));
          }
          if (facet.getSort() != null) {
            url.append("&")
                .append(encoder.encode("f." + facet.getField() + ".facet.sort", "UTF-8"))
                .append("=")
                .append(
                    encoder.encode(
                        facet.getSort() == FieldFacetSort.COUNT ? "count" : "index", "UTF-8"));
          }
        }
        for (String facetQuery : searchParameters.getFacetQueries()) {
          url.append("&facet.query=").append(encoder.encode("{!afts}" + facetQuery, "UTF-8"));
        }
      }
      // end of field facets

      final String searchTerm = searchParameters.getSearchTerm();
      String spellCheckQueryStr = null;
      if (searchTerm != null && searchParameters.isSpellCheck()) {
        StringBuilder builder = new StringBuilder();
        builder.append("&spellcheck.q=").append(encoder.encode(searchTerm, "UTF-8"));
        builder.append("&spellcheck=").append(encoder.encode("true", "UTF-8"));
        spellCheckQueryStr = builder.toString();
        url.append(spellCheckQueryStr);
      }

      JSONObject body = new JSONObject();
      body.put("query", searchParameters.getQuery());

      // Authorities go over as is - and tenant mangling and query building takes place on the SOLR
      // side

      Set<String> allAuthorisations = permissionService.getAuthorisations();
      boolean includeGroups =
          includeGroupsForRoleAdmin
              ? true
              : !allAuthorisations.contains(PermissionService.ADMINISTRATOR_AUTHORITY);

      JSONArray authorities = new JSONArray();
      for (String authority : allAuthorisations) {
        if (includeGroups) {
          authorities.put(authority);
        } else {
          if (AuthorityType.getAuthorityType(authority) != AuthorityType.GROUP) {
            authorities.put(authority);
          }
        }
      }
      body.put("authorities", authorities);
      body.put("anyDenyDenies", anyDenyDenies);

      JSONArray tenants = new JSONArray();
      tenants.put(tenantService.getCurrentUserDomain());
      body.put("tenants", tenants);

      JSONArray locales = new JSONArray();
      for (Locale currentLocale : searchParameters.getLocales()) {
        locales.put(DefaultTypeConverter.INSTANCE.convert(String.class, currentLocale));
      }
      if (locales.length() == 0) {
        locales.put(I18NUtil.getLocale());
      }
      body.put("locales", locales);

      JSONArray templates = new JSONArray();
      for (String templateName : searchParameters.getQueryTemplates().keySet()) {
        JSONObject template = new JSONObject();
        template.put("name", templateName);
        template.put("template", searchParameters.getQueryTemplates().get(templateName));
        templates.put(template);
      }
      body.put("templates", templates);

      JSONArray allAttributes = new JSONArray();
      for (String attribute : searchParameters.getAllAttributes()) {
        allAttributes.put(attribute);
      }
      body.put("allAttributes", allAttributes);

      body.put("defaultFTSOperator", searchParameters.getDefaultFTSOperator());
      body.put("defaultFTSFieldOperator", searchParameters.getDefaultFTSFieldOperator());
      body.put("queryConsistency", searchParameters.getQueryConsistency());
      if (searchParameters.getMlAnalaysisMode() != null) {
        body.put("mlAnalaysisMode", searchParameters.getMlAnalaysisMode().toString());
      }
      body.put("defaultNamespace", searchParameters.getNamespace());

      JSONArray textAttributes = new JSONArray();
      for (String attribute : searchParameters.getTextAttributes()) {
        textAttributes.put(attribute);
      }
      body.put("textAttributes", textAttributes);

      final int maximumResults = maxResults; // just needed for the final parameter

      return (ResultSet)
          postSolrQuery(
              httpClient,
              url.toString(),
              body,
              new SolrJsonProcessor<SolrJSONResultSet>() {

                @Override
                public SolrJSONResultSet getResult(JSONObject json) {
                  return new SolrJSONResultSet(
                      json, searchParameters, nodeService, nodeDAO, limitBy, maximumResults);
                }
              },
              spellCheckQueryStr);
    } catch (UnsupportedEncodingException e) {
      throw new LuceneQueryParserException("", e);
    } catch (HttpException e) {
      throw new LuceneQueryParserException("", e);
    } catch (IOException e) {
      throw new LuceneQueryParserException("", e);
    } catch (JSONException e) {
      throw new LuceneQueryParserException("", e);
    }
  }
  public List<Pair<String, Integer>> getTopTerms(String field, int count) {
    ClosingIndexSearcher searcher = null;
    try {
      LinkedList<Pair<String, Integer>> answer = new LinkedList<Pair<String, Integer>>();
      searcher = getSearcher(indexer);
      IndexReader reader = searcher.getIndexReader();
      TermEnum terms = reader.terms(new Term(field, ""));
      do {
        Term term = terms.term();
        if (term != null) {
          if (!term.field().equals(field)) {
            break;
          }
          int freq = terms.docFreq();
          Pair<String, Integer> pair =
              new Pair<String, Integer>(term.text(), Integer.valueOf(freq));
          if (answer.size() < count) {
            if (answer.size() == 0) {
              answer.add(pair);
            } else if (answer.get(answer.size() - 1).getSecond().compareTo(pair.getSecond()) >= 0) {
              answer.add(pair);
            } else {
              for (ListIterator<Pair<String, Integer>> it = answer.listIterator();
                  it.hasNext(); /**/ ) {
                Pair<String, Integer> test = it.next();
                if (test.getSecond().compareTo(pair.getSecond()) < 0) {
                  it.previous();
                  it.add(pair);
                  break;
                }
              }
            }
          } else if (answer.get(count - 1).getSecond().compareTo(pair.getSecond()) < 0) {
            for (ListIterator<Pair<String, Integer>> it = answer.listIterator();
                it.hasNext(); /**/ ) {
              Pair<String, Integer> test = it.next();
              if (test.getSecond().compareTo(pair.getSecond()) < 0) {
                it.previous();
                it.add(pair);
                break;
              }
            }
            answer.removeLast();
          } else {
            // off the end
          }
        }
      } while (terms.next());
      terms.close();
      return answer;

    } catch (IOException e) {
      throw new SearcherException(e);
    } finally {
      if (searcher != null) {
        try {
          searcher.close();
        } catch (IOException e) {
          throw new SearcherException(e);
        }
      }
    }
  }
  /** {@inheritDoc} */
  public void getNodesMetadata(
      NodeMetaDataParameters nodeMetaDataParameters,
      MetaDataResultsFilter resultFilter,
      NodeMetaDataQueryCallback callback) {
    if (false == enabled) {
      return;
    }

    NodeMetaDataQueryRowHandler rowHandler = new NodeMetaDataQueryRowHandler(callback);
    boolean includeType = (resultFilter == null ? true : resultFilter.getIncludeType());
    boolean includeProperties = (resultFilter == null ? true : resultFilter.getIncludeProperties());
    boolean includeAspects = (resultFilter == null ? true : resultFilter.getIncludeAspects());
    boolean includePaths = (resultFilter == null ? true : resultFilter.getIncludePaths());
    boolean includeNodeRef = (resultFilter == null ? true : resultFilter.getIncludeNodeRef());
    boolean includeParentAssociations =
        (resultFilter == null ? true : resultFilter.getIncludeParentAssociations());
    boolean includeChildAssociations =
        (resultFilter == null ? true : resultFilter.getIncludeChildAssociations());
    boolean includeOwner = (resultFilter == null ? true : resultFilter.getIncludeOwner());
    boolean includeChildIds = (resultFilter == null ? true : resultFilter.getIncludeChildIds());
    boolean includeTxnId = (resultFilter == null ? true : resultFilter.getIncludeTxnId());

    List<Long> nodeIds = preCacheNodes(nodeMetaDataParameters);

    for (Long nodeId : nodeIds) {
      Status status = nodeDAO.getNodeIdStatus(nodeId);
      if (status == null) {
        // We've been called with the ID of a purged node, probably due to processing a transaction
        // with a
        // cascading delete. Fine to skip and assume it will be processed in a transaction.
        // See org.alfresco.solr.tracker.CoreTracker.updateDescendantAuxDocs(NodeMetaData, boolean,
        // SolrIndexSearcher)
        continue;
      }
      NodeRef nodeRef = status.getNodeRef();

      NodeMetaData nodeMetaData = new NodeMetaData();
      nodeMetaData.setNodeId(nodeId);

      if (includeNodeRef) {
        nodeMetaData.setNodeRef(tenantService.getBaseName(nodeRef, true));
      }

      if (includeTxnId) {
        nodeMetaData.setTxnId(status.getDbTxnId());
      }

      if (status.isDeleted()) {
        rowHandler.processResult(nodeMetaData);
        continue;
      }

      Map<QName, Serializable> props = null;
      Set<QName> aspects = null;

      nodeMetaData.setAclId(nodeDAO.getNodeAclId(nodeId));

      if (includeType) {
        QName nodeType = getNodeType(nodeId);
        if (nodeType != null) {
          nodeMetaData.setNodeType(nodeType);
        } else {
          throw new AlfrescoRuntimeException("Nodes with no type are ignored by SOLR");
        }
      }

      if (includeProperties) {
        if (props == null) {
          props = getProperties(nodeId);
        }
        nodeMetaData.setProperties(props);
      } else {
        nodeMetaData.setProperties(Collections.<QName, Serializable>emptyMap());
      }

      if (includeAspects || includePaths || includeParentAssociations) {
        aspects = getNodeAspects(nodeId);
      }
      nodeMetaData.setAspects(aspects);

      boolean ignoreLargeMetadata =
          (typeIndexFilter.shouldBeIgnored(getNodeType(nodeId))
              || aspectIndexFilter.shouldBeIgnored(getNodeAspects(nodeId)));
      if (!ignoreLargeMetadata
          && (typeIndexFilter.isIgnorePathsForSpecificTypes()
              || aspectIndexFilter.isIgnorePathsForSpecificAspects())) {
        // check if parent should be ignored
        final List<Long> parentIds = new LinkedList<Long>();
        nodeDAO.getParentAssocs(
            nodeId,
            null,
            null,
            true,
            new ChildAssocRefQueryCallback() {
              @Override
              public boolean preLoadNodes() {
                return false;
              }

              @Override
              public boolean orderResults() {
                return false;
              }

              @Override
              public boolean handle(
                  Pair<Long, ChildAssociationRef> childAssocPair,
                  Pair<Long, NodeRef> parentNodePair,
                  Pair<Long, NodeRef> childNodePair) {
                parentIds.add(parentNodePair.getFirst());
                return false;
              }

              @Override
              public void done() {}
            });

        if (!parentIds.isEmpty()) {
          Long parentId = parentIds.iterator().next();
          if (typeIndexFilter.isIgnorePathsForSpecificTypes()) {
            QName parentType = getNodeType(parentId);
            ignoreLargeMetadata = typeIndexFilter.shouldBeIgnored(parentType);
          }
          if (!ignoreLargeMetadata && aspectIndexFilter.isIgnorePathsForSpecificAspects()) {
            ignoreLargeMetadata = aspectIndexFilter.shouldBeIgnored(getNodeAspects(parentId));
          }
        }
      }

      CategoryPaths categoryPaths =
          new CategoryPaths(
              new ArrayList<Pair<Path, QName>>(), new ArrayList<ChildAssociationRef>());
      if (!ignoreLargeMetadata && (includePaths || includeParentAssociations)) {
        if (props == null) {
          props = getProperties(nodeId);
        }
        categoryPaths = getCategoryPaths(status.getNodeRef(), aspects, props);
      }

      if (includePaths && !ignoreLargeMetadata) {
        if (props == null) {
          props = getProperties(nodeId);
        }

        List<Path> directPaths =
            nodeDAO.getPaths(new Pair<Long, NodeRef>(nodeId, status.getNodeRef()), false);

        Collection<Pair<Path, QName>> paths =
            new ArrayList<Pair<Path, QName>>(directPaths.size() + categoryPaths.getPaths().size());
        for (Path path : directPaths) {
          paths.add(new Pair<Path, QName>(path.getBaseNamePath(tenantService), null));
        }
        for (Pair<Path, QName> catPair : categoryPaths.getPaths()) {
          paths.add(
              new Pair<Path, QName>(
                  catPair.getFirst().getBaseNamePath(tenantService), catPair.getSecond()));
        }

        nodeMetaData.setPaths(paths);

        // Calculate name path
        Collection<Collection<String>> namePaths = new ArrayList<Collection<String>>(2);
        nodeMetaData.setNamePaths(namePaths);
        for (Pair<Path, QName> catPair : paths) {
          Path path = catPair.getFirst();

          boolean added = false;
          List<String> namePath = new ArrayList<String>(path.size());
          NEXT_ELEMENT:
          for (Path.Element pathElement : path) {
            if (!(pathElement instanceof ChildAssocElement)) {
              // This is some path element that is terminal to a cm:name path
              break;
            }
            ChildAssocElement pathChildAssocElement = (ChildAssocElement) pathElement;
            NodeRef childNodeRef = pathChildAssocElement.getRef().getChildRef();
            Pair<Long, NodeRef> childNodePair = nodeDAO.getNodePair(childNodeRef);
            if (childNodePair == null) {
              // Gone
              break;
            }
            Long childNodeId = childNodePair.getFirst();
            String childNodeName =
                (String) nodeDAO.getNodeProperty(childNodeId, ContentModel.PROP_NAME);
            if (childNodeName == null) {
              // We have hit a non-name node, which acts as a root for cm:name
              // DH: There is no particular constraint here.  This is just a decision made.
              namePath.clear();
              // We have to continue down the path as there could be a name path lower down
              continue NEXT_ELEMENT;
            }
            // We can finally add the name to the path
            namePath.add(childNodeName);
            // Add the path if this is the first entry in the name path
            if (!added) {
              namePaths.add(namePath);
              added = true;
            }
          }
        }
      }

      nodeMetaData.setTenantDomain(tenantService.getDomain(nodeRef.getStoreRef().getIdentifier()));

      if (includeChildAssociations) {
        final List<ChildAssociationRef> childAssocs = new ArrayList<ChildAssociationRef>(100);
        nodeDAO.getChildAssocs(
            nodeId,
            null,
            null,
            null,
            null,
            null,
            new ChildAssocRefQueryCallback() {
              @Override
              public boolean preLoadNodes() {
                return false;
              }

              @Override
              public boolean orderResults() {
                return false;
              }

              @Override
              public boolean handle(
                  Pair<Long, ChildAssociationRef> childAssocPair,
                  Pair<Long, NodeRef> parentNodePair,
                  Pair<Long, NodeRef> childNodePair) {
                boolean addCurrentChildAssoc = true;
                if (typeIndexFilter.isIgnorePathsForSpecificTypes()) {
                  QName nodeType = nodeDAO.getNodeType(childNodePair.getFirst());
                  addCurrentChildAssoc = !typeIndexFilter.shouldBeIgnored(nodeType);
                }
                if (!addCurrentChildAssoc && aspectIndexFilter.isIgnorePathsForSpecificAspects()) {
                  addCurrentChildAssoc =
                      !aspectIndexFilter.shouldBeIgnored(getNodeAspects(childNodePair.getFirst()));
                }
                if (addCurrentChildAssoc) {
                  childAssocs.add(tenantService.getBaseName(childAssocPair.getSecond(), true));
                }
                return true;
              }

              @Override
              public void done() {}
            });
        nodeMetaData.setChildAssocs(childAssocs);
      }

      if (includeChildIds) {
        final List<Long> childIds = new ArrayList<Long>(100);
        nodeDAO.getChildAssocs(
            nodeId,
            null,
            null,
            null,
            null,
            null,
            new ChildAssocRefQueryCallback() {
              @Override
              public boolean preLoadNodes() {
                return false;
              }

              @Override
              public boolean orderResults() {
                return false;
              }

              @Override
              public boolean handle(
                  Pair<Long, ChildAssociationRef> childAssocPair,
                  Pair<Long, NodeRef> parentNodePair,
                  Pair<Long, NodeRef> childNodePair) {
                boolean addCurrentId = true;
                if (typeIndexFilter.isIgnorePathsForSpecificTypes()) {
                  QName nodeType = nodeDAO.getNodeType(childNodePair.getFirst());
                  addCurrentId = !typeIndexFilter.shouldBeIgnored(nodeType);
                }
                if (!addCurrentId) {
                  addCurrentId =
                      !aspectIndexFilter.shouldBeIgnored(getNodeAspects(childNodePair.getFirst()));
                }
                if (addCurrentId) {
                  childIds.add(childNodePair.getFirst());
                }
                return true;
              }

              @Override
              public void done() {}
            });
        nodeMetaData.setChildIds(childIds);
      }

      if (includeParentAssociations && !ignoreLargeMetadata) {
        final List<ChildAssociationRef> parentAssocs = new ArrayList<ChildAssociationRef>(100);
        nodeDAO.getParentAssocs(
            nodeId,
            null,
            null,
            null,
            new ChildAssocRefQueryCallback() {
              @Override
              public boolean preLoadNodes() {
                return false;
              }

              @Override
              public boolean orderResults() {
                return false;
              }

              @Override
              public boolean handle(
                  Pair<Long, ChildAssociationRef> childAssocPair,
                  Pair<Long, NodeRef> parentNodePair,
                  Pair<Long, NodeRef> childNodePair) {
                parentAssocs.add(tenantService.getBaseName(childAssocPair.getSecond(), true));
                return true;
              }

              @Override
              public void done() {}
            });
        for (ChildAssociationRef ref : categoryPaths.getCategoryParents()) {
          parentAssocs.add(tenantService.getBaseName(ref, true));
        }

        CRC32 crc = new CRC32();
        for (ChildAssociationRef car : parentAssocs) {
          try {
            crc.update(car.toString().getBytes("UTF-8"));
          } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("UTF-8 encoding is not supported");
          }
        }
        nodeMetaData.setParentAssocs(parentAssocs, crc.getValue());

        // TODO non-child associations
        //                Collection<Pair<Long, AssociationRef>> sourceAssocs =
        // nodeDAO.getSourceNodeAssocs(nodeId);
        //                Collection<Pair<Long, AssociationRef>> targetAssocs =
        // nodeDAO.getTargetNodeAssocs(nodeId);
        //
        //                nodeMetaData.setAssocs();
      }

      if (includeOwner) {
        // cached in OwnableService
        nodeMetaData.setOwner(ownableService.getOwner(status.getNodeRef()));
      }

      rowHandler.processResult(nodeMetaData);
    }
  }