stefan      2004/07/07 09:04:38

  Added:       proposals/jcrri/src/org/apache/slide/jcr/core
                        HierarchyManagerImpl.java
  Log:
  jcrri
  
  Revision  Changes    Path
  1.1                  
jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/HierarchyManagerImpl.java
  
  Index: HierarchyManagerImpl.java
  ===================================================================
  /*
   * $Id: HierarchyManagerImpl.java,v 1.1 2004/07/07 16:04:38 stefan Exp $
   *
   * Copyright 2002-2004 Day Management AG, Switzerland.
   *
   * Licensed under the Day RI License, Version 2.0 (the "License"),
   * as a reference implementation of the following specification:
   *
   *   Content Repository API for Java Technology, revision 0.13
   *        <http://www.jcp.org/en/jsr/detail?id=170>
   *
   * You may not use this file except in compliance with the License.
   * You may obtain a copy of the License files at
   *
   *     http://www.day.com/content/en/licenses/day-ri-license-2.0
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.slide.jcr.core;
  
  import org.apache.slide.jcr.core.state.*;
  import org.apache.slide.jcr.util.MalformedPathException;
  import org.apache.log4j.Logger;
  
  import javax.jcr.ItemNotFoundException;
  import javax.jcr.RepositoryException;
  import javax.jcr.PathNotFoundException;
  import java.util.*;
  
  /**
   * <code>HierarchyManagerImpl</code> ...
   *
   * @author Stefan Guggisberg
   * @version $Revision: 1.1 $
   */
  public class HierarchyManagerImpl implements HierarchyManager {
  
      private static Logger log = Logger.getLogger(ItemManager.class);
  
      private final NodeId rootNodeId;
      private final ItemStateProvider provider;
      // used for outputting user-friendly paths and names
      private final NamespaceResolver nsResolver;
  
      public HierarchyManagerImpl(String rootNodeUUID, ItemStateProvider provider, 
NamespaceResolver nsResolver) {
        rootNodeId = new NodeId(rootNodeUUID);
        this.provider = provider;
        this.nsResolver = nsResolver;
      }
  
      //-------------------------------------------------< misc. helper methods >
      /**
       * Failsafe conversion of internal <code>Path</code> to JCR path for use in
       * error messages etc.
       * @param path path to convert
       * @return JCR path
       */
      public String safeGetJCRPath(Path path) {
        try {
            return path.toJCRPath(nsResolver);
        } catch (RepositoryException re) {
            log.error("failed to convert " + path.toString() + " to JCR path.");
            // return string representation of internal path as a fallback
            return path.toString();
        }
      }
  
      /**
       * Failsafe translation of internal <code>ItemId</code> to JCR path for use in
       * error messages etc.
       * @param id path to convert
       * @return JCR path
       */
      public String safeGetJCRPath(ItemId id) {
        try {
            return safeGetJCRPath(getPath(id));
        } catch (RepositoryException re) {
            log.error(id + ": failed to determine path to");
            // return string representation if id as a fallback
            return id.toString();
        }
      }
  
      //-----------------------------------------------------< HierarchyManager >
      /**
       * @see HierarchyManager#listParents(ItemId)
       */
      public NodeId[] listParents(ItemId id) throws ItemNotFoundException, 
RepositoryException {
        ArrayList list = new ArrayList();
        try {
            if (id.denotesNode()) {
                NodeState state = (NodeState) provider.getItemState(id);
                Iterator iter = state.getParentUUIDs().iterator();
                while (iter.hasNext()) {
                    list.add(new NodeId((String) iter.next()));
                }
            } else {
                PropertyState state = (PropertyState) provider.getItemState(id);
                list.add(new NodeId(state.getParentUUID()));
            }
        } catch (NoSuchItemStateException e) {
            String msg = "failed to retrieve state of item " + id;
            log.error(msg, e);
            throw new ItemNotFoundException(msg, e);
        } catch (ItemStateException e) {
            String msg = "failed to retrieve state of item " + id;
            log.error(msg, e);
            throw new RepositoryException(msg, e);
        }
        return (NodeId[]) list.toArray(new NodeId[list.size()]);
      }
  
      /**
       * @see HierarchyManager#listChildren(NodeId)
       */
      public ItemId[] listChildren(NodeId id) throws ItemNotFoundException, 
RepositoryException {
        NodeState parentState;
        try {
            parentState = (NodeState) provider.getItemState(id);
        } catch (NoSuchItemStateException e) {
            String msg = "failed to retrieve state of parent node " + id;
            log.error(msg, e);
            throw new ItemNotFoundException(msg, e);
        } catch (ItemStateException e) {
            String msg = "failed to retrieve state of parent node " + id;
            log.error(msg, e);
            throw new RepositoryException(msg, e);
        }
        ArrayList list = new ArrayList();
        Iterator iter = parentState.getPropertyEntries().iterator();
        while (iter.hasNext()) {
            // properties
            NodeState.PropertyEntry pe = (NodeState.PropertyEntry) iter.next();
            list.add(new PropertyId(id.getUUID(), pe.getName()));
        }
        iter = parentState.getChildNodeEntries().iterator();
        while (iter.hasNext()) {
            // child nodes
            NodeState.ChildNodeEntry cne = (NodeState.ChildNodeEntry) iter.next();
            list.add(new NodeId(cne.getUUID()));
        }
        return (ItemId[]) list.toArray(new ItemId[list.size()]);
      }
  
      /**
       * @see HierarchyManager#listZombieChildren(NodeId)
       */
      public ItemId[] listZombieChildren(NodeId id) throws ItemNotFoundException, 
RepositoryException {
        // FIXME messy code
        NodeState parentState;
        try {
            // get transient/persistent state
            parentState = (NodeState) provider.getItemState(id);
        } catch (NoSuchItemStateException e) {
            // try attic
            try {
                parentState = (NodeState) provider.getItemStateInAttic(id);
            } catch (NoSuchItemStateException nsise) {
                String msg = "failed to retrieve state of parent node " + id;
                log.error(msg, nsise);
                throw new ItemNotFoundException(msg, nsise);
            } catch (ItemStateException ise) {
                String msg = "failed to retrieve state of parent node " + id;
                log.error(msg, ise);
                throw new RepositoryException(msg, ise);
            }
        } catch (ItemStateException e) {
            String msg = "failed to retrieve state of parent node " + id;
            log.error(msg, e);
            throw new RepositoryException(msg, e);
        }
  
        ArrayList list = new ArrayList();
        Iterator iter = parentState.getRemovedPropertyEntries().iterator();
        while (iter.hasNext()) {
            // removed properties
            NodeState.PropertyEntry pe = (NodeState.PropertyEntry) iter.next();
            list.add(new PropertyId(id.getUUID(), pe.getName()));
        }
        iter = parentState.getRemovedChildNodeEntries().iterator();
        while (iter.hasNext()) {
            // removed child nodes
            NodeState.ChildNodeEntry cne = (NodeState.ChildNodeEntry) iter.next();
            list.add(new NodeId(cne.getUUID()));
        }
        return (ItemId[]) list.toArray(new ItemId[list.size()]);
      }
  
      /**
       * @see HierarchyManager#resolvePath(Path)
       */
      public synchronized ItemId resolvePath(Path path)
            throws PathNotFoundException, RepositoryException {
        // shortcut
        if (path.denotesRoot()) {
            return rootNodeId;
        }
  
        if (!path.isCanonical()) {
            String msg = "path is not canonical";
            log.error(msg);
            throw new RepositoryException(msg);
        }
  
        NodeState parentState;
        try {
            parentState = (NodeState) provider.getItemState(rootNodeId);
        } catch (ItemStateException e) {
            String msg = "failed to retrieve state of root node";
            log.error(msg, e);
            throw new RepositoryException(msg, e);
        }
  
        Path.PathElement[] elems = path.getElements();
        for (int i = 1; i < elems.length; i++) {
            Path.PathElement elem = elems[i];
            QName name = elem.getName();
            int index = elem.getIndex();
            if (parentState.hasChildNodeEntry(name, index == 0 ? 1 : index)) {
                // child node
                NodeState.ChildNodeEntry nodeEntry = 
parentState.getChildNodeEntry(name, index == 0 ? 1 : index);
                if (i == elems.length - 1) {
                    // last element in the path
                    return new NodeId(nodeEntry.getUUID());
                }
                try {
                    parentState = (NodeState) provider.getItemState(new 
NodeId(nodeEntry.getUUID()));
                } catch (ItemStateException e) {
                    String msg = "failed to retrieve state of intermediary node";
                    log.error(msg, e);
                    throw new RepositoryException(msg, e);
                }
                continue;
            } else if (parentState.hasPropertyEntry(name)) {
                // property
                if (index > 1) {
                    // properties can't have same name siblings
                    throw new PathNotFoundException(safeGetJCRPath(path));
                }
                if (i == elems.length - 1) {
                    return new PropertyId(parentState.getUUID(), name);
                } else {
                    // property is not the last element in the path
                    throw new PathNotFoundException(safeGetJCRPath(path));
                }
            } else {
                // no such item
                throw new PathNotFoundException(safeGetJCRPath(path));
            }
        }
  
        throw new PathNotFoundException(safeGetJCRPath(path));
      }
  
      /**
       * @see HierarchyManager#getPath(ItemId)
       */
      public synchronized Path getPath(ItemId id) throws ItemNotFoundException, 
RepositoryException {
        try {
            Path.PathBuilder builder = new Path.PathBuilder();
  
            ItemState state = provider.getItemState(id);
            String parentUUID = state.getParentUUID();
            if (parentUUID == null) {
                // specified id denotes the root node
                builder.addRoot();
                return builder.getPath();
            }
  
            NodeState parent = (NodeState) provider.getItemState(new 
NodeId(parentUUID));
            do {
                if (state.isNode()) {
                    NodeState nodeState = (NodeState) state;
                    String uuid = nodeState.getUUID();
                    List entries = parent.getChildNodeEntries(uuid);
                    if (entries.isEmpty()) {
                        String msg = "failed to build path of " + id + ": " + 
parent.getUUID() + " has no child entry for " + uuid;
                        log.error(msg);
                        throw new RepositoryException(msg);
                    }
                    // if the parent has more than one child node entries pointing
                    // to the same child node, always use the first one
                    NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) 
entries.get(0);
                    QName name = entry.getName();
                    // add to path
                    builder.addFirst(name.getNamespaceURI(), name.getLocalName(), 
entry.getIndex());
                } else {
                    PropertyState propState = (PropertyState) state;
                    QName name = propState.getName();
                    // add to path
                    builder.addFirst(name.getNamespaceURI(), name.getLocalName());
                }
                parentUUID = parent.getParentUUID();
                if (parentUUID != null) {
                    state = parent;
                    parent = (NodeState) provider.getItemState(new NodeId(parentUUID));
                } else {
                    parent = null;
                    state = null;
                }
            } while (parent != null);
  
            // add root to path
            builder.addRoot();
            return builder.getPath();
        } catch (NoSuchItemStateException nsise) {
            String msg = "failed to build path of " + id;
            log.error(msg, nsise);
            throw new ItemNotFoundException(msg, nsise);
        } catch (ItemStateException ise) {
            String msg = "failed to build path of " + id;
            log.error(msg, ise);
            throw new RepositoryException(msg, ise);
        } catch (MalformedPathException mpe) {
            String msg = "failed to build path of " + id;
            log.error(msg, mpe);
            throw new RepositoryException(msg, mpe);
        }
      }
  
      /**
       * @see HierarchyManager#getName(ItemId)
       */
      public QName getName(ItemId itemId) throws ItemNotFoundException, 
