/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2010 Sun Microsystems, Inc.
* Portions copyright 2011 ForgeRock AS
*/
/**
* The DITCacheMap class implements custom Map for structural
* storage of arbitrary objects in Directory Information Tree
* (DIT) like structure.
*
* This Map intended usage is for caching various server
* objects which can be subject to subtree operations
* like retrieval or removal of all objects under a
* specific DN. While using a regular Map it would
* require the entire Map iteration to achieve, this Map
* implementation maintains such internal structure that
* subtree operations are more efficient and do not
* require iterations over the entire map, instead
* additional subtree operations methods are provided by
* this Map to do just that.
*
* API wise it behaves exactly like a regular Map
* implementation except for providing additional
* subtree methods. All required linkage and
* structuring is performed within this Map
* implementation itself and not exposed via the
* API in any way. For example, putting these
*
* cn=Object1,ou=Objects,dc=example,dc=com : object1
* cn=Object2,ou=Objects,dc=example,dc=com : object2
* cn=Object3,ou=Objects,dc=example,dc=com : object3
*
* then invoking a subtree method on this Map with
* any of these keys
*
* ou=Objects,dc=example,dc=com
* dc=example,dc=com
* dc=com
*
* would bring all three objects previously stored in
* this map into subtree operation scope. Standard
* Map API methods can only work with the objects
* previously stored in this map explicitly.
*
* Note that this Map implementation is not
* synchronized.
*
* @param <T> arbitrary object type.
*/
{
/**
* Node class for object storage and
* linking to any subordinate nodes.
* @param <T> arbitrary storage object.
*/
private static final class Node<T>
{
// Node DN.
// Storage object or null if this node exist
// only to support the DIT like structuring.
T element;
// Parent.
// First child.
// Next sibling.
// Previous sibling.
/**
* {@inheritDoc}
*/
{
{
return "glue";
}
else
{
}
}
}
// Map size reflecting only nodes
// containing non empty elements.
// Backing Map implementation.
/**
* Default constructor.
*/
public DITCacheMap()
{
}
/**
* Constructs a new DITCacheMap from a given Map.
* @param m existing Map to construct new
* DITCacheMap from.
*/
{
this.putAll(m);
}
/**
* {@inheritDoc}
*/
public int size()
{
return size;
}
/**
* {@inheritDoc}
*/
public boolean isEmpty()
{
return ditCacheMap.isEmpty();
}
/**
* {@inheritDoc}
*/
{
{
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
{
{
{
return true;
}
}
return false;
}
/**
* {@inheritDoc}
*/
{
{
}
return null;
}
/**
* Returns a set of stored objects
* subordinate to subtree DN.
* @param key subtree DN.
* @return collection of stored objects
* subordinate to subtree DN.
*/
{
return new DITSubtreeSet(key);
}
/**
* {@inheritDoc}
*/
{
if (existingNode != null)
{
return returnValue;
}
size++;
// Update parent hierarchy.
{
if (parentNode == null)
{
// Add glue node.
}
else
{
{
{
}
}
else
{
}
break;
}
}
return null;
}
/**
* {@inheritDoc}
*/
{
{
return null;
}
if (returnValue == null)
{
return null;
}
// Remove element from DIT.
size--;
{
// This node is now glue, so remove it completely and fix up
// any other nodes which reference it.
}
return returnValue;
}
/**
* Remove references to a node after it has been removed.
* @param node The node which has just been removed.
*/
{
while (true)
{
// Fix siblings.
{
}
if (previousNode != null)
{
}
// Fix parent, if it exists.
if (parentNode == null)
{
// Reached the top of the DIT, so no parents to fix.
break;
}
{
// The parent references another sibling and does not need
// fixing.
break;
}
{
// Update child pointer and return.
break;
}
{
// Parent node is still needed as it contains data.
break;
}
// The parent node is glue so remove it.
// Smash pointers.
// Continue up tree.
node = parentNode;
}
}
/**
* Removes a set of stored objects subordinate to subtree DN.
* @param key subtree DN.
* @param values collection for removed objects subordinate
* to subtree DN or <code>null</code>.
* @return <code>true</code> on success or
* <code>false</code> otherwise.
*/
{
{
// Fix up sibling and parent references.
// Collect all elements and update the size.
return true;
}
else
{
return false;
}
}
/**
* Iterate through detached subtree counting and collecting any
* elements.
*
* @param node
* The node to be collected.
* @param values
* Collection in which to put elemenets.
*/
Collection<? super T> values)
{
{
{
}
size--;
}
// Repeat for each child.
{
}
// Smash pointers.
// Remove node from map.
}
/**
* {@inheritDoc}
*/
{
{
}
}
/**
* {@inheritDoc}
*/
public void clear()
{
ditCacheMap.clear();
size = 0;
}
/**
* {@inheritDoc}
*/
{
return new DITCacheEntrySet();
}
/**
* EntrySet class implementation for the DITCacheMap.
*/
{
/**
* Iterator class implementation for the DITCacheEntrySet.
*/
{
private boolean hasNext;
/**
* Default constructor.
*/
public EntryIterator()
{
currentEntry = null;
hasNext = false;
}
/**
* {@inheritDoc}
*/
public boolean hasNext()
{
if (hasNext)
{
return true;
}
while (ditCacheMapIterator.hasNext())
{
{
hasNext = true;
return true;
}
}
return false;
}
/**
* {@inheritDoc}
*/
{
{
hasNext = false;
}
while (ditCacheMapIterator.hasNext())
{
{
hasNext = false;
}
}
throw new NoSuchElementException();
}
/**
* {@inheritDoc}
*/
public void remove()
{
if (currentEntry != null)
{
if (hasNext())
{
}
{
currentEntry = null;
hasNext = false;
while (hasNext())
{
if ((oldIteratorEntry != null) &&
newIteratorEntry.getKey()) &&
{
hasNext = true;
return;
}
}
currentEntry = null;
hasNext = false;
return;
}
}
throw new IllegalStateException();
}
}
/**
* {@inheritDoc}
*/
public int size()
{
return DITCacheMap.this.size();
}
/**
* {@inheritDoc}
*/
{
return new EntryIterator();
}
}
/**
* Map.Entry class implementation for the DITCacheMap.
*/
{
private T value;
/**
* Constructs a new DITCacheMapEntry
* with given key and value.
* @param key Map.Entry key.
* @param value Map.Entry value.
*/
{
}
/**
* {@inheritDoc}
*/
{
return key;
}
/**
* {@inheritDoc}
*/
public T getValue()
{
return value;
}
/**
* {@inheritDoc}
*/
{
return oldValue;
}
}
/**
* SubtreeSet class implementation.
*/
{
// Set key.
/**
* Keyed constructor.
* @param key to construct
* this set from.
*/
{
}
/**
* Iterator class implementation for SubtreeSet.
*/
{
// Iterator key.
// Iterator root node.
// Iterator current node.
/**
* Default constructor.
*/
public SubtreeSetIterator()
{
}
/**
* Keyed constructor.
* @param key to cue this
* iterator from.
*/
{
}
/**
* {@inheritDoc}
*/
public boolean hasNext()
{
{
{
{
return true;
}
}
{
{
return true;
}
{
}
else
{
{
}
}
}
}
return false;
}
/**
* {@inheritDoc}
*/
public T next()
{
{
{
{
}
}
{
{
}
else
{
}
{
}
else
{
{
}
}
{
return element;
}
}
}
throw new NoSuchElementException();
}
/**
* {@inheritDoc}
*/
public void remove()
{
throw new UnsupportedOperationException();
}
}
/**
* {@inheritDoc}
*/
{
return new SubtreeSetIterator();
}
/**
* {@inheritDoc}
*/
public int size()
{
int size = 0;
{
size++;
}
return size;
}
}
/**
* Returns the size of the internal map. Used for testing purposes
* only.
*
* @return The size of the internal map.
*/
int getMapSize()
{
return ditCacheMap.size();
}
}