[jboss-cvs] jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset ...

Christian Bauer christian at hibernate.org
Sat Aug 25 13:59:20 EDT 2007


  User: cbauer  
  Date: 07/08/25 13:59:20

  Modified:    examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset       
                        AbstractNestedSetNode.java
                        NestedSetPostDeleteEventListener.java
                        NestedSetResultTransformer.java
                        NestedSetNodeWrapper.java
                        NestedSetPostInsertEventListener.java
                        NestedSetNode.java
  Added:       examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset       
                        NestedSetNodeDuplicator.java
  Log:
  Major refactoring of navigation
  
  Revision  Changes    Path
  1.2       +18 -0     jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/AbstractNestedSetNode.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: AbstractNestedSetNode.java
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/AbstractNestedSetNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -b -r1.1 -r1.2
  --- AbstractNestedSetNode.java	17 Aug 2007 13:00:23 -0000	1.1
  +++ AbstractNestedSetNode.java	25 Aug 2007 17:59:20 -0000	1.2
  @@ -39,6 +39,19 @@
       @Column(name = "NS_RIGHT", nullable = false,  updatable = false)
       private Long nsRight = 0l;
   
  +    protected AbstractNestedSetNode() {};
  +
  +    protected AbstractNestedSetNode(N original) {
  +        if (original == null) return;
  +        this.nsThread = original.getNsThread();
  +        this.nsLeft = original.getNsLeft();
  +        this.nsRight = original.getNsRight();
  +    }
  +
  +    public boolean vetoNestedSetUpdate() {
  +        return false;
  +    }
  +
       public void addChild(N child) {
           if (child.getParent() != null) {
               child.getParent().getChildren().remove(child);
  @@ -88,4 +101,9 @@
       public String getTreeSuperclassEntityName() {
           return getClass().getSimpleName();
       }
  +
  +    public String toString() {
  +        return "(ID: " + getId() + " THREAD: " + getNsThread() + " LEFT: " + getNsLeft() + " RIGHT: " + getNsRight() +")";
  +    }
  +
   }
  
  
  
  1.2       +3 -5      jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetPostDeleteEventListener.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: NestedSetPostDeleteEventListener.java
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetPostDeleteEventListener.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -b -r1.1 -r1.2
  --- NestedSetPostDeleteEventListener.java	17 Aug 2007 13:00:23 -0000	1.1
  +++ NestedSetPostDeleteEventListener.java	25 Aug 2007 17:59:20 -0000	1.2
  @@ -23,12 +23,10 @@
       public void onPostDelete(PostDeleteEvent event) {
           super.onPostDelete(event);
   
  -        if (event.getEntity() instanceof NestedSetNode) {
  -            if (event.getEntity() instanceof NestedSetNode) {
  +        if ( event.getEntity() instanceof NestedSetNode && !((NestedSetNode)event.getEntity()).vetoNestedSetUpdate() ) {
                   log.debug("executing nested set delete operation, recalculating the tree");
                   new DeleteNestedSetOperation( (NestedSetNode)event.getEntity() ).execute(event.getSession());
                }
           }
  -    }
   
   }
  
  
  
  1.2       +45 -11    jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetResultTransformer.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: NestedSetResultTransformer.java
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetResultTransformer.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -b -r1.1 -r1.2
  --- NestedSetResultTransformer.java	17 Aug 2007 13:00:23 -0000	1.1
  +++ NestedSetResultTransformer.java	25 Aug 2007 17:59:20 -0000	1.2
  @@ -62,6 +62,13 @@
    * deeper than 3 levels. This is useful for certain kinds of tree display.
    * </p>
    * <p>
  + * This transformer accepts a <tt>NestedSetNodeDuplicator</tt> instance which will be used, if not null, to
  + * copy every <tt>nestedSetNode</tt> returned by the query. This is useful if you do not want or require the
  + * original <tt>nestedSetNode</tt> instances wrapped, for example, if changes on these instances should not
  + * be reflected by the wrapped instances. You can effectively generate a stable copy of the tree, e.g. for
  + * display purposes.
  + * </p>
  + * <p>
    * A note about restrictions: If the only restriction condition in your query is the one shown above, limiting
    * the returned tuples to the nodes of the subtree, you will have a whole and complete subtree, hence, you will
    * not have any gaps in the in-memory tree of {@link NestedSetNodeWrapper}s returned by the transformer. However,
  @@ -83,14 +90,22 @@
       NestedSetNodeWrapper<N> rootWrapper;
       NestedSetNodeWrapper<N> currentParent;
       long flattenToLevel = 0;
  +    Map<String, String> additionalProjections = new HashMap<String, String>();
  +    NestedSetNodeDuplicator<N> nestedSetNodeDuplicator = null;
  +
  +    public NestedSetResultTransformer(NestedSetNodeWrapper<N> rootWrapper) {
  +        this(rootWrapper, 0l);
  +    }
   
       public NestedSetResultTransformer(NestedSetNodeWrapper<N> rootWrapper, long flattenToLevel) {
  -        this(rootWrapper);
  -        this.flattenToLevel = flattenToLevel;
  +        this(rootWrapper, flattenToLevel, new HashMap<String, String>());
       }
   
  -    public NestedSetResultTransformer(NestedSetNodeWrapper<N> rootWrapper) {
  +    public NestedSetResultTransformer(NestedSetNodeWrapper<N> rootWrapper, long flattenToLevel, Map<String, String> additionalProjections) {
           this.rootWrapper = rootWrapper;
  +        this.flattenToLevel = flattenToLevel;
  +        this.additionalProjections = additionalProjections;
  +
           this.comparator = rootWrapper.getComparator();
           currentParent = rootWrapper;
       }
  @@ -99,23 +114,41 @@
           return rootWrapper;
       }
   
  +    public Map<String, String> getAdditionalProjections() {
  +        return additionalProjections;
  +    }
  +
  +    public void setNestedSetNodeDuplicator(NestedSetNodeDuplicator<N> nestedSetNodeDuplicator) {
  +        this.nestedSetNodeDuplicator = nestedSetNodeDuplicator;
  +    }
  +
       public Object transformTuple(Object[] objects, String[] aliases) {
   
           if (!"nestedSetNodeLevel".equals(aliases[0]))
               throw new RuntimeException("Missing alias 'nestedSetNodeLevel' as the first projected value in the nested set query");
           if (!"nestedSetNode".equals(aliases[1]))
               throw new RuntimeException("Missing alias 'nestedSetNode' as the second projected value in the nested set query");
  -        if (objects.length != 2) {
  -            throw new RuntimeException("Nested set query needs to return two values, the level and the nested set node instance");
  +        if (objects.length < 2) {
  +            throw new RuntimeException("Nested set query needs to at least return two values, the level and the nested set node instance");
           }
   
           Long nestedSetNodeLevel = (Long)objects[0];
           N nestedSetNode = (N)objects[1];
   
  +        Long nestedSetNodeParentId = nestedSetNode.getParent().getId(); // Store the parent id before making a duplicate
  +        if (nestedSetNodeDuplicator != null) nestedSetNode = nestedSetNodeDuplicator.duplicate(nestedSetNode);
  +        if (nestedSetNode == null) return null; // Continue in loop if the duplicator didn't make a proper copy
  +
  +        Map<String, Object> additionalProjectionValues = new LinkedHashMap<String, Object>();
  +        int i = 2;
  +        for (Map.Entry<String, String> entry : additionalProjections.entrySet()) {
  +            additionalProjectionValues.put(entry.getKey(), objects[i++]);
  +        }
  +
           // Connect the tree hierarchically (child to parent, skip child if parent isn't present)
  -        NestedSetNodeWrapper<N> nodeWrapper = new NestedSetNodeWrapper<N>(nestedSetNode, comparator, nestedSetNodeLevel);
  -        if (!nodeWrapper.getWrappedNode().getParent().getId().equals(currentParent.getWrappedNode().getId())) {
  -            NestedSetNodeWrapper<N> foundParent = findParentInTree(nodeWrapper.getWrappedNode().getParent().getId(), currentParent);
  +        NestedSetNodeWrapper<N> nodeWrapper = new NestedSetNodeWrapper<N>(nestedSetNode, comparator, nestedSetNodeLevel, additionalProjectionValues);
  +        if (!nestedSetNodeParentId.equals(currentParent.getWrappedNode().getId())) {
  +            NestedSetNodeWrapper<N> foundParent = findParentInTree(nestedSetNodeParentId, currentParent);
               if (foundParent != null) {
                   currentParent = foundParent;
               } else {
  @@ -126,7 +159,7 @@
           currentParent.getWrappedChildren().add(nodeWrapper);
           currentParent = nodeWrapper;
   
  -        return rootWrapper; // Need to return something so that transformList() is called afterwards
  +        return rootWrapper; // Return just something so that transformList() will be called when we are done
       }
   
       private NestedSetNodeWrapper<N> findParentInTree(Serializable parentId, NestedSetNodeWrapper<N> startNode) {
  @@ -147,12 +180,13 @@
               }
               rootWrapper.setWrappedChildren(flatChildren);
           }
  -        return new ArrayList();
  +        return new ArrayList(); // Nothing is returned from this transformer
       }
   
       // Recursively flatten tree
       private void flattenTree(List<NestedSetNodeWrapper<N>> flatChildren, long i, NestedSetNodeWrapper<N> wrapper) {
  -        NestedSetNodeWrapper<N> newWrapper = new NestedSetNodeWrapper<N>(wrapper.getWrappedNode(), comparator, i);
  +        NestedSetNodeWrapper<N> newWrapper =
  +                new NestedSetNodeWrapper<N>(wrapper.getWrappedNode(), comparator, i, wrapper.getAdditionalProjections());
           flatChildren.add( newWrapper );
           if (wrapper.getWrappedChildren().size() > 0 && wrapper.getLevel() < flattenToLevel) {
               i++;
  
  
  
  1.2       +10 -0     jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetNodeWrapper.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: NestedSetNodeWrapper.java
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetNodeWrapper.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -b -r1.1 -r1.2
  --- NestedSetNodeWrapper.java	17 Aug 2007 13:00:23 -0000	1.1
  +++ NestedSetNodeWrapper.java	25 Aug 2007 17:59:20 -0000	1.2
  @@ -48,15 +48,21 @@
       List<NestedSetNodeWrapper<N>> wrappedChildren = new ArrayList<NestedSetNodeWrapper<N>>();
       Comparator<NestedSetNodeWrapper<N>> comparator;
       Long level;
  +    Map<String, Object> additionalProjections = new HashMap<String, Object>();
   
       public NestedSetNodeWrapper(N wrappedNode, Comparator<NestedSetNodeWrapper<N>> comparator) {
           this(wrappedNode, comparator, 0l);
       }
   
       public NestedSetNodeWrapper(N wrappedNode, Comparator<NestedSetNodeWrapper<N>> comparator, Long level) {
  +        this(wrappedNode, comparator, level, new HashMap<String,Object>());
  +    }
  +
  +    public NestedSetNodeWrapper(N wrappedNode, Comparator<NestedSetNodeWrapper<N>> comparator, Long level, Map<String,Object> additionalProjections) {
           this.wrappedNode = wrappedNode;
           this.comparator = comparator;
           this.level = level;
  +        this.additionalProjections = additionalProjections;
       }
   
       public N getWrappedNode() {
  @@ -91,6 +97,10 @@
           return level;
       }
   
  +    public Map<String, Object> getAdditionalProjections() {
  +        return additionalProjections;
  +    }
  +
       public SortedSet<NestedSetNodeWrapper<N>> getWrappedChildrenSorted() {
           SortedSet<NestedSetNodeWrapper<N>> sortedSet = new TreeSet<NestedSetNodeWrapper<N>>(comparator);
           sortedSet.addAll(getWrappedChildren());
  
  
  
  1.2       +1 -1      jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetPostInsertEventListener.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: NestedSetPostInsertEventListener.java
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetPostInsertEventListener.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -b -r1.1 -r1.2
  --- NestedSetPostInsertEventListener.java	17 Aug 2007 13:00:23 -0000	1.1
  +++ NestedSetPostInsertEventListener.java	25 Aug 2007 17:59:20 -0000	1.2
  @@ -23,7 +23,7 @@
       public void onPostInsert(PostInsertEvent event) {
           super.onPostInsert(event);
   
  -        if (event.getEntity() instanceof NestedSetNode) {
  +        if ( event.getEntity() instanceof NestedSetNode && !((NestedSetNode)event.getEntity()).vetoNestedSetUpdate() ) {
               log.debug("executing nested set insert operation, recalculating the tree");
               new InsertNestedSetOperation( (NestedSetNode)event.getEntity() ).execute(event.getSession());
           }
  
  
  
  1.2       +14 -0     jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetNode.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: NestedSetNode.java
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -b -r1.1 -r1.2
  --- NestedSetNode.java	17 Aug 2007 13:00:23 -0000	1.1
  +++ NestedSetNode.java	25 Aug 2007 17:59:20 -0000	1.2
  @@ -25,6 +25,19 @@
       public Long getId();
   
       /**
  +     * A node can veto any nested set updates.
  +     * <p>
  +     * This is useful if a particular instance doesn't really belong into the tree but has
  +     * the same type. For example, if you have <tt>FileSystemNode</tt> implements
  +     * <tt>NestedSetNode</tt> and <tt>HistoricalFileSystemNode</tt> (for audit logging, saved
  +     * to a completely different table than the tree) then <tt>HistoricalFileSystemNode</tt>
  +     * can return a veto when it is saved, so that the main tree will not be updated.
  +     *
  +     * @return true if a particular instance should not trigger nested set tree updates
  +     */
  +    public boolean vetoNestedSetUpdate();
  +
  +    /**
        * Nested set updates require that direct DML is executed by event listeners, this is
        * the name of the entity that is used by the event listeners. You can in most cases
        * return the simple class name of an instance, unless you customize your persistent
  @@ -37,6 +50,7 @@
        * @return the persistent entity name of the superclass that implements this interface
        */
       public String getTreeSuperclassEntityName();
  +    public Class getTreeSuperclass();
   
       /**
        * Utility method required until TODO: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1615
  
  
  
  1.1      date: 2007/08/25 17:59:20;  author: cbauer;  state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetNodeDuplicator.java
  
  Index: NestedSetNodeDuplicator.java
  ===================================================================
  /*
   * JBoss, Home of Professional Open Source
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.seam.wiki.core.nestedset;
  
  /**
   * Generate a copy of a <tt>NestedSetNode</tt>.
   *
   * <p>
   * Used by the <tt>NestedSetResultTransformer</tt> to duplicate nodes after retrieving them
   * from the database. Useful if you need a copy of the tree for display purposes which is stable and
   * does not reflect any changes to the underlying real persistent nodes. This copy should be not
   * connected or hollow, that is, you should copy only the miminum properties you require for display
   * and probably not any collections or to-one entity references.
   * </p>
   *
   * @author Christian Bauer
   */
  public interface NestedSetNodeDuplicator<N> {
  
      /**
       * Make a (probably hollow) copy of the given node.
       * <p>
       * You <b>have to</b> ensure that the copy holds the same identifier value as the original.
       * </p>
       * @param nestedSetNode the persistent node from the database
       * @return null if a copy couln't be made, skipping the node in the tree result transformation
       */
      public N duplicate(N nestedSetNode);
  }
  
  
  



More information about the jboss-cvs-commits mailing list