예제 #1
0
  /* (non-Javadoc)
   * @see org.alfresco.service.cmr.view.Exporter#startNode(org.alfresco.service.cmr.repository.NodeRef)
   */
  public void startNode(NodeRef nodeRef) {
    try {
      AttributesImpl attrs = new AttributesImpl();

      Path path = nodeService.getPath(nodeRef);
      if (path.size() > 1) {
        // a child name does not exist for root
        Path.ChildAssocElement pathElement = (Path.ChildAssocElement) path.last();
        QName childQName = pathElement.getRef().getQName();
        attrs.addAttribute(
            NamespaceService.REPOSITORY_VIEW_1_0_URI,
            CHILDNAME_LOCALNAME,
            CHILDNAME_QNAME.toPrefixString(),
            null,
            toPrefixString(childQName));
      }

      QName type = nodeService.getType(nodeRef);
      contentHandler.startElement(
          type.getNamespaceURI(), type.getLocalName(), toPrefixString(type), attrs);
    } catch (SAXException e) {
      throw new ExporterException(
          "Failed to process start node event - node ref " + nodeRef.toString(), e);
    }
  }
예제 #2
0
  /**
   * Helper to convert a path into an indexed path which uniquely identifies a node
   *
   * @param nodeRef
   * @param path
   * @return
   */
  private Path createIndexedPath(NodeRef nodeRef, Path path) {
    // Add indexes for same name siblings
    // TODO: Look at more efficient approach
    for (int i = path.size() - 1; i >= 0; i--) {
      Path.Element pathElement = path.get(i);
      if (i > 0 && pathElement instanceof Path.ChildAssocElement) {
        int index = 1; // for xpath index compatibility
        String searchPath = path.subPath(i).toPrefixString(namespaceService);
        List<NodeRef> siblings =
            searchService.selectNodes(nodeRef, searchPath, null, namespaceService, false);
        if (siblings.size() > 1) {
          ChildAssociationRef childAssoc = ((Path.ChildAssocElement) pathElement).getRef();
          NodeRef childRef = childAssoc.getChildRef();
          for (NodeRef sibling : siblings) {
            if (sibling.equals(childRef)) {
              childAssoc.setNthSibling(index);
              break;
            }
            index++;
          }
        }
      }
    }

    return path;
  }
예제 #3
0
 /**
  * Returns human readable path for node. To improve performance may return simple toString()
  * method of the path.
  *
  * @param nodeRef
  * @return Human readable path for node
  */
 private String getNodePath(NodeRef nodeRef) {
   String result = null;
   if (nodeService.exists(nodeRef)) {
     Path path = nodeService.getPath(nodeRef);
     return path.toPrefixString(namespacePrefixResolver);
   }
   return result;
 }
예제 #4
0
  /**
   * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
   */
  public boolean evaluate(Node node) {
    final FacesContext fc = FacesContext.getCurrentInstance();
    final ServiceRegistry services = Repository.getServiceRegistry(fc);
    final NavigationBean navigator =
        (NavigationBean) FacesHelper.getManagedBean(fc, NavigationBean.BEAN_NAME);

    // get the path to the current name - compare last element with the Forms folder name
    final Path path = navigator.getCurrentNode().getNodePath();
    final Path.Element element = path.get(path.size() - 1);
    final String endPath = element.getPrefixedString(services.getNamespaceService());

    // check we have the permission to create nodes in that Forma folder
    return (Application.getContentFormsFolderName(fc).equals(endPath)
        && navigator.getCurrentNode().hasPermission(PermissionService.ADD_CHILDREN));
  }
  /**
   * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
   */
  public boolean evaluate(final Node node) {
    // is the authenticated user permitted to execute the regenerate renditions action
    // against at least one web project
    boolean isUserAllowed = false;

    final FacesContext fc = FacesContext.getCurrentInstance();
    final ServiceRegistry services = Repository.getServiceRegistry(fc);
    final PermissionService permissionService = services.getPermissionService();
    final WebProjectService webProjectService = services.getWebProjectService();
    final NavigationBean navigator =
        (NavigationBean) FacesHelper.getManagedBean(fc, NavigationBean.BEAN_NAME);

    // check that the authenticated user has CONTENT MANAGER permissions for at least one web
    // project
    // this will ensure that the action appears only if the user is able to regenerate renditions
    // for at least one web project
    List<WebProjectInfo> wpInfos = webProjectService.listWebProjects();
    for (WebProjectInfo wpInfo : wpInfos) {
      if (permissionService.hasPermission(
              wpInfo.getNodeRef(), PermissionService.WCM_CONTENT_MANAGER)
          == AccessStatus.ALLOWED) {
        isUserAllowed = true;
        break;
      }
    }

    // TODO improve how we determine whether the form supports the ability to regenerate renditions
    // or not

    // get the path to the current name - compare each path element with the Web Forms folder name
    final Path path = navigator.getCurrentNode().getNodePath();

    boolean isWebFormsPath = false;
    Iterator<Path.Element> itr = path.iterator();
    while (itr.hasNext()) {
      Path.Element element = (Path.Element) itr.next();
      String pathElement = element.getPrefixedString(services.getNamespaceService());
      if (Application.getWebContentFormsFolderName(fc).equals(pathElement)) {
        isWebFormsPath = true;
        break;
      }
    }

    return (node.hasAspect(WCMAppModel.ASPECT_RENDERING_ENGINE_TEMPLATE) || isWebFormsPath)
        && isUserAllowed;
  }