RepositoryException {
        if (itemId.denotesNode()) {
            NodeId nodeId = (NodeId) itemId;
            NodeState parentState;
            if (!provider.hasItemState(nodeId)) {
                String msg = "failed to resolve name of " + nodeId;
                log.error(msg);
                throw new ItemNotFoundException(nodeId.toString());
            }
            try {
                NodeState nodeState = (NodeState) provider.getItemState(nodeId);
                String parentUUID = nodeState.getParentUUID();
                if (parentUUID == null) {
                    // this is the root or an orphaned node
                    // FIXME
                    return new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, "");
                }
                parentState = (NodeState) provider.getItemState(new 
NodeId(parentUUID));
            } catch (ItemStateException ise) {
                String msg = "failed to resolve name of " + nodeId;
                log.error(msg, ise);
                throw new RepositoryException(msg, ise);
            }
  
            List entries = parentState.getChildNodeEntries(nodeId.getUUID());
            if (entries.size() == 0) {
                String msg = "failed to resolve name of " + nodeId;
                log.error(msg);
                throw new RepositoryException(msg);
            }
            NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) entries.get(0);
            return entry.getName();
        } else {
            PropertyId propId = (PropertyId) itemId;
            return propId.getName();
        }
      }
  
      /**
       * @see HierarchyManager#getAllPaths(ItemId)
       */
      public synchronized Path[] getAllPaths(ItemId id) throws ItemNotFoundException, 
