Package de.esoco.j2me.model

Source Code of de.esoco.j2me.model.BasicHierarchyNode

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// J2ME-Lib source file
// Copyright (c) 2006 Elmar Sonnenschein / esoco GmbH
// Last Change: 10.11.2006 by eso
//
// J2ME-Lib is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 2.1 of the License, or (at your option)
// any later version.
//
// J2ME-Lib is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with J2ME-Lib; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA or use the contact
// information from the GNU website http://www.gnu.org
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
package de.esoco.j2me.model;

import de.esoco.j2me.J2meLib;
import de.esoco.j2me.storage.HierarchicalStorage;
import de.esoco.j2me.storage.StorageException;
import de.esoco.j2me.storage.StorageFullException;
import de.esoco.j2me.util.Arrays;
import de.esoco.j2me.util.IntArray;
import de.esoco.j2me.util.Log;

import java.io.IOException;

import java.util.Vector;


/********************************************************************
* Basic implementation of the MutableHierarchyNode interface with data fields,
* child object management, and corresponding methods. This implementation does
* not support child nodes which are not also BasicHierarchyNodes.
*
* <p>The implementation can be made fail-safe persistent by backing it with a
* HierarchicalStorage implementation with random access (normally provided by
* the root node). An instance will then store itself immediately after each
* change to it's data and/or structure.</p>
*
* @author eso
*/
public class BasicHierarchyNode implements MutableHierarchyNode
{
  //~ Static fields/initializers ---------------------------------------------

  /** Node type character constants */
  private static final char NTCHAR_GROUP = 'G';
  private static final char NTCHAR_TEXT  = 'T';

  /** The storage handle value for nodes that haven't been stored or loaded */
  private static final int STORAGE_UNASSIGNED = -1;

  /** The "previous node handle" value for the first child node */
  private static final int FIRST_CHILD_NODE = -1;

  //~ Instance fields --------------------------------------------------------

  /** Node data: data of the node */
  protected byte[] aData = null;

  /** Node data: title of the node */
  protected String sTitle;

  /** A Vector containing the child nodes in their logical order */
  private Vector aChildren = new Vector();

  /** Handle for the storage record the node is stored in */
  private int nStorageHandle = STORAGE_UNASSIGNED;

  /** The parent node or NULL for the root node */
  private BasicHierarchyNode rParent = null;

  /** The previous node or NULL for the first node in a child list */
  private BasicHierarchyNode rPrevious = null;

  //~ Constructors -----------------------------------------------------------

  /***************************************
   * Constructs a node from a title and byte array data.
   *
   * @param rParent The parent node
   * @param sTitle  The title string
   * @param rData   The node data as a byte array
   */
  public BasicHierarchyNode(BasicHierarchyNode rParent,
                String       sTitle,
                byte[]       rData)
  {
    this.rParent = rParent;
    this.sTitle  = sTitle;

    if (rData != null)
    {
      setDataField(rData);
    }
  }

  //~ Methods ----------------------------------------------------------------

  /***************************************
   * @see MutableHierarchyNode#createChild(String, String)
   */
  public MutableHierarchyNode createChild(String sCreateOption,
                       String sTitle)
  {
    BasicHierarchyNode rNode = newChildNode(sTitle);

    if (J2meLib.DEBUG)
    {
      Log.debug("New Node(" + sTitle + "): " +
            rNode.getClass().getName());
    }

    if (sCreateOption == NT_TEXT)
    {
      rNode.aData = new byte[0];
    }

    return rNode;
  }

  /***************************************
   * Recursively creates a copy of this node and all it's children. The copies
   * will include all fields of the original nodes except for the storage
   * handle. To make the copy persistent it must be written to a storage with
   * the writeTo() method.
   *
   * <p>To copy the data fields of the node the method copyFields() will be
   * called. If necessary, subclasses can overload it to copy their additional
   * data fields after invoking super.copyFields().</p>
   *
   * @see de.esoco.j2me.model.HierarchyNode#deepCopy()
   */
  public HierarchyNode deepCopy()
  {
    BasicHierarchyNode aCopy = newChildNode(sTitle);

    copyFields(aCopy);

    for (int i = 0, n = aChildren.size(); i < n; i++)
    {
      BasicHierarchyNode rChild = (BasicHierarchyNode) getChild(i);

      aCopy.insertChildNode((BasicHierarchyNode) rChild.deepCopy(), i);
    }

    return aCopy;
  }

