/**
* This source file is part of WZ Hybrid Bots
* For the latest information, see http://sourceforge.net/projects/wzhybridbots
*
* Copyright (c) 2006 - WzCtf
* For more information about WzCtf, see http://www.wzctf.net
* Also see the license in license.txt
*/
package wzhybridbots.security;
/** The imported classes/interfaces */
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
import wzhybridbots.security.BotOperator;
import wzhybridbots.security.BotOperatorSet;
/**
* An HashMap that contains BotOperator.
*
* @author Witlospock
* @version 1.0
*/
public class HashBotOperatorSet implements BotOperatorSet {
/** The map that contains the bot operators */
private Map map = Collections.synchronizedMap( new HashMap() );
/** The conflict resolver use in case of addition conflict */
private ConflictResolver resolver = new BotOperatorConflictResolver();
/**
* Default class constructor. By default, this class
* will use a ConflictResolver that, in case of conflict,
* keeps the bot operator with the highest access level
* between the bot operators.
*/
public HashBotOperatorSet () {
// Initialize the container
init();
}
/**
* Class constructor.
*
* @param resolver The conflict resolver use in case of addition conflict.
*/
public HashBotOperatorSet ( ConflictResolver resolver ) {
if ( resolver == null ) { throw new NullPointerException(); }
// Sets the resolver
this.resolver = resolver;
// Initialize the container
init();
}
/**
* Initializes the container.
*/
protected void init () {
// Clears the content of the container
clear();
}
/**
* Adds a bot operator to the container.
*
* @param operator The operator to add.
* @return true if it's a new addition to the container, false if a conflit was detected.
*/
public boolean add ( BotOperator operator ) {
if ( operator == null ) { throw new NullPointerException(); }
// Checks if the operator is already in the container
boolean alreadyIn = this.contains( operator );
if ( !alreadyIn ) {
// Add the operator to the container
synchronized( map ) {
map.put( operator.getOperatorName(), operator );
}
}
else {
// Get the bot operator object in the container
BotOperator oldOperator = (BotOperator)map.get( operator.getOperatorName() );
if ( oldOperator == null ) { throw new NullPointerException(); }
// Resolve the conflict
BotOperator newOperator = resolver.resolveConflict( operator, oldOperator );
// Keep the good bot operator
remove( oldOperator );
if ( newOperator != null ) {
synchronized ( map ) {
map.put( newOperator.getOperatorName(), newOperator );
}
}
}
return !alreadyIn;
}
/**
* Adds all the bot operator of a container in this one.
*
* @param container The container to get the bot operators from.
*/
public void addAll ( BotOperatorSet container ) {
if ( container == null ) { throw new NullPointerException(); }
if ( resolver == null ) { throw new NullPointerException(); }
// Iterate through one container and add everything to the other
synchronized ( container ) {
for ( Iterator iter = container.iterator() ; iter.hasNext() ; ) {
BotOperator operator = (BotOperator)iter.next();
add( operator );
}
}
}
/**
* Clears the content of the container.
*/
public void clear () {
synchronized ( map ) {
map.clear();
}
}
/**
* Returns true if the bot operator is already in the container,
* false otherwise.
*
* @param operator The bot operator to check out.
* @return see above.
*/
public boolean contains ( BotOperator operator ) {
if ( operator == null ) { throw new NullPointerException(); }
return map.containsKey( operator.getOperatorName() );
}
/**
* Returns true if the container is equal to o.
*
* @param o The object to compare with.
* @return see above.
*/
public boolean equals ( Object o ) {
// Checks if the object structure is the same
if ( o == this ) { return true; }
if ( o == null ) { return false; }
if ( o.hashCode() != this.hashCode() ) { return false; }
if ( !(o instanceof HashBotOperatorSet) ) { return false; }
// Checks if the object contains the same object
HashBotOperatorSet hmbo = (HashBotOperatorSet)o;
if ( hmbo.size() != this.size() ) { return false; }
synchronized ( hmbo ) {
// Checks if every bot operator is the same in the 2 containers
for ( Iterator iter = hmbo.iterator() ; iter.hasNext() ; ) {
BotOperator bo = (BotOperator)iter.next();
BotOperator co = this.get( bo );
if ( !bo.equals( co ) ) { return false; }
}
}
return true;
}
/**
* Returns the hash code of this object.
*
* @return see above.
*/
public int hashCode () {
return this.map.hashCode();
}
/**
* Returns the bot operator specified.
*
* @param operator The bot operator to look for.
* @return The bot operator specified, null otherwise.
*/
public BotOperator get ( BotOperator operator ) {
if ( operator == null ) { throw new NullPointerException(); }
return (BotOperator)map.get( operator.getOperatorName() );
}
/**
* Returns true if the container is empty, false otherwise.
*
* @return see above.
*/
public boolean isEmpty () {
return map.isEmpty();
}
/**
* Returns an iterator on the data in the container.
*
* @return see above.
*/
public Iterator iterator () {
return map.values().iterator();
}
/**
* Removes the bot operator specified.
*
* @param operator The bot operator to remove.
* @return The bot operator if remove successfully, null otherwise.
*/
public BotOperator remove ( BotOperator operator ) {
if ( operator == null ) { throw new NullPointerException(); }
BotOperator retval = null;
synchronized ( map ) {
retval = (BotOperator)map.remove( operator.getOperatorName() );
}
return retval;
}
/**
* Removes all bot operators that are in a container from this one.
*
* @param container The container that contains the bot operators to remove from this container.
*/
public void removeAll ( BotOperatorSet container ) {
if ( container == null ) { throw new NullPointerException(); }
if ( isEmpty() || container.isEmpty() ) { return; }
// Iterate through one container and remove everything to the other
synchronized ( container ) {
for ( Iterator iter = container.iterator() ; iter.hasNext() ; ) {
BotOperator operator = (BotOperator)iter.next();
remove( operator );
}
}
}
/**
* Keeps only the bot operators that are common to both containers.
*
* @param container The container to compare with.
*/
public void retainAll ( BotOperatorSet container ) {
if ( container == null ) { throw new NullPointerException(); }
if ( resolver == null ) { throw new NullPointerException(); }
if ( isEmpty() || container.isEmpty() ) {
clear();
return;
}
// Creates a new map that will contain the intersection of
// both container
Map map = Collections.synchronizedMap( new HashMap() );
// Iterate through one container and check if the other
// has the bot operator has well.
synchronized ( container ) {
for ( Iterator iter = container.iterator() ; iter.hasNext() ; ) {
BotOperator operator = (BotOperator)iter.next();
BotOperator oldOperator = get( operator );
// Checks if the bot operator was in both container
if ( oldOperator != null ) {
// The operator is in both container
BotOperator keep = resolver.resolveConflict( operator, oldOperator );
if ( keep != null ) {
// Add the operator
map.put( keep.getOperatorName(), keep );
}
}
}
}
// Keep the map containing the intersection
this.map = map;
}
/**
* Returns the size of the container.
*
* @return see above.
*/
public int size() {
return map.size();
}
/**
* An interface that specifies the methods required to resolve a
* conflict detected in the container. The class that implements
* this interface must resolve the conflict to get a container
* in a stable state.
*
* @author Witlospock
* @version 1.0
*/
public interface ConflictResolver {
/**
* This method receive the 2 bot operators in conflict and
* must return the one to keep. The returned bot operator
* may be a new once since the 2 bot operator in conflict
* are removed from the container anyway. If null is
* returned, the 2 bot operators will be removed from
* the container without inserting the null value.
*
* @param newOperator The first operator.
* @param oldOperator The second operator.
* @return The operator kept.
*/
public BotOperator resolveConflict ( BotOperator newOperator, BotOperator oldOperator );
}
/**
* A class that resolves conflict when a conflict is detected and
* a solution is required. For example, what should the set do when
* you add a BotOperator to the container while he is already in with
* a different access level ?
*
* @author Witlospock
* @version 1.0
*/
private class BotOperatorConflictResolver implements ConflictResolver {
/**
* Resolves conflict by keeping the highest access level bot operator.
*
* @param newOperator The first operator.
* @param oldOperator The second operator.
* @return The operator with the highest access level.
*/
public BotOperator resolveConflict ( BotOperator newOperator, BotOperator oldOperator ) {
BotOperator retval = oldOperator;
// Keep the highest access level
if ( newOperator.getAccessLevel() > oldOperator.getAccessLevel() ) {
retval = newOperator;
}
return retval;
}
}
}