RepositoryException {
        Path.PathBuilder builder = new Path.PathBuilder();
        ArrayList list = new ArrayList();
        list.add(builder);
  
        NodeId nodeId = null;
        if (!id.denotesNode()) {
            try {
                PropertyState propState = (PropertyState) provider.getItemState(id);
                QName name = propState.getName();
                // add to path
                builder.addFirst(name.getNamespaceURI(), name.getLocalName());
                nodeId = new NodeId(propState.getParentUUID());
            } catch (NoSuchItemStateException nsise) {
                String msg = "failed to build path of " + id;
                log.error(msg, nsise);
                throw new ItemNotFoundException(msg, nsise);
            } catch (ItemStateException ise) {
                String msg = "failed to build path of " + id;
                log.error(msg, ise);
                throw new RepositoryException(msg, ise);
            }
        } else {
            nodeId = (NodeId) id;
        }
  
        // recursively traverse parent nodes
        recursiveBuildPaths(nodeId, builder, list);
  
        Path[] paths = new Path[list.size()];
        int i = 0;
        Iterator iter = list.iterator();
        while (iter.hasNext()) {
            Path.PathBuilder pb = (Path.PathBuilder) iter.next();
            try {
                paths[i++] = pb.getPath();
            } catch (MalformedPathException mpe) {
                String msg = "failed to build all paths of " + id;
                log.error(msg, mpe);
                throw new RepositoryException(msg, mpe);
            }
        }
        return paths;
      }
  
      /**
       *
       * @param nodeId
       * @param builder
       * @param builders
       * @throws ItemNotFoundException
       * @throws RepositoryException
       */
      private void recursiveBuildPaths(NodeId nodeId, Path.PathBuilder builder, List 
builders)
            throws ItemNotFoundException, RepositoryException {
        try {
            NodeState nodeState = (NodeState) provider.getItemState(nodeId);
  
            String uuid = nodeState.getUUID();
            /**
             * the parent uuid list contains an entry for every parent-child
             * link to the specified node. this list may contain duplicate
             * entries if the same parent node has more than one child link to
             * the same target node. because the following code expects unique
             * entries in the parent uuid list, we put them into a set.
             */
            HashSet parentUUIDs = new HashSet(nodeState.getParentUUIDs());
            if (parentUUIDs.size() == 0) {
                // nodeId denotes the root node
                builder.addRoot();
                return;
            }
  
            // if the specified node has n parents,
            // we need to create n - 1 path builder clones
            LinkedList queue = new LinkedList();
            queue.add(builder);
            int n = parentUUIDs.size() - 1;
            while (n-- > 0) {
                Path.PathBuilder clone = (Path.PathBuilder) builder.clone();
                queue.addLast(clone);
                // add to list of path builders
                builders.add(clone);
            }
  
  
            Iterator iter = parentUUIDs.iterator();
            while (iter.hasNext()) {
                String parentUUID = (String) iter.next();
                NodeState parent = (NodeState) provider.getItemState(new 
NodeId(parentUUID));
                List entries = parent.getChildNodeEntries(uuid);
                if (entries.isEmpty()) {
                    String msg = "failed to build path of " + nodeId + ": " + 
parent.getUUID() + " has no child entry for " + uuid;
                    log.error(msg);
                    throw new RepositoryException(msg);
                }
                n = entries.size() - 1;
                while (n-- > 0) {
                    // the same parent has multiple child references to
                    // this node, more path builder clones are needed
  
                    // since we are consuming the queue of path builders
                    // starting at the tail, we can safely clone 'builder'
                    // because it will be consumed as the very last queue entry
                    Path.PathBuilder clone = (Path.PathBuilder) builder.clone();
                    queue.add(clone);
                    // add to list of path builders
                    builders.add(clone);
                }
                for (int i = 0; i < entries.size(); i++) {
                    NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) 
entries.get(i);
                    QName name = entry.getName();
  
                    // get a path builder clone from the tail of the queue
                    Path.PathBuilder pb = (Path.PathBuilder) queue.removeLast();
                    // add entry to path
                    pb.addFirst(name.getNamespaceURI(), name.getLocalName(), 
entry.getIndex());
  
                    // recurse
                    recursiveBuildPaths(new NodeId(parentUUID), pb, builders);
                }
            }
        } catch (NoSuchItemStateException nsise) {
            String msg = "failed to build path of " + nodeId;
            log.error(msg, nsise);
            throw new ItemNotFoundException(msg, nsise);
        } catch (ItemStateException ise) {
            String msg = "failed to build path of " + nodeId;
            log.error(msg, ise);
            throw new RepositoryException(msg, ise);
        }
      }
  }
  
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to