  /***************************************
   * @see HierarchyNode#getChild(int)
   */
  public HierarchyNode getChild(int nIndex)
  {
    return (HierarchyNode) aChildren.elementAt(nIndex);
  }

  /***************************************
   * @see HierarchyNode#getChildCount()
   */
  public int getChildCount()
  {
    return aChildren.size();
  }

  /***************************************
   * @see MutableHierarchyNode#getChildCreateOptions()
   */
  public String[] getChildCreateOptions()
  {
    return new String[] { NT_GROUP, NT_TEXT };
  }

  /***************************************
   * @see HierarchyNode#getChildIndex(HierarchyNode)
   */
  public int getChildIndex(HierarchyNode rChild)
  {
    return aChildren.indexOf(rChild);
  }

  /***************************************
   * Returns a copy of the internal data array.
   *
   * @see de.esoco.j2me.model.HierarchyNode#getData()
   */
  public byte[] getData()
  {
    return ((aData != null) ? Arrays.copy(aData) : null);
  }

  /***************************************
   * @see HierarchyNode#getChild(int)
   */
  public int getMaximumSize()
  {
    if (isGroup())
    {
      return UNLIMITED_SIZE;
    }
    else
    {
      return Short.MAX_VALUE;
    }
  }

  /***************************************
   * Returns the node type which will be either NT_GROUP or NT_TEXT.
   *
   * @return The string constant describing the node type
   *
   * @see    HierarchyNode#getNodeType()
   */
  public String getNodeType()
  {
    return ((aData == null) ? NT_GROUP : NT_TEXT);
  }

  /***************************************
   * @see HierarchyNode#getParent()
   */
  public HierarchyNode getParent()
  {
    return rParent;
  }

  /***************************************
   * Returns the root node of the hierarchy (i.e. the node where the parent
   * NULL).
   *
   * @return The root node of the heriarchy
   */
  public HierarchyNode getRoot()
  {
    if (rParent != null)
    {
      return rParent.getRoot();
    }
    else
    {
      return this;
    }
  }

  /***************************************
   * @see HierarchyNode#getTitle()
   */
  public String getTitle()
  {
    return sTitle;
  }

  /***************************************
   * Returns the total number of children in the hierarchy of this node (not
   * counting the starting node itself).
   *
   * @return The total number of children of the node
   */
  public int getTotalChildCount()
  {
    int nCount = aChildren.size();

    for (int i = 0, n = nCount; i < n; i++)
    {
      nCount += ((BasicHierarchyNode) getChild(i)).getTotalChildCount();
    }

    return nCount;
  }

  /***************************************
   * Inserts a child object at a specific position into the child list. The
   * node previously at that position and all nodes behind it will have an
   * index that is one higher afterwards. The given child must be an instance
   * that has been created by the createChild() method of this node, otherwise
   * a ClassCastException will be thrown.
   *
   * <p><b>Attention</b>: The given child node ist directly inserted into the
   * child list of the node. Therefore it must be a separate instance and no
   * reference to it should be held and modified by the application
   * afterwards. Otherwise side effects will occur. This is important for
   * example, if the application manages a kind of clipbord to insert nodes
   * from. If it cannot made sure that the node is unique and independent the
   * result of a call to the method <code>deepCopy()</code> on the node should
   * be inserted instead.</p>
   *
   * <p>This method also creates and updates all affected storage records if
   * the node hierarchy is backed by a storage.</p>
   *
   * @param  rNewChild The child node to add
   * @param  nIndex    The position at which to insert (use getChildCount() to
   *                   append the child to the end of the child list)
   *
   * @throws ClassCastException If the child node hasn't a class of a node
   *                            created by createChild()
   *
   * @see    de.esoco.j2me.model.MutableHierarchyNode#insertChild(HierarchyNode,
   *         int)
   */
  public void insertChild(HierarchyNode rNewChild, int nIndex)
    throws NodeAccessException, StorageException
  {
    insertChildNode((BasicHierarchyNode) rNewChild, nIndex);

    HierarchicalStorage rStorage = getStorage();

    if ((rStorage != null) && (nStorageHandle != STORAGE_UNASSIGNED))
    {
      try
      {
        // immediately write the child hierarchy to the storage
        // open parent node for reading only so that it is not necessary
        // to write out it's data again
        rStorage.openNode(nStorageHandle, false);
        writeChildNode(rStorage, nIndex);
        rStorage.closeNode();
      }
      catch (IOException eIO)
      {
        throw new StorageException("Writing child node(s) to storage failed",
                       eIO);
      }

      // insertChildNode() modifies rPrevious of the next node, so it
      // must also be stored
      if (++nIndex < aChildren.size())
      {
        ((BasicHierarchyNode) aChildren.elementAt(nIndex))
        .updateStorage(rStorage);
      }
    }
  }