예제 #6
0
  /* (non-Javadoc)
   * @see org.alfresco.service.cmr.view.Exporter#startReference(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName)
   */
  public void startReference(NodeRef nodeRef, QName childName) {
    try {
      // determine format of reference e.g. node or path based
      ReferenceType referenceFormat = referenceType;
      if (nodeRef.equals(nodeService.getRootNode(nodeRef.getStoreRef()))) {
        referenceFormat = ReferenceType.PATHREF;
      }

      // output reference
      AttributesImpl attrs = new AttributesImpl();
      if (referenceFormat.equals(ReferenceType.PATHREF)) {
        Path path = createPath(context.getExportParent(), context.getExportParent(), nodeRef);
        attrs.addAttribute(
            NamespaceService.REPOSITORY_VIEW_1_0_URI,
            PATHREF_LOCALNAME,
            PATHREF_QNAME.toPrefixString(),
            null,
            path.toPrefixString(namespaceService));
      } else {
        attrs.addAttribute(
            NamespaceService.REPOSITORY_VIEW_1_0_URI,
            NODEREF_LOCALNAME,
            NODEREF_QNAME.toPrefixString(),
            null,
            nodeRef.toString());
      }
      if (childName != null) {
        attrs.addAttribute(
            NamespaceService.REPOSITORY_VIEW_1_0_URI,
            CHILDNAME_LOCALNAME,
            CHILDNAME_QNAME.toPrefixString(),
            null,
            childName.toPrefixString(namespaceService));
      }
      contentHandler.startElement(
          REFERENCE_QNAME.getNamespaceURI(),
          REFERENCE_LOCALNAME,
          toPrefixString(REFERENCE_QNAME),
          attrs);
    } catch (SAXException e) {
      throw new ExporterException("Failed to process start reference", e);
    }
  }
예제 #7
0
  /**
   * Return relative path between from and to references within export root
   *
   * @param fromRef from reference
   * @param toRef to reference
   * @return path
   */
  private Path createPath(NodeRef rootRef, NodeRef fromRef, NodeRef toRef) {
    // Check that item exists first
    if (!nodeService.exists(toRef)) {
      // return null path
      return null;
    }

    // Check whether item is the root node of the store
    // If so, always return absolute path
    if (toRef.equals(nodeService.getRootNode(toRef.getStoreRef()))) {
      return nodeService.getPath(toRef);
    }

    // construct relative path
    Path rootPath = createIndexedPath(rootRef, nodeService.getPath(rootRef));
    Path fromPath = createIndexedPath(fromRef, nodeService.getPath(fromRef));
    Path toPath = createIndexedPath(toRef, nodeService.getPath(toRef));
    Path relativePath = null;

    try {
      // Determine if 'to path' is a category
      // TODO: This needs to be resolved in a more appropriate manner - special support is
      //       required for categories.
      for (int i = 0; i < toPath.size(); i++) {
        Path.Element pathElement = toPath.get(i);
        if (pathElement.getPrefixedString(namespaceService).equals("cm:categoryRoot")) {
          Path.ChildAssocElement childPath = (Path.ChildAssocElement) pathElement;
          relativePath = new Path();
          relativePath.append(
              new Path.ChildAssocElement(
                  new ChildAssociationRef(null, null, null, childPath.getRef().getParentRef())));
          relativePath.append(toPath.subPath(i + 1, toPath.size() - 1));
          break;
        }
      }

      if (relativePath == null) {
        // Determine if from node is relative to export tree
        int i = 0;
        while (i < rootPath.size()
            && i < fromPath.size()
            && rootPath.get(i).equals(fromPath.get(i))) {
          i++;
        }
        if (i == rootPath.size()) {
          // Determine if to node is relative to export tree
          i = 0;
          while (i < rootPath.size()
              && i < toPath.size()
              && rootPath.get(i).equals(toPath.get(i))) {
            i++;
          }
          if (i == rootPath.size()) {
            // build relative path between from and to
            relativePath = new Path();
            for (int p = 0; p < fromPath.size() - i; p++) {
              relativePath.append(new Path.ParentElement());
            }
            if (i < toPath.size()) {
              relativePath.append(toPath.subPath(i, toPath.size() - 1));
            }
          }
        }
      }

      if (relativePath == null) {
        // default to absolute path
        relativePath = toPath;
      }
    } catch (Throwable e) {
      String msg =
          "Failed to determine relative path: root path="
              + rootPath
              + "; from path="
              + fromPath
              + "; to path="
              + toPath;
      throw new ExporterException(msg, e);
    }

    return relativePath;
  }