  /***************************************
   * Returns TRUE if data string is null. Therefore leaf nodes must always
   * contain at least an empty String.
   *
   * @return TRUE if Data is null, FALSE otherwise
   *
   * @see    HierarchyNode#isGroup()
   */
  public boolean isGroup()
  {
    return (aData == null);
  }

  /***************************************
   * @see MutableHierarchyNode#removeChild(int)
   */
  public void removeChild(int nIndex) throws StorageException
  {
    BasicHierarchyNode  rChild   = (BasicHierarchyNode) getChild(nIndex);
    HierarchicalStorage rStorage = getStorage();

    aChildren.removeElementAt(nIndex);

    if (nIndex < aChildren.size())
    {
      // if the child wasn't the last node, update the reference to the
      // previous node of it's successor which is now at the same
      // position as the removed node
      BasicHierarchyNode rNext = (BasicHierarchyNode) getChild(nIndex);

      rNext.rPrevious = rChild.rPrevious;

      rNext.updateStorage(rStorage);
    }

    rChild.deleteFromStorage(rStorage);
  }

  /***************************************
   * Sets the data of the node. The new array must never be NULL. It's
   * contents will be copied into the node.
   *
   * @see MutableHierarchyNode#setData(byte[])
   */
  public void setData(byte[] rNewData) throws StorageException
  {
    setDataField(rNewData);
    updateStorage(getStorage());
  }

  /***************************************
   * @see MutableHierarchyNode#setTitle(String)
   */
  public void setTitle(String sNewTitle) throws StorageException
  {
    setTitleField(sNewTitle);
    updateStorage(getStorage());
  }

  /***************************************
   * Invokes the internal toString(sIndent) method with an empty indentation
   * string.
   *
   * @return A formatted, multi-line String for this node and all children
   */
  public String toString()
  {
    return toString("");
  }

  /***************************************
   * Copies the data fields of the node into another node. This is used by the
   * method deepCopy() and should be overloaded by subclasses to copy their
   * additional data fields. It will only copy the data elements of the node,
   * not the fields that are used to manage the node hierarchy (like the
   * parent reference or the child nodes).
   *
   * @param rTarget The target node to copy the data into
   */
  protected void copyFields(BasicHierarchyNode rTarget)
  {
    rTarget.sTitle = sTitle;
    rTarget.aData  = ((aData != null) ? Arrays.copy(aData) : null);
  }

  /***************************************
   * Deletes the node and all it's children from the underlying storage (if
   * such exists). This will also reset the internal storage handle to
   * NOT_IN_STORAGE so that further storage access is not possible. To make
   * the node persistent again it would be necessary to write it to the
   * storage with the method writeTo().
   *
   * @param  rStorage The storage to delete the node(s) from
   *
   * @throws StorageException If deleting fails
   */
  protected void deleteFromStorage(HierarchicalStorage rStorage)
    throws StorageException
  {
    if ((rStorage != null) && (nStorageHandle != STORAGE_UNASSIGNED))
    {
      for (int i = 0, n = aChildren.size(); i < n; i++)
      {
        ((BasicHierarchyNode) getChild(i)).deleteFromStorage(rStorage);
      }

      rStorage.deleteNode(nStorageHandle);
      nStorageHandle = STORAGE_UNASSIGNED;
    }
  }