예제 #8
0
  /* (non-Javadoc)
   * @see org.alfresco.service.cmr.view.Exporter#value(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, java.io.Serializable)
   */
  public void value(NodeRef nodeRef, QName property, Object value, int index) {
    try {
      // determine data type of value
      QName valueDataType = null;
      PropertyDefinition propDef = dictionaryService.getProperty(property);
      DataTypeDefinition dataTypeDef = (propDef == null) ? null : propDef.getDataType();
      if (dataTypeDef == null || dataTypeDef.getName().equals(DataTypeDefinition.ANY)) {
        dataTypeDef = (value == null) ? null : dictionaryService.getDataType(value.getClass());
        if (dataTypeDef != null) {
          valueDataType = dataTypeDef.getName();
        }
      }

      // convert node references to paths
      if (value instanceof NodeRef && referenceType.equals(ReferenceType.PATHREF)) {
        NodeRef valueNodeRef = (NodeRef) value;
        if (nodeRef.getStoreRef().equals(valueNodeRef.getStoreRef())) {
          Path nodeRefPath = createPath(context.getExportOf(), nodeRef, valueNodeRef);
          value = (nodeRefPath == null) ? null : nodeRefPath.toPrefixString(namespaceService);
        }
      }

      // output value wrapper if value is null or property data type is ANY or value is part of
      // collection
      if (value == null || valueDataType != null || index != -1) {
        AttributesImpl attrs = new AttributesImpl();
        if (value == null) {
          attrs.addAttribute(
              NamespaceService.REPOSITORY_VIEW_PREFIX,
              ISNULL_LOCALNAME,
              ISNULL_QNAME.toPrefixString(),
              null,
              "true");
        }
        if (valueDataType != null) {
          attrs.addAttribute(
              NamespaceService.REPOSITORY_VIEW_PREFIX,
              DATATYPE_LOCALNAME,
              DATATYPE_QNAME.toPrefixString(),
              null,
              toPrefixString(valueDataType));
        }
        contentHandler.startElement(
            NamespaceService.REPOSITORY_VIEW_PREFIX,
            VALUE_LOCALNAME,
            toPrefixString(VALUE_QNAME),
            attrs);
      }

      // output value
      String strValue = (String) DefaultTypeConverter.INSTANCE.convert(String.class, value);
      if (strValue != null) {
        for (int i = 0; i < strValue.length(); i++) {
          char[] temp = new char[] {strValue.charAt(i)};
          contentHandler.characters(temp, 0, 1);
        }
      }

      // output value wrapper if property data type is any
      if (value == null || valueDataType != null || index != -1) {
        contentHandler.endElement(
            NamespaceService.REPOSITORY_VIEW_PREFIX, VALUE_LOCALNAME, toPrefixString(VALUE_QNAME));
      }
    } catch (SAXException e) {
      throw new ExporterException(
          "Failed to process value event - nodeRef "
              + nodeRef
              + "; property "
              + toPrefixString(property)
              + "; value "
              + value,
          e);
    }
  }
예제 #9
0
  protected Set<String> getPaths(boolean primaryOnly) throws AfException {

    if (isNew()) {
      throw new AfException("this object is new, you can not get any paths");
    }

    if (!nodeRef.getStoreRef().equals(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE)) {
      throw new AfException("you cannot query the object's paths that is not in workspace");
    }

    NodeService nodeService = ServiceHelper.getNodeService(afSession);

    List<Path> ps = nodeService.getPaths(nodeRef, primaryOnly);
    Set<String> paths = new HashSet<String>();

    //		NodeRef parent = AFCHelper.getNodeRefByPath(afSession, "/");

    for (Path p : ps) {

      StringBuffer realPath = new StringBuffer();

      int length = p.size();
      for (int i = 0; i < length; i++) {

        QName qname = QName.createQName(p.get(i).getElementString());
        String fname = qname.getLocalName();

        if (fname.equals("/") || fname.equals("company_home")) {
          continue;
        } else if ("system".equals(fname) && i == 1) {
          break;
        }

        realPath.append('/');
        if (i == length - 1) {
          realPath.append(getObjectName());
        } else {
          realPath.append(ISO9075.decode(fname));
        }
      }

      if (realPath.length() != 0) {
        paths.add(realPath.toString());
      }
    }

    //		for (Path p : ps) {
    //
    //			NodeRef tmpParent = parent;
    //
    //			String realPath = "";
    //			for (int i = 0; i < p.size(); i++) {
    //				QName qname = QName.createQName(p.get(i).getElementString());
    //				String fname = qname.getLocalName();
    //
    //				if (fname.equals("/") || fname.equals("company_home")) {
    //					continue;
    //				}
    //
    //				String name = ISO9075.decode(fname);
    //
    //				tmpParent = getChildByAssName(nodeService, tmpParent, name);
    //
    //				if (tmpParent == null) {
    //					break;
    //				}
    //
    //				realPath += "/" + getNodeName(nodeService, tmpParent);
    //
    //			}
    //
    //			if (!realPath.equals("")) {
    // 				paths.add(realPath);
    //			}
    //
    //		}
    return paths;
  }
예제 #10
0
  /**
   * Returns a list of NodeRefs representing the deployment servers configured for the given web
   * project.
   *
   * @param webProject Web project to get test servers for
   * @param live
   * @param availableOnly if true only returns those servers still available for deployment
   * @return List of test servers
   */
  private static List<NodeRef> findServers(
      NodeRef webProject, boolean live, boolean availableOnly) {
    FacesContext context = FacesContext.getCurrentInstance();
    NodeService nodeService = Repository.getServiceRegistry(context).getNodeService();
    SearchService searchService = Repository.getServiceRegistry(context).getSearchService();

    NamespacePrefixResolver namespacePrefixResolver =
        Repository.getServiceRegistry(context).getNamespaceService();

    Path projectPath = nodeService.getPath(webProject);

    String stringPath = projectPath.toPrefixString(namespacePrefixResolver);

    StringBuilder query = new StringBuilder("PATH:\"");

    query.append(stringPath);
    query.append("/*\" ");
    query.append(" AND @");
    query.append(NamespaceService.WCMAPP_MODEL_PREFIX);
    query.append("\\:");
    query.append(WCMAppModel.PROP_DEPLOYSERVERTYPE.getLocalName());
    query.append(":\"");
    if (live) {
      query.append(WCMAppModel.CONSTRAINT_LIVESERVER);
    } else {
      query.append(WCMAppModel.CONSTRAINT_TESTSERVER);
    }
    query.append("\"");

    // if required filter the test servers
    if (live == false && availableOnly) {
      query.append(" AND ISNULL:\"");
      query.append(WCMAppModel.PROP_DEPLOYSERVERALLOCATEDTO.toString());
      query.append("\"");
    }

    if (logger.isDebugEnabled())
      logger.debug("Finding deployment servers using query: " + query.toString());

    // execute the query
    ResultSet results = null;
    List<NodeRef> servers = new ArrayList<NodeRef>();
    try {
      results =
          searchService.query(
              Repository.getStoreRef(), SearchService.LANGUAGE_LUCENE, query.toString());

      if (logger.isDebugEnabled())
        logger.debug("Found " + results.length() + " deployment servers");

      for (NodeRef server : results.getNodeRefs()) {
        servers.add(server);
      }
    } finally {
      if (results != null) {
        results.close();
      }
    }

    return servers;
  }
  /** {@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);
    }
  }