  /***************************************
   * Returns a storage implementation in which the node data shall be stored
   * on each change. If this method return null, the data will not be stored
   * automatically.
   *
   * <p>The default implementation simply return Parent.getStorage() or null
   * if the node has no parent. Therefore it is necessary to implement a
   * subclass as the root node to provide a storage for automatic saving at
   * runtime.</p>
   *
   * @return HierarchicalStorage
   */
  protected HierarchicalStorage getStorage()
  {
    if (rParent instanceof BasicHierarchyNode)
    {
      return ((BasicHierarchyNode) rParent).getStorage();
    }
    else
    {
      return null;
    }
  }

  /***************************************
   * Inserts a new child into the child list of this node. The new child will
   * get the index of the insert position and the node currently at that
   * position and all nodes behind will have an index that is one higher
   * afterwards. This method will also set the parent of the new child node to
   * this node and update the references to the previous child node in all
   * affected nodes.
   *
   * <p>None of the changes made by this method will be made persistent,
   * therefore this is the responsibility of the caller. When saving the
   * changes it is necessary to consider that not only the inserted child but
   * also the next node in the child list will be modified (it's reference to
   * the previous node will be changed).</p>
   *
   * @param rChild The child node to insert
   * @param nIndex The position where to insert the child node
   */
  protected void insertChildNode(BasicHierarchyNode rChild, int nIndex)
  {
    int nPrev = nIndex - 1;

    rChild.rParent = this;

    if (nPrev >= 0)
    {
      rChild.rPrevious = (BasicHierarchyNode) aChildren.elementAt(nPrev);
    }
    else
    {
      rChild.rPrevious = null;
    }

    if (nIndex < aChildren.size())
    {
      BasicHierarchyNode rNext = (BasicHierarchyNode) aChildren.elementAt(nIndex);

      rNext.rPrevious = rChild;
    }

    aChildren.insertElementAt(rChild, nIndex);
  }

  /***************************************
   * Returns a new child node instance. Can be overloaded by subclasses that
   * don't want to replace the complete createChild() method. This is only
   * possible if the subclass doesn't change the handling of node types from
   * BasicHierarchyNode (i.e. Data == NULL means it's a group node) but only
   * wants to use it's own instances as children. The instance should be
   * initialized to have no parent node (i.e. parent = NULL) because the
   * parent will be set in the insertChild() method.
   *
   * @param  sTitle The title of the new Node to be created
   *
   * @return An instance of an MutableHierarchyNode subclass
   */
  protected BasicHierarchyNode newChildNode(String sTitle)
  {
    return new BasicHierarchyNode(null, sTitle, null);
  }

  /***************************************
   * Reads the data fields of the node from a HierarchicalStorage
   * implementation. This method is invoked internally by the readFrom()
   * method. It must be overloaded by derived classes that need to read
   * additional fields before or after (or even instead of) reading the base
   * class fields.
   *
   * @param  rStorage The storage to read from
   *
   * @return The storage handle of the previous node in the child list
   *
   * @throws StorageException If access to the storage fails
   * @throws IOException      If an I/O error occurs during reading
   */
  protected int readFields(HierarchicalStorage rStorage)
    throws StorageException, IOException
  {
    int  nPreviousNodeStorageHandle = rStorage.readInt();
    char cNodeType            = (char) rStorage.readByte();

    sTitle = rStorage.readString();

    if (cNodeType != NTCHAR_GROUP)
    {
      aData = rStorage.readData();
    }

    if (J2meLib.DEBUG)
    {
      Log.debug("Node read (T'T'D): " + cNodeType + "'" + sTitle + "'" +
            ((aData != null) ? new String(aData) : ""));
    }

    return nPreviousNodeStorageHandle;
  }

  /***************************************
   * Reads this Node from a HierarchicalStorage implementation. It reads it's
   * children recursively from the storage, therefore it should normally only
   * be invoked on the root node. This is enforced by this method being
   * protected so that a specific root node subclass (the application's data
   * model) should be implemented that provides corresponding top-level
   * methods (e.g. load() and save()).
   *
   * <p>The method expects that the node to read from has already been
   * initialized by invoking the method nextNode() on the storage instance. It
   * is also required for the caller to close the node after the method
   * returns.The method will invoke nextNode() for each child node it stores
   * and close the node after invoking the child object's readFrom() method.
   * </p>
   *
   * <p>Although subclassing of this method is possible because of the above,
   * it is not recommended to do so except for special cases. Instead, the
   * method <code>readFields()</code> (and it's counterpart <code>
   * writeFields()</code>) should be overloaded in normal cases.</p>
   *
   * @param  rStorage The storage to read from
   *
   * @return The integer value that defines the logical child order as defined
   *         by the <code>writeTo()</code> method
   *
   * @throws StorageException If access to the storage fails
   * @throws IOException      If an I/O error occurs during reading
   */
  protected int readFrom(HierarchicalStorage rStorage)
    throws StorageException, IOException
  {
    if (nStorageHandle == STORAGE_UNASSIGNED)
    {
      nStorageHandle = rStorage.getCurrentNode();
    }

    int nPreviousNodeStorageHandle = readFields(rStorage);

    IntArray aPrevNodeHandles = new IntArray();

    while (rStorage.nextNode())
    {
      BasicHierarchyNode rNode = newChildNode(null);

      rNode.rParent = this;
      aPrevNodeHandles.add(rNode.readFrom(rStorage));
      rStorage.closeNode();
      aChildren.addElement(rNode);
    }

    rebuildChildOrder(aPrevNodeHandles);

    return nPreviousNodeStorageHandle;
  }

  /***************************************
   * Sets the data attribute of the node without updating the underlying
   * storage. This method can be overloaded by subclasses to intercept the
   * setting of the value.
   *
   * @param rNewData The new data of the node
   */
  protected void setDataField(byte[] rNewData)
  {
    aData = Arrays.copy(rNewData);
  }

  /***************************************
   * Sets the title attribute of the node without updating the underlying
   * storage. This method can be overloaded by subclasses to intercept the
   * setting of the value.
   *
   * @param sNewTitle The new title of the node
   */
  protected void setTitleField(String sNewTitle)
  {
    sTitle = sNewTitle;
  }

  /***************************************
   * Returns a string with formatted output of the node and it's child
   * hierarchy.
   *
   * @param  sIndent The indentation prefix for the output
   *
   * @return A formatted, multi-line String for this node and all children
   */
  protected String toString(String sIndent)
  {
    String s = "[" + sTitle + "]:";

    for (int i = 0, n = aChildren.size(); i < n; i++)
    {
      s += ("\n" + sIndent + "+-");

      HierarchyNode rChild = getChild(i);

      s += ((BasicHierarchyNode) rChild).toString(sIndent + "  ");
    }

    return s;
  }

  /***************************************
   * Updates the data fields in the underlying storage. This will only be
   * performed if a storage is provided by the root node and if the storage
   * handle has been provided on reading the node for the first time (which is
   * only available in storages that implement random access).
   *
   * @param  rStorage The storage to update the child data in
   *
   * @throws StorageException If updating the data in the storage fails
   */
  protected void updateStorage(HierarchicalStorage rStorage)
    throws StorageException
  {
    if ((rStorage != null) && (nStorageHandle != STORAGE_UNASSIGNED))
    {
      try
      {
        rStorage.openNode(nStorageHandle, true);
        writeFields(rStorage);
        rStorage.closeNode();
      }
      catch (IOException eIO)
      {
        throw new StorageException("Update of fields in storage failed",
                       eIO);
      }
    }
  }

  /***************************************
   * Writes a certain child node from the child list to a storage. Will also
   * store the child node's own child hierarchy to the storage recursively.
   *
   * @param  rStorage The storage to write to
   * @param  nIndex   The index position of the child to write in the child
   *                  list
   *
   * @throws StorageException     If access to the storage fails
   * @throws StorageFullException If the storage has no more capacity
   * @throws IOException          If an I/O error occurs during writing
   * @throws NullPointerException If the storage is NULL
   */
  protected void writeChildNode(HierarchicalStorage rStorage, int nIndex)
    throws StorageException, StorageFullException, IOException
  {
    rStorage.createNode();
    ((BasicHierarchyNode) getChild(nIndex)).writeTo(rStorage);
    rStorage.closeNode();
  }

  /***************************************
   * Writes the data fields of the node to a HierarchicalStorage
   * implementation. This method is invoked internally by the writeTo()
   * method. It must be overloaded by derived classes that need to write
   * additional fields before or after writing the base class fields. If it is
   * overloaded it is absolutely necessary for the derived class to invoke
   * <code>super.writeFields()</code>, unless it completely rebuilds the
   * read/write mechanism of this class.
   *
   * @param  rStorage The storage to write to
   *
   * @throws StorageException If access to the storage fails
   * @throws IOException      If an I/O error occurs during writing
   */
  protected void writeFields(HierarchicalStorage rStorage)
    throws StorageException, IOException
  {
    char cNodeType = ((aData == null) ? NTCHAR_GROUP : NTCHAR_TEXT);

    // write the storage handle of the previous child node as a hint for
    // reconstructing the child order when reading the nodes back in
    rStorage.writeInt((rPrevious != null) ? rPrevious.nStorageHandle
                        : FIRST_CHILD_NODE);
    rStorage.writeByte((byte) cNodeType);
    rStorage.writeString(sTitle);

    if (aData != null)
    {
      rStorage.writeData(aData);
    }

    if (J2meLib.DEBUG)
    {
      Log.debug("writing Node (T'T'D): " + cNodeType + "'" + sTitle +
            "'" + ((aData != null) ? new String(aData) : ""));
    }
  }

  /***************************************
   * <p>Writes this Node to a HierarchicalStorage implementation. It call this
   * method recursively on it's children, therefore it should normally only be
   * invoked on the root node. This is enforced by this method being protected
   * so that a specific root node subclass (the application's data model)
   * should be implemented that provides corresponding top-level methods (e.g.
   * load() and save()).</p>
   *
   * <p>The corresponding node must have been created already in the storage,
   * this will not be done by this method. Otherwise it would be difficult to
   * overload this method in subclasses. After the method returns, the node
   * that has been written to needs to be closed by the caller. The method
   * will create a new storage node for each child object it stores and close
   * it after invoking the child object's writeTo() method.</p>
   *
   * <p>Although subclassing of this method is possible because of the above,
   * it is not recommended to do so except for special cases. Instead, the
   * method <code>writeFields()</code> (and it's counterpart <code>
   * readFields()</code>) should be overloaded in normal cases.</p>
   *
   * @param  rStorage The storage to write to
   *
   * @throws StorageException     If access to the storage fails
   * @throws StorageFullException If the storage has no more capacity
   * @throws IOException          If an I/O error occurs during writing
   * @throws NullPointerException If the storage is NULL
   */
  protected void writeTo(HierarchicalStorage rStorage)
    throws StorageException, IOException
  {
    // in case of a new node, keep the handle of the associated record
    if (nStorageHandle == STORAGE_UNASSIGNED)
    {
      nStorageHandle = rStorage.getCurrentNode();
    }

    writeFields(rStorage);

    for (int i = 0, n = aChildren.size(); i < n; i++)
    {
      writeChildNode(rStorage, i);
    }
  }

  /***************************************
   * Rebuilds the order of the child nodes after they have been read from the
   * storage.
   *
   * @param  rPrevNodeHandles An IntArray containing the storage handles of
   *                          the previous nodes of the child nodes at the
   *                          same positions in this node's child vector
   *
   * @throws StorageException If the child hierarchy cannot be rebuilt due to
   *                          inconsistencies
   */
  private void rebuildChildOrder(IntArray rPrevNodeHandles)
    throws StorageException
  {
    BasicHierarchyNode rPrev     = null;
    BasicHierarchyNode rChild     = null;
    int           nSearchHandle = FIRST_CHILD_NODE;
    int           nCount     = aChildren.size();

    for (int i = 0; i < nCount; i++)
    {
      int pos = rPrevNodeHandles.find(nSearchHandle);

      if (pos >= 0)
      {
        rChild       = (BasicHierarchyNode) aChildren.elementAt(pos);
        rChild.rPrevious = rPrev;

        if (pos != i)
        {
          // Swap child AND it's PrevNodeHandle to correct array pos
          HierarchyNode rTmp = (HierarchyNode) aChildren.elementAt(i);
          int        nTmp = rPrevNodeHandles.get(i);

          aChildren.setElementAt(rChild, i);
          aChildren.setElementAt(rTmp, pos);
          rPrevNodeHandles.set(nSearchHandle, i);
          rPrevNodeHandles.set(nTmp, pos);
        }

        nSearchHandle = rChild.nStorageHandle;
        rPrev      = rChild;
      }
      else
      {
        throw new StorageException("Child hierarchy inconsistent");
      }
    }
  }
}
TOP

Related Classes of de.esoco.j2me.model.BasicHierarchyNode

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.