Initial commit from SVN.
This commit is contained in:
121
Foundation/src/com/foundation/util/CollectionChangeEvent.java
Normal file
121
Foundation/src/com/foundation/util/CollectionChangeEvent.java
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.util.ICollection;
|
||||
|
||||
public class CollectionChangeEvent implements java.io.Externalizable {
|
||||
private boolean hasAdds = false; //Whether there were any additions.//
|
||||
private Object addedObject = null; //For single item adds.//
|
||||
private ICollection addedObjects = null; //For multi-item adds.//
|
||||
private boolean hasRemoves = false; //Whether there were any removals.//
|
||||
private Object removedObject = null; //For single item removals.//
|
||||
private ICollection removedObjects = null; //For multi-item removes.//
|
||||
/**
|
||||
* CollectionChangeEvent constructor.
|
||||
*/
|
||||
public CollectionChangeEvent() {
|
||||
super();
|
||||
}//CollectionChangeEvent()//
|
||||
/**
|
||||
* CollectionChangeEvent constructor.
|
||||
* @param hasAdds Whether there are added values.
|
||||
* @param addedObjects The added values.
|
||||
* @param hasRemoves Whether there are removed values.
|
||||
* @param removedObjects The removed values.
|
||||
*/
|
||||
public CollectionChangeEvent(boolean hasAdds, ICollection addedObjects, boolean hasRemoves, ICollection removedObjects) {
|
||||
this.hasAdds = hasAdds;
|
||||
this.addedObjects = addedObjects;
|
||||
this.hasRemoves = hasRemoves;
|
||||
this.removedObjects = removedObjects;
|
||||
}//CollectionChangeEvent()//
|
||||
/**
|
||||
* CollectionChangeEvent constructor.
|
||||
* @param hasAdds Whether there is an added value.
|
||||
* @param addedObject The added value.
|
||||
* @param hasRemoves Whether there is a removed value.
|
||||
* @param removedObject The removed value.
|
||||
*/
|
||||
public CollectionChangeEvent(boolean hasAdds, Object addedObject, boolean hasRemoves, Object removedObject) {
|
||||
this.hasAdds = hasAdds;
|
||||
this.addedObject = addedObject;
|
||||
this.hasRemoves = hasRemoves;
|
||||
this.removedObject = removedObject;
|
||||
}//CollectionChangeEvent()//
|
||||
/**
|
||||
* Gets the single object added to the collection that fired the event.
|
||||
* <p>Note: Callers should first call to get the collection of added values. If the collection is null then call this method to get the single value added. This is done to reduce memory overhead by avoiding creating unnecessary lists.</p>
|
||||
* @return The object added to the collection.
|
||||
*/
|
||||
public Object getAddedObject() {
|
||||
return addedObject;
|
||||
}//getAddedObject()//
|
||||
/**
|
||||
* Gets the collection of objects added to the collection that fired the event. This collection will be null if there was only one added object.
|
||||
* @return The objects added to the collection.
|
||||
*/
|
||||
public ICollection getAddedObjects() {
|
||||
return addedObjects;
|
||||
}//getAddedObjects()//
|
||||
/**
|
||||
* Gets the single object removed from the collection that fired the event.
|
||||
* <p>Note: Callers should first call to get the collection of removed values. If the collection is null then call this method to get the single value removed. This is done to reduce memory overhead by avoiding creating unnecessary lists.</p>
|
||||
* @return The object removed to the collection.
|
||||
*/
|
||||
public Object getRemovedObject() {
|
||||
return removedObject;
|
||||
}//getRemovedObject()//
|
||||
/**
|
||||
* Gets the collection of objects removed from the collection that fired the event. This collection will be null if there was only one removed object.
|
||||
* @return The objects removed to the collection.
|
||||
*/
|
||||
public ICollection getRemovedObjects() {
|
||||
return removedObjects;
|
||||
}//getRemovedObjects()//
|
||||
/**
|
||||
* Determines whether there are any added values.
|
||||
* @return Whether there were any additions.
|
||||
*/
|
||||
public boolean hasAdds() {
|
||||
return hasAdds;
|
||||
}//hasAdds()//
|
||||
/**
|
||||
* Determines whether there are any removed values.
|
||||
* @return Whether there were any removals.
|
||||
*/
|
||||
public boolean hasRemoves() {
|
||||
return hasRemoves;
|
||||
}//hasRemoves()//
|
||||
/**
|
||||
* Reads the collection from the stream.
|
||||
* @param in java.io.ObjectInput The stream that the object data can be read from.
|
||||
*/
|
||||
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
|
||||
in.readByte();
|
||||
hasAdds = in.readBoolean();
|
||||
addedObject = in.readObject();
|
||||
addedObjects = (ICollection) in.readObject();
|
||||
hasRemoves = in.readBoolean();
|
||||
removedObject = in.readObject();
|
||||
removedObjects = (ICollection) in.readObject();
|
||||
}//readExternal()//
|
||||
/**
|
||||
* Writes the collection to the stream.
|
||||
* @param out java.io.ObjectOutput The stream that the object data can be written to.
|
||||
*/
|
||||
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
|
||||
out.writeByte(0);
|
||||
out.writeBoolean(hasAdds);
|
||||
out.writeObject(addedObject);
|
||||
out.writeObject(addedObjects);
|
||||
out.writeBoolean(hasRemoves);
|
||||
out.writeObject(removedObject);
|
||||
out.writeObject(removedObjects);
|
||||
}//writeExternal()//
|
||||
}//CollectionChangeEvent//
|
||||
426
Foundation/src/com/foundation/util/CollectionManager.java
Normal file
426
Foundation/src/com/foundation/util/CollectionManager.java
Normal file
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.util.*;
|
||||
|
||||
/**
|
||||
* Collection manager is used to control what is placed in a collection.
|
||||
* Applications are encouraged to extend this class to provide application specific changes.
|
||||
* <p>Note that a single collection manager can be used with multiple collections and is copied when the collection is cloned.</p>
|
||||
*/
|
||||
public abstract class CollectionManager implements java.io.Externalizable {
|
||||
public static final byte CONTEXT_TRUSTED = IManagedCollection.CONTEXT_TRUSTED;
|
||||
public static final byte CONTEXT_UNTRUSTED = IManagedCollection.CONTEXT_UNTRUSTED;
|
||||
/**
|
||||
* CollectionManager constructor.
|
||||
*/
|
||||
public CollectionManager() {
|
||||
super();
|
||||
}//CollectionManager()//
|
||||
/**
|
||||
* Determines whether the value can be added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param value The value that may be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether the value can be added to the collection.
|
||||
*/
|
||||
public boolean canAdd(IManagedCollection managed, Object value, byte context) {
|
||||
return true;
|
||||
}//canAdd()//
|
||||
/**
|
||||
* Determines whether the values can be added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param values The values that may be added.
|
||||
* @param offset The offset of the first value to add.
|
||||
* @param length The count of values added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether the values can be added to the collection.
|
||||
*/
|
||||
public boolean canAddAll(IManagedCollection managed, Object[] values, int offset, int length, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
for(int index = offset; (index < length) && (result); index++) {
|
||||
result = canAdd(managed, values[index], context);
|
||||
}//for//
|
||||
|
||||
return result;
|
||||
}//canAddAll()//
|
||||
/**
|
||||
* Determines whether the values can be added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param values The values that may be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether the values can be added to the collection.
|
||||
*/
|
||||
public boolean canAddAll(IManagedCollection managed, ICollection values, byte context) {
|
||||
boolean result = true;
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
while((result) && (iterator.hasNext())) {
|
||||
result = canAdd(managed, iterator.next(), context);
|
||||
}//while//
|
||||
|
||||
return result;
|
||||
}//canAddAll()//
|
||||
/**
|
||||
* Determines whether the user can make the collection immutable (unchangeable).
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @return Whether the collection immutable flag can be set.
|
||||
*/
|
||||
public boolean canMakeImmutable(IManagedCollection managed) {
|
||||
return true;
|
||||
}//canMakeImmutable()//
|
||||
/**
|
||||
* Determines whether the value can be removed from the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param value The value that may be removed.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether the value can be removed from the collection.
|
||||
*/
|
||||
public boolean canRemove(IManagedCollection managed, Object value, byte context) {
|
||||
return true;
|
||||
}//canRemove()//
|
||||
/**
|
||||
* Determines whether the values can be removed from the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param values The values that may be removed.
|
||||
* @param offset The offset of the first value to remove.
|
||||
* @param length The count of values removed.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether the values can be removed from the collection.
|
||||
*/
|
||||
public boolean canRemoveAll(IManagedCollection managed, Object[] values, int offset, int length, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
for(int index = offset; (index < length) && (result); index++) {
|
||||
result = canRemove(managed, values[index], context);
|
||||
}//for//
|
||||
|
||||
return result;
|
||||
}//canRemoveAll()//
|
||||
/**
|
||||
* Determines whether all the values can be removed from the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether all the values can be removed from the collection.
|
||||
*/
|
||||
public boolean canRemoveAll(IManagedCollection managed, byte context) {
|
||||
boolean result = true;
|
||||
IIterator iterator = managed.iterator();
|
||||
|
||||
while((result) && (iterator.hasNext())) {
|
||||
result = canRemove(managed, iterator.next(), context);
|
||||
}//while//
|
||||
|
||||
return result;
|
||||
}//canRemoveAll()//
|
||||
/**
|
||||
* Determines whether the values can be removed from the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param values The values that may be removed.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether the values can be removed from the collection.
|
||||
*/
|
||||
public boolean canRemoveAll(IManagedCollection managed, ICollection values, byte context) {
|
||||
boolean result = true;
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
while((result) && (iterator.hasNext())) {
|
||||
result = canRemove(managed, iterator.next(), context);
|
||||
}//while//
|
||||
|
||||
return result;
|
||||
}//canRemoveAll()//
|
||||
/**
|
||||
* Determines whether the value can be swapped in the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param oldValue The value that may be replaced.
|
||||
* @param newValue The value that may replace the old one.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether the value can be replaced in the collection with the new value.
|
||||
*/
|
||||
public boolean canReplace(IManagedCollection managed, Object oldValue, Object newValue, byte context) {
|
||||
return canRemove(managed, oldValue, context) && canAdd(managed, newValue, context);
|
||||
}//canReplace()//
|
||||
/**
|
||||
* Determines whether the collection should ask the manager to allow an add operation.
|
||||
* @return Whether this manager will be asked for permission before an add operation.
|
||||
*/
|
||||
public boolean checkOnAdd() {
|
||||
return false;
|
||||
}//checkOnAdd()//
|
||||
/**
|
||||
* Determines whether the collection should ask the manager to allow a remove operation.
|
||||
* @return Whether this manager will be asked for permission before a remove operation.
|
||||
*/
|
||||
public boolean checkOnRemove() {
|
||||
return false;
|
||||
}//checkOnRemove()//
|
||||
/**
|
||||
* Determines whether the collection should ask the manager to allow a replace operation.
|
||||
* @return Whether this manager will be asked for permission before a replace operation.
|
||||
*/
|
||||
public boolean checkOnReplace() {
|
||||
return false;
|
||||
}//checkOnReplace()//
|
||||
/**
|
||||
* Determines whether the collection should notify the manager after an add operation occurs.
|
||||
* @return Whether this manager will be notified after an add operation.
|
||||
*/
|
||||
public boolean notifyOnPostAdd() {
|
||||
return false;
|
||||
}//notifyOnPostAdd()//
|
||||
/**
|
||||
* Determines whether the collection should notify the manager after a remove operation occurs.
|
||||
* @return Whether this manager will be notified after a remove operation.
|
||||
*/
|
||||
public boolean notifyOnPostRemove() {
|
||||
return false;
|
||||
}//notifyOnPostRemove()//
|
||||
/**
|
||||
* Determines whether the collection should notify the manager after a replace operation occurs.
|
||||
* @return Whether this manager will be notified after a replace operation.
|
||||
*/
|
||||
public boolean notifyOnPostReplace() {
|
||||
return notifyOnPostAdd() || notifyOnPostRemove();
|
||||
}//notifyOnPostReplace()//
|
||||
/**
|
||||
* Determines whether the collection should notify the manager before an add operation occurs.
|
||||
* @return Whether this manager will be notified before an add operation.
|
||||
*/
|
||||
public boolean notifyOnPreAdd() {
|
||||
return false;
|
||||
}//notifyOnPreAdd()//
|
||||
/**
|
||||
* Determines whether the collection should notify the manager before a remove operation occurs.
|
||||
* @return Whether this manager will be notified before a remove operation.
|
||||
*/
|
||||
public boolean notifyOnPreRemove() {
|
||||
return false;
|
||||
}//notifyOnPreRemove()//
|
||||
/**
|
||||
* Determines whether the collection should notify the manager before a replace operation occurs.
|
||||
* @return Whether this manager will be notified before a replace operation.
|
||||
*/
|
||||
public boolean notifyOnPreReplace() {
|
||||
return notifyOnPreAdd() || notifyOnPreRemove();
|
||||
}//notifyOnPreReplace()//
|
||||
/**
|
||||
* Allows the manager to provide functionality after a value has been added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param value The value that has be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #preAdd(Object)
|
||||
*/
|
||||
public void postAdd(IManagedCollection managed, Object value, byte context) {
|
||||
}//postAdd()//
|
||||
/**
|
||||
* Allows the manager to provide functionality after values are added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param values The values that have been added.
|
||||
* @param offset The offset of the first value to add.
|
||||
* @param length The count of values added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #preAddAll(IManagedCollection, Object[], int, int, byte)
|
||||
*/
|
||||
public void postAddAll(IManagedCollection managed, Object[] values, int offset, int length, byte context) {
|
||||
for(int index = offset; index < length; index++) {
|
||||
postAdd(managed, values[index], context);
|
||||
}//for//
|
||||
}//postAddAll()//
|
||||
/**
|
||||
* Allows the manager to pprovide functionality after values are added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param values The values that have been added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #preAddAll(IManagedCollection)
|
||||
*/
|
||||
public void postAddAll(IManagedCollection managed, ICollection values, byte context) {
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
postAdd(managed, iterator.next(), context);
|
||||
}//while//
|
||||
}//postAddAll()//
|
||||
/**
|
||||
* Called after the collection is made immutable (unchangeable).
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
*/
|
||||
public void postMakeImmutable(IManagedCollection managed) {
|
||||
}//postMakeImmutable()//
|
||||
/**
|
||||
* Allows the manager to provide functionality after a value has been removed from the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param value The value that has be removed.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #preRemove(Object)
|
||||
*/
|
||||
public void postRemove(IManagedCollection managed, Object value, byte context) {
|
||||
}//postRemove()//
|
||||
/**
|
||||
* Allows the manager to provide functionality after values were removed from the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param values The values that were removed.
|
||||
* @param offset The offset of the first value to remove.
|
||||
* @param length The count of values removed.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #preRemoveAll(IManagedCollection, Object[], int, int, byte)
|
||||
*/
|
||||
public void postRemoveAll(IManagedCollection managed, Object[] values, int offset, int length, byte context) {
|
||||
for(int index = offset; index < length; index++) {
|
||||
postRemove(managed, values[index], context);
|
||||
}//for//
|
||||
}//postRemoveAll()//
|
||||
/**
|
||||
* Allows the manager to provide functionality after values were removed from the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param values The values that were removed.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #preRemoveAll(IManagedCollection)
|
||||
*/
|
||||
public void postRemoveAll(IManagedCollection managed, ICollection values, byte context) {
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
postRemove(managed, iterator.next(), context);
|
||||
}//while//
|
||||
}//postRemoveAll()//
|
||||
/**
|
||||
* Allows the manager to provide functionality after one value replaces another in the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param oldValue The value that was replaced.
|
||||
* @param newValue The value that did replace the old one.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #preReplace(Object)
|
||||
*/
|
||||
public void postReplace(IManagedCollection managed, Object oldValue, Object newValue, byte context) {
|
||||
postRemove(managed, oldValue, context);
|
||||
postAdd(managed, newValue, context);
|
||||
}//postReplace()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to the value being added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param value The value that will be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #canAdd(Object)
|
||||
*/
|
||||
public void preAdd(IManagedCollection managed, Object value, byte context) {
|
||||
}//preAdd()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to the values being added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param values The values that will be added.
|
||||
* @param offset The offset of the first value to add.
|
||||
* @param length The count of values added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #canAddAll(IManagedCollection, Object[], int, int, byte)
|
||||
*/
|
||||
public void preAddAll(IManagedCollection managed, Object[] values, int offset, int length, byte context) {
|
||||
for(int index = offset; index < length; index++) {
|
||||
preAdd(managed, values[index], context);
|
||||
}//for//
|
||||
}//preAddAll()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to the values being added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param values The values that will be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #canAddAll(IManagedCollection)
|
||||
*/
|
||||
public void preAddAll(IManagedCollection managed, ICollection values, byte context) {
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
preAdd(managed, iterator.next(), context);
|
||||
}//while//
|
||||
}//preAddAll()//
|
||||
/**
|
||||
* Called before the collection is made immutable (unchangeable).
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
*/
|
||||
public void preMakeImmutable(IManagedCollection managed) {
|
||||
}//preMakeImmutable()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to the value being removed from the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param value The value that will be removed.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #canRemove(Object)
|
||||
*/
|
||||
public void preRemove(IManagedCollection managed, Object value, byte context) {
|
||||
}//preRemove()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to the values being removed from the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param values The values that will be removed.
|
||||
* @param offset The offset of the first value to remove.
|
||||
* @param length The count of values removed.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #canRemoveAll(IManagedCollection, Object[], int, int, byte)
|
||||
*/
|
||||
public void preRemoveAll(IManagedCollection managed, Object[] values, int offset, int length, byte context) {
|
||||
for(int index = offset; index < length; index++) {
|
||||
preRemove(managed, values[index], context);
|
||||
}//while//
|
||||
}//preRemoveAll()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to all the values being removed from the collection.
|
||||
* <p>NOTE: After the removal, the collection will call one of the postRemoveAll methods passing a copy of the collection as it was before all the items were removed.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #canRemoveAll()
|
||||
*/
|
||||
public void preRemoveAll(IManagedCollection managed, byte context) {
|
||||
IIterator iterator = managed.iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
preRemove(managed, iterator.next(), context);
|
||||
}//while//
|
||||
}//preRemoveAll()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to the values being removed from the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param values The values that will be removed.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #canRemoveAll(IManagedCollection)
|
||||
*/
|
||||
public void preRemoveAll(IManagedCollection managed, ICollection values, byte context) {
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
preRemove(managed, iterator.next(), context);
|
||||
}//while//
|
||||
}//preRemoveAll()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to one value replacing another in the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param oldValue The value that is going to be replaced.
|
||||
* @param newValue The value that will replace the old one.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #canReplace(Object)
|
||||
*/
|
||||
public void preReplace(IManagedCollection managed, Object oldValue, Object newValue, byte context) {
|
||||
preRemove(managed, oldValue, context);
|
||||
preAdd(managed, newValue, context);
|
||||
}//preReplace()//
|
||||
/**
|
||||
* Reads the collection manager from a stream.
|
||||
* @param in The input stream to deserialize from.
|
||||
*/
|
||||
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
|
||||
/*byte version = */in.readByte();
|
||||
}//readExternal()//
|
||||
/**
|
||||
* Writes the collection manager to the stream.
|
||||
* @param out The output stream to serialize to.
|
||||
*/
|
||||
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
|
||||
out.writeByte(0);
|
||||
}//writeExternal()//
|
||||
}//CollectionManager//
|
||||
745
Foundation/src/com/foundation/util/HashMap.java
Normal file
745
Foundation/src/com/foundation/util/HashMap.java
Normal file
@@ -0,0 +1,745 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2009 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.thread.Monitor;
|
||||
import com.common.util.ICollection;
|
||||
import com.common.util.IHashMap;
|
||||
import com.common.util.IIterator;
|
||||
import com.common.util.LiteHashMap;
|
||||
import com.common.util.LiteList;
|
||||
import com.common.debug.*;
|
||||
import com.common.comparison.IComparator;
|
||||
import com.foundation.attribute.AttributeSupport;
|
||||
import com.foundation.common.BackReferenceNode;
|
||||
import com.foundation.common.IEntity;
|
||||
import com.foundation.common.MetadataContainer;
|
||||
import com.foundation.metadata.CloneContext;
|
||||
import com.foundation.metadata.ISupportsContainment;
|
||||
import com.foundation.metadata.LoadAttributesContext;
|
||||
import com.foundation.metadata.TypeCallbackHandler;
|
||||
import com.foundation.metadata.MetadataService;
|
||||
|
||||
/**
|
||||
* Provides advanced map functionality, such as the ability to wrapper it with an adapter.
|
||||
* <p><b>TODO: This class needs to have change tracking. Once change tracking is implemented we can properly implement change notification (updating the part-of entity's virtual object change counter) - see ManagedCollection.collectionStateChanged().</b></p>
|
||||
* <p>TODO: Allow this map to be reflected (copy from ManagedCollection - this will require the class extend a different base class).</p>
|
||||
*/
|
||||
public class HashMap extends LiteHashMap implements IInlineCollectionObservable {
|
||||
protected static final int CHANGE_TYPE_ADD = 0;
|
||||
protected static final int CHANGE_TYPE_REMOVE = 1;
|
||||
protected static final int CHANGE_TYPE_REMOVE_ALL = 2;
|
||||
protected static final int CHANGE_TYPE_START_CHANGES = 3;
|
||||
protected static final int CHANGE_TYPE_STOP_CHANGES = 4;
|
||||
|
||||
protected static final TypeCallbackHandler TYPE_CALLBACK_HANDLER = new TypeCallbackHandler() {
|
||||
public Monitor getMonitor(Object instance) {
|
||||
return ((ManagedCollection) instance).getMonitor();
|
||||
}//getMonitor()//
|
||||
public void setMonitor(Object instance, IEntity parent, boolean isPartOf) {
|
||||
if(parent == null) {
|
||||
if(((HashMap) instance).getPartOfEntityCounter() != 0) {
|
||||
((HashMap) instance).setPartOfEntityCounter(((HashMap) instance).getPartOfEntityCounter() - 1);
|
||||
|
||||
if(((HashMap) instance).getPartOfEntityCounter() == 0) {
|
||||
((HashMap) instance).setPartOfEntity(null);
|
||||
((HashMap) instance).isPartOf(false);
|
||||
}//if//
|
||||
}//if//
|
||||
}//if//
|
||||
else if(((HashMap) instance).getPartOfEntity() == parent) {
|
||||
((HashMap) instance).setPartOfEntityCounter(((HashMap) instance).getPartOfEntityCounter() + 1);
|
||||
}//else if//
|
||||
else if(((HashMap) instance).getPartOfEntity() != null) {
|
||||
if(((HashMap) instance).getMonitor() != parent.getMonitor()) {
|
||||
Debug.log(new RuntimeException("Error: Invalid monitor state: A managed hash map cannot be contained by more than one object or collection."));
|
||||
//TODO: Throw a custom exception and catch it in the code that is setting up the containment.//
|
||||
}//if//
|
||||
}//else if//
|
||||
else {
|
||||
((HashMap) instance).setPartOfEntityCounter(1);
|
||||
((HashMap) instance).setPartOfEntity(parent);
|
||||
((HashMap) instance).isPartOf(isPartOf);
|
||||
}//else//
|
||||
}//setMonitor()//
|
||||
public AttributeSupport getAttributeSupport(Object instance) {
|
||||
return null;
|
||||
}//getAttributeSupport()//
|
||||
public void preClone(Object instance, MetadataContainer metadata, CloneContext cloneContext) {
|
||||
((HashMap) instance).preClone(metadata, cloneContext);
|
||||
}//preClone()//
|
||||
public ISupportsContainment clone(Object instance, MetadataContainer metadata, CloneContext cloneContext) {
|
||||
HashMap result = null;
|
||||
CloneContext context = cloneContext;
|
||||
|
||||
if(context != null) {
|
||||
//Load a previous clone in this cloning context.//
|
||||
result = (HashMap) context.getClone(instance);
|
||||
}//if//
|
||||
else {
|
||||
context = createCloneContext();
|
||||
}//else//
|
||||
|
||||
if(result == null) {
|
||||
//Create a shallow copy of the hash map.//
|
||||
result = (HashMap) ((HashMap) instance).clone();
|
||||
|
||||
if(((HashMap) instance).isPartOf()) {
|
||||
//Clone attribute values that are part of this entity and reference the clones. Also clear key attributes, repository bindings, and transient attributes.//
|
||||
result.clonePartOfReferences(context, metadata);
|
||||
}//if//
|
||||
}//if//
|
||||
|
||||
if(cloneContext == null) {
|
||||
context.release();
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//clone()//
|
||||
public void loadAttributes(Object instance, LoadAttributesContext context) {
|
||||
//Clone attribute values that are part of this entity and reference the clones. Also clear key attributes, repository bindings, and transient attributes.//
|
||||
((HashMap) instance).loadAttributes(context);
|
||||
}//loadAttributes()//
|
||||
public void postLoadAttributes(Object instance, LoadAttributesContext context) {
|
||||
((HashMap) instance).postLoadAttributes(context);
|
||||
}//postLoadAttributes()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#getIsVirtualObjectChanged(java.lang.Object)
|
||||
*/
|
||||
public boolean getIsVirtualObjectChanged(Object instance) {
|
||||
/* HashSet does not currently track changes.
|
||||
* TODO: Enable this when change tracking is added.
|
||||
boolean result = ((HashMap) instance).trackChanges && ((((HashMap) instance).getAddedValues().getSize() > 0) || (((HashMap) instance).getRemovedValues().getSize() > 0));
|
||||
*/
|
||||
boolean result = false;
|
||||
|
||||
if((!result) && (((HashMap) instance).isPartOf())) {
|
||||
IIterator iterator = ((HashMap) instance).valueIterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object next = iterator.next();
|
||||
|
||||
if(next instanceof ISupportsContainment) {
|
||||
TypeCallbackHandler handler = MetadataService.getSingleton().getTypeMetadata(next.getClass()).getTypeCallbackHandler();
|
||||
|
||||
result = handler.getIsVirtualObjectChanged(next);
|
||||
}//if//
|
||||
}//while//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//getIsVirtualObjectChanged()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#resetVirtualObjectChangeFlags(java.lang.Object)
|
||||
*/
|
||||
public void resetVirtualObjectChangeFlags(Object instance) {
|
||||
/* HashSet does not currently track changes.
|
||||
* TODO: Enable this when change tracking is added.
|
||||
if(((HashMap) instance).trackChanges) {
|
||||
((HashMap) instance).resetChangeTracking();
|
||||
}//if//
|
||||
*/
|
||||
|
||||
if(((HashMap) instance).isPartOf()) {
|
||||
IIterator iterator = ((HashMap) instance).valueIterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object next = iterator.next();
|
||||
|
||||
if(next instanceof ISupportsContainment) {
|
||||
TypeCallbackHandler handler = MetadataService.getSingleton().getTypeMetadata(next.getClass()).getTypeCallbackHandler();
|
||||
|
||||
handler.resetVirtualObjectChangeFlags(next);
|
||||
}//if//
|
||||
}//while//
|
||||
}//if//
|
||||
}//resetVirtualObjectChangeFlags()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#reverseVirtualObjectChanges(java.lang.Object)
|
||||
*/
|
||||
public void reverseVirtualObjectChanges(Object instance) {
|
||||
/* HashSet does not currently track changes.
|
||||
* TODO: Enable this when change tracking is added.
|
||||
if(((HashMap) instance).trackChanges) {
|
||||
((HashMap) instance).removeAll(((HashMap) instance).getAddedValues());
|
||||
((HashMap) instance).addAll(((HashMap) instance).getRemovedValues());
|
||||
((HashMap) instance).resetChangeTracking();
|
||||
}//if//
|
||||
*/
|
||||
|
||||
//Note: The values that were added may have been changed, but since they are no longer part-of and they were part-of before, then we can assume that they are not going to remain in the system and thus don't need to be considered here.//
|
||||
if(((HashMap) instance).isPartOf()) {
|
||||
IIterator iterator = ((HashMap) instance).valueIterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object next = iterator.next();
|
||||
|
||||
if(next instanceof ISupportsContainment) {
|
||||
TypeCallbackHandler handler = MetadataService.getSingleton().getTypeMetadata(next.getClass()).getTypeCallbackHandler();
|
||||
|
||||
handler.reverseVirtualObjectChanges(next);
|
||||
}//if//
|
||||
}//while//
|
||||
}//if//
|
||||
}//reverseVirtualObjectChanges()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#getIsVirtualObjectAltered(java.lang.Object)
|
||||
*/
|
||||
public boolean getIsVirtualObjectAltered(Object instance) {
|
||||
boolean result = ((HashMap) instance).getIsAltered();
|
||||
|
||||
if((!result) && (((HashMap) instance).isPartOf())) {
|
||||
IIterator iterator = ((HashMap) instance).valueIterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object next = iterator.next();
|
||||
|
||||
if(next instanceof ISupportsContainment) {
|
||||
TypeCallbackHandler handler = MetadataService.getSingleton().getTypeMetadata(next.getClass()).getTypeCallbackHandler();
|
||||
|
||||
result = handler.getIsVirtualObjectAltered(next);
|
||||
}//if//
|
||||
}//while//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//getIsVirtualObjectAltered()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#resetVirtualObjectAlteredFlags(java.lang.Object)
|
||||
*/
|
||||
public void resetVirtualObjectAlteredFlags(Object instance) {
|
||||
((HashMap) instance).resetAlteredFlag();
|
||||
|
||||
if(((HashMap) instance).isPartOf()) {
|
||||
IIterator iterator = ((HashMap) instance).valueIterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object next = iterator.next();
|
||||
|
||||
if(next instanceof ISupportsContainment) {
|
||||
TypeCallbackHandler handler = MetadataService.getSingleton().getTypeMetadata(next.getClass()).getTypeCallbackHandler();
|
||||
|
||||
handler.resetVirtualObjectAlteredFlags(next);
|
||||
}//if//
|
||||
}//while//
|
||||
}//if//
|
||||
}//resetVirtualObjectAlteredFlags()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#setMaintainWeakLinkBackReferences(java.lang.Object)
|
||||
*/
|
||||
public void setMaintainWeakLinkBackReferences(Object instance) {
|
||||
((HashMap) instance).setMaintainWeakLinkBackReferences();
|
||||
}//setMaintainWeakLinkBackReferences()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#addWeakLinkBackReference(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public void addWeakLinkBackReference(Object instance, Object collection) {
|
||||
((HashMap) instance).weakLinkBackReferenceRootNode = new BackReferenceNode(collection, ((HashMap) instance).weakLinkBackReferenceRootNode);
|
||||
}//addWeakLinkBackReference()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#removeWeakLinkBackReference(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public void removeWeakLinkBackReference(Object instance, Object collection) {
|
||||
BackReferenceNode previous = null;
|
||||
BackReferenceNode next = ((HashMap) instance).weakLinkBackReferenceRootNode;
|
||||
|
||||
while(next != null && next.getReference() != collection) {
|
||||
previous = next;
|
||||
next = next.getNext();
|
||||
}//while//
|
||||
|
||||
if(next != null) {
|
||||
if(previous != null) {
|
||||
previous.setNext(next.getNext());
|
||||
}//if//
|
||||
else {
|
||||
((HashMap) instance).weakLinkBackReferenceRootNode = next.getNext();
|
||||
}//else//
|
||||
}//if//
|
||||
}//removeWeakLinkBackReference()//
|
||||
};//TypeCallbackHandler//
|
||||
|
||||
static {
|
||||
MetadataService.getSingleton().setTypeCallbackHandler(HashMap.class, TYPE_CALLBACK_HANDLER);
|
||||
}//static//
|
||||
|
||||
/**
|
||||
* Defines a collection operation that may make multiple changes to the collection.
|
||||
* The collection operation makes making changes more efficient since only one event is fired for a set of changes.
|
||||
*/
|
||||
public interface ICollectionOperation {
|
||||
public void run(HashMap collection);
|
||||
}//ICollectionOperation//
|
||||
|
||||
/** A collection of ICollectionObserver instances which will be provided immediate inline change notification. */
|
||||
private LiteList collectionObservers = null;
|
||||
/** The number of times the part of entity has been set to the same value. */
|
||||
private volatile int partOfEntityCounter = 0;
|
||||
/** A reference to the entity that this collection is a part of. If the collection is not a part of an entity then this will be null. */
|
||||
private volatile IEntity partOfEntity = null;
|
||||
/** The monitor for this collection or null if this map object is to be used as the monitor. Users will synchronize on this monitor prior to accessing the public methods. */
|
||||
private volatile Monitor entityMonitor = null;
|
||||
/** TODO: It would be nice if this hashmap had the monitor built in instead of creating a separate object. This will require changing the hierarchy which is probably best anyways to allow for reflectable hashmaps and advanced behavior. */
|
||||
private final Monitor localMonitor = new Monitor(this);
|
||||
/** Whether this collection is part of another object (logically an integrated component and cannot exist outside that context). */
|
||||
private boolean isPartOf = false;
|
||||
/** A flag that is used to track whether the object may have been altered. This is intended to be less accuate than hasChanged and the added and removed values collections. The intended use is to improve view validation by only validating objects that may have been altered. */
|
||||
private boolean isAltered = false;
|
||||
/** Whether back references should be maintained between collected items and the collection to prevent the model referencing this collection from GC'ing the collection while collected items are referenced. */
|
||||
private boolean maintainWeakLinkBackReferences = false;
|
||||
/** The root node in the linked list of back references used when the object is referenced by a collection that is referenced by an entity using the part-of and weak flags. */
|
||||
private BackReferenceNode weakLinkBackReferenceRootNode = null;
|
||||
/**
|
||||
* HashMap constructor.
|
||||
*/
|
||||
protected HashMap() {
|
||||
super();
|
||||
}//HashMap()//
|
||||
/**
|
||||
* HashMap constructor.
|
||||
* @param initialCapacity
|
||||
*/
|
||||
public HashMap(int initialCapacity) {
|
||||
super(initialCapacity);
|
||||
}//HashMap()//
|
||||
/**
|
||||
* HashMap constructor.
|
||||
* @param initialCapacity
|
||||
* @param loadFactor
|
||||
*/
|
||||
public HashMap(int initialCapacity, float loadFactor) {
|
||||
super(initialCapacity, loadFactor);
|
||||
}//HashMap()//
|
||||
/**
|
||||
* HashMap constructor.
|
||||
* @param initialCapacity
|
||||
* @param loadFactor
|
||||
* @param keyComparator
|
||||
* @param valueComparator
|
||||
*/
|
||||
public HashMap(int initialCapacity, float loadFactor, IComparator keyComparator, IComparator valueComparator) {
|
||||
super(initialCapacity, loadFactor, keyComparator, valueComparator);
|
||||
}//HashMap()//
|
||||
/**
|
||||
* HashMap constructor.
|
||||
* @param initialCapacity
|
||||
* @param keyComparator
|
||||
* @param valueComparator
|
||||
*/
|
||||
public HashMap(int initialCapacity, IComparator keyComparator, IComparator valueComparator) {
|
||||
super(initialCapacity, keyComparator, valueComparator);
|
||||
}//HashMap()//
|
||||
/**
|
||||
* HashMap constructor.
|
||||
* @param keyComparator
|
||||
* @param valueComparator
|
||||
*/
|
||||
public HashMap(IComparator keyComparator, IComparator valueComparator) {
|
||||
super(keyComparator, valueComparator);
|
||||
}//HashMap()//
|
||||
/**
|
||||
* HashMap constructor.
|
||||
* @param map The map to be copied.
|
||||
*/
|
||||
public HashMap(IHashMap map) {
|
||||
super(map);
|
||||
}//HashMap()//
|
||||
/**
|
||||
* HashMap constructor.
|
||||
* @param map The map to be copied.
|
||||
*/
|
||||
public HashMap(HashMap map) {
|
||||
super(map);
|
||||
}//HashMap()//
|
||||
/**
|
||||
* Gets whether the object has been altered in some way.
|
||||
* <p>
|
||||
* The altered flag errors on the side of false positives with no possibility of a false negative.
|
||||
* The intended use of the altered flag is to improve validation efficiency.
|
||||
* </p>
|
||||
*/
|
||||
public boolean getIsAltered() {
|
||||
return isAltered;
|
||||
}//getIsAltered()//
|
||||
/**
|
||||
* Resets the altered flag which is used to identify when the object may have been altered.
|
||||
* <p>
|
||||
* The altered flag errors on the side of false positives with no possibility of a false negative.
|
||||
* The intended use of the altered flag is to improve validation efficiency.
|
||||
* </p>
|
||||
*/
|
||||
public void resetAlteredFlag() {
|
||||
if(isAltered) {
|
||||
TypeCallbackHandler handler = MetadataService.getSingleton().getTypeMetadata(getPartOfEntity().getClass()).getTypeCallbackHandler();
|
||||
|
||||
handler.updateVirtualObjectAlteredCounter(getPartOfEntity(), false, 1);
|
||||
}//if//
|
||||
|
||||
isAltered = false;
|
||||
}//resetAlteredFlag()//
|
||||
/**
|
||||
* Determines whether there are any observers to this collection.
|
||||
* @return Whether there are any observer objects attached to this collection.
|
||||
*/
|
||||
protected boolean hasCollectionObservers() {
|
||||
return (collectionObservers != null) && (collectionObservers.getSize() > 0);
|
||||
}//hasCollectionObservers()//
|
||||
/**
|
||||
* Notifies any collection listeners of a change in the collection values.
|
||||
* @param value The value added.
|
||||
*/
|
||||
protected void notifyCollectionObserversOnAdd(Object value) {
|
||||
if((collectionObservers != null) && (collectionObservers.getSize() > 0)) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).valueAdded(value);
|
||||
}//for//
|
||||
}//if//
|
||||
}//notifyCollectionObserversOnAdd()//
|
||||
/**
|
||||
* Notifies any collection listeners of a change in the collection values.
|
||||
* @param value The value removed.
|
||||
*/
|
||||
protected void notifyCollectionObserversOnRemove(Object value) {
|
||||
if((collectionObservers != null) && (collectionObservers.getSize() > 0)) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).valueRemoved(value);
|
||||
}//for//
|
||||
}//if//
|
||||
}//notifyCollectionObserversOnRemove()//
|
||||
/**
|
||||
* Notifies any collection listeners of a change in the collection values.
|
||||
*/
|
||||
protected void notifyCollectionObserversOnRemovingAll() {
|
||||
if((collectionObservers != null) && (collectionObservers.getSize() > 0)) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).removingAll();
|
||||
}//for//
|
||||
}//if//
|
||||
}//notifyCollectionObserversOnRemovingAll()//
|
||||
/**
|
||||
* Notifies any collection listeners that a set of changes to the collection is beginning.
|
||||
* @param changeCount The number of changes anticipated, or <= 0 if unkown.
|
||||
*/
|
||||
protected void notifyCollectionObserversOnStart(int changeCount) {
|
||||
if((collectionObservers != null) && (collectionObservers.getSize() > 0)) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).startChanges(changeCount);
|
||||
}//for//
|
||||
}//if//
|
||||
}//notifyCollectionObserversOnStart()//
|
||||
/**
|
||||
* Notifies any collection listeners that the set of changes to the collection has ended.
|
||||
*/
|
||||
protected void notifyCollectionObserversOnStop() {
|
||||
if((collectionObservers != null) && (collectionObservers.getSize() > 0)) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).stopChanges();
|
||||
}//for//
|
||||
}//if//
|
||||
}//notifyCollectionObserversOnStop()//
|
||||
/**
|
||||
* Places a key/value pair in the map.
|
||||
* The value can be retrieved later with the given key.
|
||||
* @param key The key that will be used to map the value.
|
||||
* @param value The value stored in map.
|
||||
* @return The value previously associated with the key.
|
||||
*/
|
||||
public Object put(Object key, Object value) {
|
||||
Object result = super.put(key, value);
|
||||
|
||||
if(result != null) {
|
||||
setContainment(result, false);
|
||||
notifyCollectionObserversOnRemove(result);
|
||||
}//if//
|
||||
|
||||
if(value != null) {
|
||||
setContainment(value, true);
|
||||
notifyCollectionObserversOnAdd(value);
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//put()//
|
||||
/**
|
||||
* Removes a key/value pair from the map.
|
||||
* @param key The key that should be removed (with its' value) from the map.
|
||||
* @return Will be the value removed from map. A <code>null</code> value is returned if the key was not found.
|
||||
*/
|
||||
public Object remove(Object key) {
|
||||
Object result = super.remove(key);
|
||||
|
||||
if(result != null) {
|
||||
setContainment(result, false);
|
||||
notifyCollectionObserversOnRemove(result);
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//remove()//
|
||||
/**
|
||||
* Removes all key/value pairs from the map.
|
||||
* @return Will be <code>true</code> if the method was successful.
|
||||
*/
|
||||
public void removeAll() {
|
||||
LiteList removedData = new LiteList(valueIterator(), getSize(), 10, false);
|
||||
|
||||
notifyCollectionObserversOnRemovingAll();
|
||||
super.removeAll();
|
||||
|
||||
//Clear containments.//
|
||||
if(isPartOf) {
|
||||
for(int index = 0; index < removedData.getSize(); index++) {
|
||||
setContainment(removedData.get(index), false);
|
||||
}//for//
|
||||
}//if//
|
||||
}//removeAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.IInlineCollectionObservable#addCollectionObserver(com.foundation.util.IInlineCollectionObserver)
|
||||
*/
|
||||
public void addCollectionObserver(IInlineCollectionObserver observer) {
|
||||
if(collectionObservers == null) {
|
||||
collectionObservers = new LiteList(2, 4);
|
||||
}//if//
|
||||
|
||||
collectionObservers.add(observer);
|
||||
observer.startChanges(getSize());
|
||||
|
||||
//Pass all existing values to the observer.//
|
||||
for(IIterator iterator = valueIterator(); iterator.hasNext();) {
|
||||
observer.valueAdded(iterator.next());
|
||||
}//for//
|
||||
|
||||
observer.stopChanges();
|
||||
}//addCollectionObserver()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.IInlineCollectionObservable#removeCollectionObserver(com.foundation.util.IInlineCollectionObserver)
|
||||
*/
|
||||
public void removeCollectionObserver(IInlineCollectionObserver observer) {
|
||||
collectionObservers.remove(observer);
|
||||
}//removeCollectionObserver()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.IInlineCollectionObservable#getCollection()
|
||||
*/
|
||||
public ICollection getCollection() {
|
||||
return new LiteList((IIterator) valueIterator(), this.getSize(), 10, true);
|
||||
}//getCollection()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.IInlineCollectionObservable#getMonitor()
|
||||
*/
|
||||
public Monitor getMonitor() {
|
||||
Monitor monitor = getEntityMonitor();
|
||||
|
||||
if((monitor != null) && (monitor.getSupported() instanceof ISupportsContainment) && (monitor.getSupported() != this)) {
|
||||
monitor = ((ISupportsContainment) monitor.getSupported()).getMonitor();
|
||||
}//if//
|
||||
|
||||
return monitor == null ? localMonitor : monitor;
|
||||
}//getMonitor()//
|
||||
/**
|
||||
* Executes an operation on this collection such that events are condensed into one.
|
||||
* @param operation the operation to be run.
|
||||
*/
|
||||
public void execute(ICollectionOperation operation) {
|
||||
notifyCollectionObserversOnStart(0);
|
||||
operation.run(this);
|
||||
notifyCollectionObserversOnStop();
|
||||
}//execute()//
|
||||
/**
|
||||
* Gets the count of times the part-of entity has been set to the current value.
|
||||
* @return The counter for setting the part of entity.
|
||||
*/
|
||||
private int getPartOfEntityCounter() {
|
||||
return partOfEntityCounter;
|
||||
}//getPartOfEntityCounter()//
|
||||
/**
|
||||
* Sets the count of times the part-of entity has been set to the current value.
|
||||
* @param partOfEntityCounter The counter for setting the part of entity.
|
||||
*/
|
||||
private void setPartOfEntityCounter(int partOfEntityCounter) {
|
||||
this.partOfEntityCounter = partOfEntityCounter;
|
||||
}//setPartOfEntityCounter()//
|
||||
/**
|
||||
* Gets the entity the collection is part of.
|
||||
* @return The entity that this collection is a part of. This may be null.
|
||||
*/
|
||||
private IEntity getPartOfEntity() {
|
||||
return partOfEntity;
|
||||
}//getPartOfEntity()//
|
||||
/**
|
||||
* Sets the entity the collection is part of.
|
||||
* @param partOfEntity The entity that this collection is a part of. This may be null.
|
||||
*/
|
||||
private void setPartOfEntity(IEntity partOfEntity) {
|
||||
this.partOfEntity = partOfEntity;
|
||||
setEntityMonitor(partOfEntity != null ? partOfEntity.getMonitor() : null);
|
||||
}//setPartOfEntity()//
|
||||
/**
|
||||
* Gets the monitor used to synchronize on this entity.
|
||||
* @return The monitor used by the entity if it is contained by another entity, or null if it is not contained by another entity.
|
||||
*/
|
||||
private Monitor getEntityMonitor() {
|
||||
return entityMonitor;
|
||||
}//getEntityMonitor()//
|
||||
/**
|
||||
* Sets the monitor used to synchronize on this entity.
|
||||
* @param entityMonitor The monitor used by the entity if it is contained by another entity, or null if it is not contained by another entity.
|
||||
*/
|
||||
private void setEntityMonitor(Monitor entityMonitor) {
|
||||
this.entityMonitor = entityMonitor;
|
||||
}//setEntityMonitor()//
|
||||
/**
|
||||
* Gets whether the collection and its collected values are contained by another object.
|
||||
* @return Whether the collected values are part of this collection's referencer.
|
||||
*/
|
||||
protected boolean isPartOf() {
|
||||
return isPartOf;
|
||||
}//isPartOf()//
|
||||
/**
|
||||
* Sets whether the collection and its collected values are contained by another object.
|
||||
* @param isPartOf Whether the collected values are part of this collection's referencer.
|
||||
*/
|
||||
private void isPartOf(boolean isPartOf) {
|
||||
if(/*(!isReflection()) && */(this.isPartOf != isPartOf)) {
|
||||
IIterator iterator = valueIterator();
|
||||
|
||||
this.isPartOf = isPartOf;
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object next = iterator.next();
|
||||
|
||||
if(next instanceof ISupportsContainment) {
|
||||
MetadataService.getSingleton().getTypeMetadata(next.getClass()).getTypeCallbackHandler().setMonitor(next, isPartOf ? getPartOfEntity() : null, false);
|
||||
}//if//
|
||||
}//while//
|
||||
}//if//
|
||||
}//isPartOf()//
|
||||
/**
|
||||
* Sets whether the value is part of the collection's referencer.
|
||||
* @param value The collection value.
|
||||
* @param isAdding Whether the list is adding the value to the collection.
|
||||
*/
|
||||
protected final void setContainment(Object value, boolean isAdding) {
|
||||
if(/*(!isReflection()) && */(isPartOf) && (value != null) && (value instanceof ISupportsContainment)) {
|
||||
MetadataService.getSingleton().getTypeMetadata(value.getClass()).getTypeCallbackHandler().setMonitor(value, isAdding ? getPartOfEntity() : null, false);
|
||||
}//if//
|
||||
}//setContainment()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.clone.ICloneable#cloneObject(com.foundation.metadata.CloneContext, com.foundation.common.MetadataContainer)
|
||||
*/
|
||||
public Object cloneObject(CloneContext context, MetadataContainer metadata) {
|
||||
return TYPE_CALLBACK_HANDLER.clone(this, metadata, context);
|
||||
}//cloneObject()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#clone()
|
||||
*/
|
||||
protected Object clone() {
|
||||
HashMap clone;
|
||||
|
||||
//TODO: We should be using super.clone() so that subclasses can properly override the functionality. To do this we would need to implement clone in the super classes.
|
||||
clone = new HashMap(this);
|
||||
clone.isPartOf = false;
|
||||
clone.partOfEntity = null;
|
||||
clone.partOfEntityCounter = 0;
|
||||
|
||||
return clone;
|
||||
}//clone()//
|
||||
/**
|
||||
* Clones all the cloneable part of references in the collection.
|
||||
* @param metadata The metadata for the clone job.
|
||||
* @param context The context for the clone job.
|
||||
*/
|
||||
protected void clonePartOfReferences(CloneContext context, MetadataContainer metadata) {
|
||||
IIterator iterator = keyIterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object key = iterator.next();
|
||||
Object value = get(key);
|
||||
|
||||
if(value instanceof ISupportsContainment) {
|
||||
Object newValue = context.getClone(value);
|
||||
|
||||
if(newValue == null) {
|
||||
TypeCallbackHandler handler = MetadataService.getSingleton().getTypeMetadata(value.getClass()).getTypeCallbackHandler();
|
||||
|
||||
newValue = handler.clone(value, metadata, context);
|
||||
context.setClone(value, newValue);
|
||||
}//if//
|
||||
|
||||
put(key, newValue);
|
||||
}//if//
|
||||
}//while//
|
||||
}//clonePartOfReferences()//
|
||||
/**
|
||||
* Called prior to cloning to allow lazy data to be initialized as necessary.
|
||||
* @param metadata The metadata for the cloning operation.
|
||||
* @param cloneContext The context for the cloning operation.
|
||||
*/
|
||||
protected void preClone(MetadataContainer metadata, CloneContext cloneContext) {
|
||||
IIterator iterator = keyIterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object key = iterator.next();
|
||||
Object value = get(key);
|
||||
|
||||
if(value instanceof ISupportsContainment) {
|
||||
TypeCallbackHandler handler = MetadataService.getSingleton().getTypeMetadata(value.getClass()).getTypeCallbackHandler();
|
||||
|
||||
handler.preClone(value, metadata, cloneContext);
|
||||
}//if//
|
||||
}//while//
|
||||
}//preClone()//
|
||||
/**
|
||||
* Loads attributes within the given context. The context controls which attributes are loaded from which objects.
|
||||
* @param context The context for the load operation.
|
||||
*/
|
||||
protected void loadAttributes(LoadAttributesContext context) {
|
||||
if(isPartOf()) {
|
||||
IIterator iterator = keyIterator();
|
||||
|
||||
addCollectionObserver(context);
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object key = iterator.next();
|
||||
Object value = get(key);
|
||||
|
||||
if(value instanceof ISupportsContainment) {
|
||||
context.include(value);
|
||||
}//if//
|
||||
}//while//
|
||||
}//if//
|
||||
}//loadAttributes()//
|
||||
/**
|
||||
* Called after the loadAttributes method and after the attributes have been used as needed.
|
||||
* @param context The context for the load operation.
|
||||
*/
|
||||
protected void postLoadAttributes(LoadAttributesContext context) {
|
||||
if(isPartOf()) {
|
||||
removeCollectionObserver(context);
|
||||
}//if//
|
||||
}//postLoadAttributes()//
|
||||
/**
|
||||
* Sets the flag for maintaining weak link back references used to prevent this collection from being GC'd while a collected object is being actively referenced (when the entity that references this collection flags it as part-of and weak).
|
||||
*/
|
||||
protected void setMaintainWeakLinkBackReferences() {
|
||||
if(!maintainWeakLinkBackReferences) {
|
||||
IIterator iterator = valueIterator();
|
||||
|
||||
maintainWeakLinkBackReferences = true;
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object next = iterator.next();
|
||||
|
||||
if(next instanceof ISupportsContainment) {
|
||||
TypeCallbackHandler handler = MetadataService.getSingleton().getTypeMetadata(next.getClass()).getTypeCallbackHandler();
|
||||
|
||||
if(handler != null) {
|
||||
handler.addWeakLinkBackReference(next, this);
|
||||
}//if//
|
||||
}//if//
|
||||
}//while//
|
||||
}//if//
|
||||
}//setMaintainWeakLinkBackReferences()//
|
||||
}//HashMap//
|
||||
752
Foundation/src/com/foundation/util/HashMapAdapter.java
Normal file
752
Foundation/src/com/foundation/util/HashMapAdapter.java
Normal file
@@ -0,0 +1,752 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2009 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.debug.Debug;
|
||||
import com.common.thread.Monitor;
|
||||
import com.common.thread.ThreadService;
|
||||
import com.common.util.*;
|
||||
import com.foundation.attribute.AttributeSupport;
|
||||
import com.foundation.common.BackReferenceNode;
|
||||
import com.foundation.common.IEntity;
|
||||
import com.foundation.common.MetadataContainer;
|
||||
import com.foundation.metadata.CloneContext;
|
||||
import com.foundation.metadata.ISupportsContainment;
|
||||
import com.foundation.metadata.LoadAttributesContext;
|
||||
import com.foundation.metadata.MetadataService;
|
||||
import com.foundation.metadata.TypeCallbackHandler;
|
||||
import com.foundation.util.ListAdapter.Converter;
|
||||
import com.foundation.util.ListAdapter.IFilter;
|
||||
import com.foundation.util.Updater.UpdaterRunnable;
|
||||
|
||||
/**
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* <p>TODO: Add the ability to disconnect the map.</p>
|
||||
* <p>TODO: Add serialization code and test.</p>
|
||||
*/
|
||||
public class HashMapAdapter extends LiteHashMap implements ISupportsContainment, IInlineCollectionObservable {
|
||||
/** An identifier used by the collection observer. */
|
||||
private static final Integer ADD = new Integer(0);
|
||||
/** An identifier used by the collection observer. */
|
||||
private static final Integer REMOVE = new Integer(1);
|
||||
/** An identifier used by the collection observer. */
|
||||
private static final Integer REMOVE_ALL = new Integer(2);
|
||||
|
||||
/** The number of times the part of entity has been set to the same value. */
|
||||
private volatile int partOfEntityCounter = 0;
|
||||
/** A reference to the entity that this collection is a part of. If the collection is not a part of an entity then this will be null. */
|
||||
private volatile IEntity partOfEntity = null;
|
||||
/** Whether this collection is part of another object (logically an integrated component and cannot exist outside that context). */
|
||||
private boolean isPartOf = false;
|
||||
/** The monitor for this collection or null if this map object is to be used as the monitor. Users will synchronize on this monitor prior to accessing the public methods. */
|
||||
private volatile Monitor entityMonitor = null;
|
||||
/** The collection that is supplying this collection with values. */
|
||||
// private IInlineCollectionObservable parent = null;
|
||||
/** The handler used to obtain keys from the collection's values. */
|
||||
private IKeyExtractor keyHandler = null;
|
||||
/** The observer used to listen to changes in the parent. */
|
||||
private CollectionObserver observer = new CollectionObserver();
|
||||
/** A collection of ICollectionObserver instances which will be provided immediate inline change notification. */
|
||||
private LiteList collectionObservers = null;
|
||||
/** The filter used to determine what is added to the adapter. */
|
||||
private transient IFilter filter = null;
|
||||
/** The converter used to convert values added to the adapter. */
|
||||
private transient Converter converter = null;
|
||||
/** Whether back references should be maintained between collected items and the collection to prevent the model referencing this collection from GC'ing the collection while collected items are referenced. */
|
||||
private boolean maintainWeakLinkBackReferences = false;
|
||||
/** The root node in the linked list of back references used when the object is referenced by a collection that is referenced by an entity using the part-of and weak flags. */
|
||||
private BackReferenceNode weakLinkBackReferenceRootNode = null;
|
||||
|
||||
/**
|
||||
* Observes to the attached collection for changes.
|
||||
*/
|
||||
private class CollectionObserver implements IInlineCollectionObserver {
|
||||
/** The changed queued up, interleved with identifiers for ADD, REMOVE, and REMOVE_ALL. */
|
||||
private LiteList queuedChanges = null;
|
||||
|
||||
private class CollectionObserverUpdaterRunnable extends UpdaterRunnable {
|
||||
private Object value;
|
||||
private Integer command;
|
||||
private Monitor monitor;
|
||||
|
||||
public CollectionObserverUpdaterRunnable(Monitor monitor, Integer command, Object value) {
|
||||
this.command = command;
|
||||
this.value = value;
|
||||
this.monitor = monitor;
|
||||
}//CollectionObserverUpdaterRunnable()//
|
||||
public Monitor getMonitor() {
|
||||
return monitor;
|
||||
}//getMonitor()//
|
||||
public void run() {
|
||||
internalProcessCommand(command, value);
|
||||
}//run()//
|
||||
}//CollectionObserverUpdaterRunnable//
|
||||
|
||||
public CollectionObserver() {
|
||||
}//CollectionObserver()//
|
||||
public void valueAdded(final Object value) {
|
||||
if((filter == null) || (filter.include(value))) {
|
||||
if(queuedChanges != null) {
|
||||
queuedChanges.add(ADD);
|
||||
queuedChanges.add(value);
|
||||
}//if//
|
||||
else {
|
||||
//Thread the changes if we are not in a single threaded context (in which case we will presume to be running on the context's thread.//
|
||||
if(getMonitor() != null && !ThreadService.getIsSingleThreadedContext()) {
|
||||
Updater.getSingleton().run(new CollectionObserverUpdaterRunnable(getMonitor(), ADD, value));
|
||||
}//if//
|
||||
else {
|
||||
internalValueAdded(value);
|
||||
}//else//
|
||||
}//else//
|
||||
}//if//
|
||||
}//valueAdded()//
|
||||
public void valueRemoved(final Object value) {
|
||||
if((filter == null) || (filter.include(value))) {
|
||||
if(queuedChanges != null) {
|
||||
queuedChanges.add(REMOVE);
|
||||
queuedChanges.add(value);
|
||||
}//if//
|
||||
else {
|
||||
//Thread the changes if we are not in a single threaded context (in which case we will presume to be running on the context's thread.//
|
||||
if(getMonitor() != null && !ThreadService.getIsSingleThreadedContext()) {
|
||||
Updater.getSingleton().run(new CollectionObserverUpdaterRunnable(getMonitor(), REMOVE, value));
|
||||
}//if//
|
||||
else {
|
||||
internalValueRemoved(value);
|
||||
}//else//
|
||||
}//else//
|
||||
}//if//
|
||||
}//valueRemoved()//
|
||||
public void removingAll() {
|
||||
if(queuedChanges != null) {
|
||||
queuedChanges.add(REMOVE_ALL);
|
||||
queuedChanges.add(null);
|
||||
}//if//
|
||||
else {
|
||||
//Thread the changes if we are not in a single threaded context (in which case we will presume to be running on the context's thread.//
|
||||
if(getMonitor() != null && !ThreadService.getIsSingleThreadedContext()) {
|
||||
Updater.getSingleton().run(new CollectionObserverUpdaterRunnable(getMonitor(), REMOVE_ALL, null));
|
||||
}//if//
|
||||
else {
|
||||
internalRemovingAll();
|
||||
}//else//
|
||||
}//else//
|
||||
}//removingAll()//
|
||||
public void startChanges(int changeCount) {
|
||||
queuedChanges = new LiteList(changeCount > 0 ? changeCount : 100, 1000);
|
||||
}//startChanges()//
|
||||
public void stopChanges() {
|
||||
//Thread the changes if we are not in a single threaded context (in which case we will presume to be running on the context's thread.//
|
||||
if(getMonitor() != null && !ThreadService.getIsSingleThreadedContext()) {
|
||||
Updater.getSingleton().run(new UpdaterRunnable() {
|
||||
public void run() {
|
||||
internalStopChanges();
|
||||
}//run()//
|
||||
public Monitor getMonitor() {
|
||||
return HashMapAdapter.this.getMonitor();
|
||||
}//getMonitor()//
|
||||
});
|
||||
}//if//
|
||||
else {
|
||||
if(queuedChanges != null && queuedChanges.getSize() > 0) {
|
||||
internalStopChanges();
|
||||
}//if//
|
||||
}//else//
|
||||
}//stopChanges()//
|
||||
/**
|
||||
* Proces the queued changes in batch.
|
||||
*/
|
||||
private void internalStopChanges() {
|
||||
if(collectionObservers != null) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).startChanges(queuedChanges.getSize() >> 1);
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
for(int index = 0; index < queuedChanges.getSize(); index ++) {
|
||||
internalProcessCommand((Integer) queuedChanges.get(index++), queuedChanges.get(index));
|
||||
}//for//
|
||||
|
||||
if(collectionObservers != null) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).stopChanges();
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
queuedChanges.removeAll();
|
||||
queuedChanges = null;
|
||||
}//internalStopChanges()//
|
||||
private void internalProcessCommand(Integer command, Object value) {
|
||||
switch(command.intValue()) {
|
||||
case 0: { //ADD
|
||||
internalValueAdded(value);
|
||||
break;
|
||||
}//case//
|
||||
case 1: { //REMOVE
|
||||
internalValueRemoved(value);
|
||||
break;
|
||||
}//case//
|
||||
case 2: { //REMOVING ALL
|
||||
internalRemovingAll();
|
||||
break;
|
||||
}//case//
|
||||
}//switch//
|
||||
}//internalProcessCommand()//
|
||||
private void internalValueAdded(Object value) {
|
||||
Object newValue = value;
|
||||
|
||||
if(converter != null) {
|
||||
newValue = converter.internalAdd(newValue);
|
||||
}//if//
|
||||
|
||||
internalPut(keyHandler.getKey(newValue), newValue);
|
||||
|
||||
if(collectionObservers != null) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).valueAdded(value);
|
||||
}//for//
|
||||
}//if//
|
||||
}//internalValueAdded()//
|
||||
private void internalValueRemoved(Object value) {
|
||||
Object oldValue = value;
|
||||
|
||||
if(converter != null) {
|
||||
oldValue = converter.internalRemove(oldValue);
|
||||
}//if//
|
||||
|
||||
internalRemove(keyHandler.getKey(oldValue));
|
||||
|
||||
if(collectionObservers != null) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).valueRemoved(value);
|
||||
}//for//
|
||||
}//if//
|
||||
}//internalValueRemoved()//
|
||||
private void internalRemovingAll() {
|
||||
if(collectionObservers != null) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).removingAll();
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
if(converter != null) {
|
||||
converter.getConversionMap().removeAll();
|
||||
}//if//
|
||||
|
||||
internalRemoveAll();
|
||||
}//internalRemovingAll()//
|
||||
}//CollectionObserver//
|
||||
|
||||
protected static final TypeCallbackHandler TYPE_CALLBACK_HANDLER = new TypeCallbackHandler() {
|
||||
public Monitor getMonitor(Object instance) {
|
||||
return ((HashMapAdapter) instance).getMonitor();
|
||||
}//getMonitor()//
|
||||
public void setMonitor(Object instance, IEntity parent, boolean isPartOf) {
|
||||
if(parent == null) {
|
||||
if(((HashMapAdapter) instance).getPartOfEntityCounter() != 0) {
|
||||
((HashMapAdapter) instance).setPartOfEntityCounter(((HashMapAdapter) instance).getPartOfEntityCounter() - 1);
|
||||
|
||||
if(((HashMapAdapter) instance).getPartOfEntityCounter() == 0) {
|
||||
((HashMapAdapter) instance).setPartOfEntity(null);
|
||||
((HashMapAdapter) instance).isPartOf(false);
|
||||
}//if//
|
||||
}//if//
|
||||
}//if//
|
||||
else if(((HashMapAdapter) instance).getPartOfEntity() == parent) {
|
||||
((HashMapAdapter) instance).setPartOfEntityCounter(((HashMapAdapter) instance).getPartOfEntityCounter() + 1);
|
||||
}//else if//
|
||||
else if(((HashMapAdapter) instance).getPartOfEntity() != null) {
|
||||
if(((HashMapAdapter) instance).getMonitor() != parent.getMonitor()) {
|
||||
Debug.log(new RuntimeException("Error: Invalid monitor state: A hash map adapter cannot be contained by more than one object or collection."));
|
||||
//TODO: Throw a custom exception and catch it in the code that is setting up the containment.//
|
||||
}//if//
|
||||
}//else if//
|
||||
else {
|
||||
((HashMapAdapter) instance).setPartOfEntityCounter(1);
|
||||
((HashMapAdapter) instance).setPartOfEntity(parent);
|
||||
((HashMapAdapter) instance).isPartOf(isPartOf);
|
||||
}//else//
|
||||
}//setMonitor()//
|
||||
public AttributeSupport getAttributeSupport(Object instance) {
|
||||
return null;
|
||||
}//getAttributeSupport()//
|
||||
public void preClone(Object instance, MetadataContainer metadata, CloneContext cloneContext) {
|
||||
//Does nothing.//
|
||||
}//preClone()//
|
||||
public ISupportsContainment clone(Object instance, MetadataContainer metadata, CloneContext cloneContext) {
|
||||
//TODO: Implement the clone functionality?
|
||||
|
||||
return null;
|
||||
}//clone()//
|
||||
public void loadAttributes(Object instance, LoadAttributesContext context) {
|
||||
//Does nothing since it is dependant on another collection.//
|
||||
}//loadAttributes()//
|
||||
public void postLoadAttributes(Object instance, LoadAttributesContext context) {
|
||||
//Does nothing since it is dependant on another collection.//
|
||||
}//postLoadAttributes()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#getIsVirtualObjectChanged(java.lang.Object)
|
||||
*/
|
||||
public boolean getIsVirtualObjectChanged(Object instance) {
|
||||
//Always false since the adapter is dependant on another collection and cannot be modified except through the dependant collection.//
|
||||
return false;
|
||||
}//getIsVirtualObjectChanged()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#resetVirtualObjectChangeFlags(java.lang.Object)
|
||||
*/
|
||||
public void resetVirtualObjectChangeFlags(Object instance) {
|
||||
//Does nothing since it is dependant on another collection.//
|
||||
}//resetVirtualObjectChangeFlags()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#reverseVirtualObjectChanges(java.lang.Object)
|
||||
*/
|
||||
public void reverseVirtualObjectChanges(Object instance) {
|
||||
//Does nothing since it is dependant on another collection.//
|
||||
}//reverseVirtualObjectChanges()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#getIsVirtualObjectAltered(java.lang.Object)
|
||||
*/
|
||||
public boolean getIsVirtualObjectAltered(Object instance) {
|
||||
//Always false since the adapter is dependant on another collection and cannot be modified except through the dependant collection.//
|
||||
return false;
|
||||
}//getIsVirtualObjectAltered()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#resetVirtualObjectAlteredFlags(java.lang.Object)
|
||||
*/
|
||||
public void resetVirtualObjectAlteredFlags(Object instance) {
|
||||
//Does nothing.//
|
||||
}//resetVirtualObjectAlteredFlags()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#setMaintainWeakLinkBackReferences(java.lang.Object)
|
||||
*/
|
||||
public void setMaintainWeakLinkBackReferences(Object instance) {
|
||||
((HashMapAdapter) instance).setMaintainWeakLinkBackReferences();
|
||||
}//setMaintainWeakLinkBackReferences()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#addWeakLinkBackReference(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public void addWeakLinkBackReference(Object instance, Object collection) {
|
||||
((HashMapAdapter) instance).weakLinkBackReferenceRootNode = new BackReferenceNode(collection, ((HashMapAdapter) instance).weakLinkBackReferenceRootNode);
|
||||
}//addWeakLinkBackReference()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#removeWeakLinkBackReference(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public void removeWeakLinkBackReference(Object instance, Object collection) {
|
||||
BackReferenceNode previous = null;
|
||||
BackReferenceNode next = ((HashMapAdapter) instance).weakLinkBackReferenceRootNode;
|
||||
|
||||
while(next != null && next.getReference() != collection) {
|
||||
previous = next;
|
||||
next = next.getNext();
|
||||
}//while//
|
||||
|
||||
if(next != null) {
|
||||
if(previous != null) {
|
||||
previous.setNext(next.getNext());
|
||||
}//if//
|
||||
else {
|
||||
((HashMapAdapter) instance).weakLinkBackReferenceRootNode = next.getNext();
|
||||
}//else//
|
||||
}//if//
|
||||
}//removeWeakLinkBackReference()//
|
||||
};//TypeCallbackHandler//
|
||||
|
||||
static {
|
||||
MetadataService.getSingleton().setTypeCallbackHandler(HashMapAdapter.class, TYPE_CALLBACK_HANDLER);
|
||||
}//static//
|
||||
/**
|
||||
* HashMapAdapter constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
*/
|
||||
protected HashMapAdapter() {
|
||||
super();
|
||||
}//HashMapAdapter()//
|
||||
/**
|
||||
* HashMapAdapter constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param keyHandler The handler that will retreive each collection value's key.
|
||||
*/
|
||||
public HashMapAdapter(IInlineCollectionObservable parent, IKeyExtractor keyHandler) {
|
||||
super();
|
||||
|
||||
initialize(parent, keyHandler);
|
||||
}//HashMapAdapter()//
|
||||
/**
|
||||
* HashMapAdapter constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param keyHandler The handler that will retreive each collection value's key.
|
||||
* @param initialCapacity
|
||||
*/
|
||||
public HashMapAdapter(IInlineCollectionObservable parent, IKeyExtractor keyHandler, int initialCapacity) {
|
||||
super(initialCapacity);
|
||||
|
||||
initialize(parent, keyHandler);
|
||||
}//HashMapAdapter()//
|
||||
/**
|
||||
* HashMapAdapter constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param keyHandler The handler that will retreive each collection value's key.
|
||||
* @param initialCapacity
|
||||
* @param loadFactor
|
||||
*/
|
||||
public HashMapAdapter(IInlineCollectionObservable parent, IKeyExtractor keyHandler, int initialCapacity, float loadFactor) {
|
||||
super(initialCapacity, loadFactor);
|
||||
|
||||
initialize(parent, keyHandler);
|
||||
}//HashMapAdapter()//
|
||||
/**
|
||||
* HashMapAdapter constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param keyHandler The handler that will retreive each collection value's key.
|
||||
* @param initialCapacity
|
||||
* @param loadFactor
|
||||
* @param keyComparator
|
||||
* @param valueComparator
|
||||
*/
|
||||
public HashMapAdapter(IInlineCollectionObservable parent, IKeyExtractor keyHandler, int initialCapacity, float loadFactor, com.common.comparison.IComparator keyComparator, com.common.comparison.IComparator valueComparator) {
|
||||
super(initialCapacity, loadFactor, keyComparator, valueComparator);
|
||||
|
||||
initialize(parent, keyHandler);
|
||||
}//HashMapAdapter()//
|
||||
/**
|
||||
* HashMapAdapter constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param keyHandler The handler that will retreive each collection value's key.
|
||||
* @param initialCapacity
|
||||
* @param keyComparator
|
||||
* @param valueComparator
|
||||
*/
|
||||
public HashMapAdapter(IInlineCollectionObservable parent, IKeyExtractor keyHandler, int initialCapacity, com.common.comparison.IComparator keyComparator, com.common.comparison.IComparator valueComparator) {
|
||||
super(initialCapacity, keyComparator, valueComparator);
|
||||
|
||||
initialize(parent, keyHandler);
|
||||
}//HashMapAdapter()//
|
||||
/**
|
||||
* HashMapAdapter constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param keyHandler The handler that will retreive each collection value's key.
|
||||
* @param keyComparator
|
||||
* @param valueComparator
|
||||
*/
|
||||
public HashMapAdapter(IInlineCollectionObservable parent, IKeyExtractor keyHandler, com.common.comparison.IComparator keyComparator, com.common.comparison.IComparator valueComparator) {
|
||||
super(keyComparator, valueComparator);
|
||||
|
||||
initialize(parent, keyHandler);
|
||||
}//HashMapAdapter()//
|
||||
/**
|
||||
* HashMapAdapter constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param keyHandler The handler that will retreive each collection value's key.
|
||||
* @param filter A filter used to determine whether values should be included in this filtered collection.
|
||||
* @param converter A converter used to convert the external value into the internal value.
|
||||
*/
|
||||
public HashMapAdapter(IInlineCollectionObservable parent, IKeyExtractor keyHandler, IFilter filter, Converter converter) {
|
||||
super();
|
||||
|
||||
this.filter = filter;
|
||||
this.converter = converter;
|
||||
initialize(parent, keyHandler);
|
||||
}//HashMapAdapter()//
|
||||
/**
|
||||
* HashMapAdapter constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param keyHandler The handler that will retreive each collection value's key.
|
||||
* @param filter A filter used to determine whether values should be included in this filtered collection.
|
||||
* @param converter A converter used to convert the external value into the internal value.
|
||||
* @param initialCapacity
|
||||
*/
|
||||
public HashMapAdapter(IInlineCollectionObservable parent, IKeyExtractor keyHandler, IFilter filter, Converter converter, int initialCapacity) {
|
||||
super(initialCapacity);
|
||||
|
||||
this.filter = filter;
|
||||
this.converter = converter;
|
||||
initialize(parent, keyHandler);
|
||||
}//HashMapAdapter()//
|
||||
/**
|
||||
* HashMapAdapter constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param keyHandler The handler that will retreive each collection value's key.
|
||||
* @param filter A filter used to determine whether values should be included in this filtered collection.
|
||||
* @param converter A converter used to convert the external value into the internal value.
|
||||
* @param initialCapacity
|
||||
* @param loadFactor
|
||||
*/
|
||||
public HashMapAdapter(IInlineCollectionObservable parent, IKeyExtractor keyHandler, IFilter filter, Converter converter, int initialCapacity, float loadFactor) {
|
||||
super(initialCapacity, loadFactor);
|
||||
|
||||
this.filter = filter;
|
||||
this.converter = converter;
|
||||
initialize(parent, keyHandler);
|
||||
}//HashMapAdapter()//
|
||||
/**
|
||||
* HashMapAdapter constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param keyHandler The handler that will retreive each collection value's key.
|
||||
* @param filter A filter used to determine whether values should be included in this filtered collection.
|
||||
* @param converter A converter used to convert the external value into the internal value.
|
||||
* @param initialCapacity
|
||||
* @param loadFactor
|
||||
* @param keyComparator
|
||||
* @param valueComparator
|
||||
*/
|
||||
public HashMapAdapter(IInlineCollectionObservable parent, IKeyExtractor keyHandler, IFilter filter, Converter converter, int initialCapacity, float loadFactor, com.common.comparison.IComparator keyComparator, com.common.comparison.IComparator valueComparator) {
|
||||
super(initialCapacity, loadFactor, keyComparator, valueComparator);
|
||||
|
||||
this.filter = filter;
|
||||
this.converter = converter;
|
||||
initialize(parent, keyHandler);
|
||||
}//HashMapAdapter()//
|
||||
/**
|
||||
* HashMapAdapter constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param keyHandler The handler that will retreive each collection value's key.
|
||||
* @param filter A filter used to determine whether values should be included in this filtered collection.
|
||||
* @param converter A converter used to convert the external value into the internal value.
|
||||
* @param initialCapacity
|
||||
* @param keyComparator
|
||||
* @param valueComparator
|
||||
*/
|
||||
public HashMapAdapter(IInlineCollectionObservable parent, IKeyExtractor keyHandler, IFilter filter, Converter converter, int initialCapacity, com.common.comparison.IComparator keyComparator, com.common.comparison.IComparator valueComparator) {
|
||||
super(initialCapacity, keyComparator, valueComparator);
|
||||
|
||||
this.filter = filter;
|
||||
this.converter = converter;
|
||||
initialize(parent, keyHandler);
|
||||
}//HashMapAdapter()//
|
||||
/**
|
||||
* HashMapAdapter constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param keyHandler The handler that will retreive each collection value's key.
|
||||
* @param filter A filter used to determine whether values should be included in this filtered collection.
|
||||
* @param converter A converter used to convert the external value into the internal value.
|
||||
* @param keyComparator
|
||||
* @param valueComparator
|
||||
*/
|
||||
public HashMapAdapter(IInlineCollectionObservable parent, IKeyExtractor keyHandler, IFilter filter, Converter converter, com.common.comparison.IComparator keyComparator, com.common.comparison.IComparator valueComparator) {
|
||||
super(keyComparator, valueComparator);
|
||||
|
||||
this.filter = filter;
|
||||
this.converter = converter;
|
||||
initialize(parent, keyHandler);
|
||||
}//HashMapAdapter()//
|
||||
/**
|
||||
* TODO: Implement?
|
||||
* @return
|
||||
* @throws CloneNotSupportedException
|
||||
*/
|
||||
protected Object clone() throws CloneNotSupportedException {
|
||||
return super.clone();
|
||||
}//clone()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.clone.ICloneable#cloneObject(com.foundation.metadata.CloneContext, com.foundation.common.MetadataContainer)
|
||||
*/
|
||||
public Object cloneObject(CloneContext context, MetadataContainer metadata) {
|
||||
//TODO: Implement?
|
||||
return null;
|
||||
}//cloneObject()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.ISupportsContainment#getMonitor()
|
||||
*/
|
||||
public Monitor getMonitor() {
|
||||
Monitor monitor = getEntityMonitor();
|
||||
|
||||
if((monitor != null) && (monitor.getSupported() instanceof ISupportsContainment) && (monitor.getSupported() != this)) {
|
||||
monitor = ((ISupportsContainment) monitor.getSupported()).getMonitor();
|
||||
}//if//
|
||||
|
||||
return monitor;
|
||||
}//getMonitor()//
|
||||
/**
|
||||
* Gets the monitor used to synchronize on this entity.
|
||||
* @return The monitor used by the entity if it is contained by another entity, or null if it is not contained by another entity.
|
||||
*/
|
||||
private Monitor getEntityMonitor() {
|
||||
return entityMonitor;
|
||||
}//getEntityMonitor()//
|
||||
/**
|
||||
* Sets the monitor used to synchronize on this entity.
|
||||
* @param entityMonitor The monitor used by the entity if it is contained by another entity, or null if it is not contained by another entity.
|
||||
*/
|
||||
private void setEntityMonitor(Monitor entityMonitor) {
|
||||
this.entityMonitor = entityMonitor;
|
||||
}//setEntityMonitor()//
|
||||
/**
|
||||
* Gets whether the collection and its collected values are contained by another object.
|
||||
* @return Whether the collected values are part of this collection's referencer.
|
||||
*/
|
||||
protected boolean isPartOf() {
|
||||
return isPartOf;
|
||||
}//isPartOf()//
|
||||
/**
|
||||
* Sets whether the collection and its collected values are contained by another object.
|
||||
* @param isPartOf Whether the collected values are part of this collection's referencer.
|
||||
*/
|
||||
private void isPartOf(boolean isPartOf) {
|
||||
if(/*(!isReflection()) && */(this.isPartOf != isPartOf)) {
|
||||
IIterator iterator = valueIterator();
|
||||
|
||||
this.isPartOf = isPartOf;
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object next = iterator.next();
|
||||
|
||||
if(next instanceof ISupportsContainment) {
|
||||
MetadataService.getSingleton().getTypeMetadata(next.getClass()).getTypeCallbackHandler().setMonitor(next, isPartOf ? getPartOfEntity() : null, false);
|
||||
}//if//
|
||||
}//while//
|
||||
}//if//
|
||||
}//isPartOf()//
|
||||
/**
|
||||
* Gets the count of times the part-of entity has been set to the current value.
|
||||
* @return The counter for setting the part of entity.
|
||||
*/
|
||||
private int getPartOfEntityCounter() {
|
||||
return partOfEntityCounter;
|
||||
}//getPartOfEntityCounter()//
|
||||
/**
|
||||
* Sets the count of times the part-of entity has been set to the current value.
|
||||
* @param partOfEntityCounter The counter for setting the part of entity.
|
||||
*/
|
||||
private void setPartOfEntityCounter(int partOfEntityCounter) {
|
||||
this.partOfEntityCounter = partOfEntityCounter;
|
||||
}//setPartOfEntityCounter()//
|
||||
/**
|
||||
* Gets the entity the collection is part of.
|
||||
* @return The entity that this collection is a part of. This may be null.
|
||||
*/
|
||||
private IEntity getPartOfEntity() {
|
||||
return partOfEntity;
|
||||
}//getPartOfEntity()//
|
||||
/**
|
||||
* Sets the entity the collection is part of.
|
||||
* @param partOfEntity The entity that this collection is a part of. This may be null.
|
||||
*/
|
||||
private void setPartOfEntity(IEntity partOfEntity) {
|
||||
this.partOfEntity = partOfEntity;
|
||||
setEntityMonitor(partOfEntity != null ? partOfEntity.getMonitor() : null);
|
||||
}//setPartOfEntity()//
|
||||
/**
|
||||
* Initializes the read only map.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param keyHandler The handler that will retreive each collection value's key.
|
||||
*/
|
||||
protected void initialize(IInlineCollectionObservable parent, IKeyExtractor keyHandler) {
|
||||
// this.parent = parent;
|
||||
this.keyHandler = keyHandler;
|
||||
//Add this object as a listener on the adaptable collection. The collection will notify us of all existing values.//
|
||||
parent.addCollectionObserver(observer);
|
||||
}//initialize()//
|
||||
/**
|
||||
* Places a key/value pair in the map. The value can be retrieved later with the given key.
|
||||
* @param key The key that will be used to map the value.
|
||||
* @param value The value stored in map.
|
||||
* @return The value previously associated with the key.
|
||||
*/
|
||||
protected void internalPut(Object key, Object value) {
|
||||
super.put(key, value);
|
||||
}//internalPut()//
|
||||
/**
|
||||
* Removes a key/value pair from the map.
|
||||
* @param key The key that should be removed (with its' value) from the map.
|
||||
* @return Will be the value removed from map. A <code>null</code> value is returned if the key was not found.
|
||||
*/
|
||||
protected void internalRemove(Object key) {
|
||||
super.remove(key);
|
||||
}//internalRemove()//
|
||||
/**
|
||||
* Removes all key/value pairs from the map.
|
||||
* @return Will be <code>true</code> if the method was successful.
|
||||
*/
|
||||
protected void internalRemoveAll() {
|
||||
super.removeAll();
|
||||
}//internalRemoveAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.util.LiteHashMap#put(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public Object put(Object key, Object value) {
|
||||
throw new com.common.exception.MethodNotSupportedException("A read only map cannot accept new values.");
|
||||
}//put()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.util.LiteHashMap#remove(java.lang.Object)
|
||||
*/
|
||||
public Object remove(Object key) {
|
||||
throw new com.common.exception.MethodNotSupportedException("A read only map cannot remove values.");
|
||||
}//remove()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.util.LiteHashMap#removeAll()
|
||||
*/
|
||||
public void removeAll() {
|
||||
throw new com.common.exception.MethodNotSupportedException("A read only map cannot remove values.");
|
||||
}//removeAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.IInlineCollectionObservable#addCollectionObserver(com.foundation.util.IInlineCollectionObserver)
|
||||
*/
|
||||
public void addCollectionObserver(IInlineCollectionObserver observer) {
|
||||
if(collectionObservers == null) {
|
||||
collectionObservers = new LiteList(2, 4);
|
||||
}//if//
|
||||
|
||||
collectionObservers.add(observer);
|
||||
observer.startChanges(getSize());
|
||||
|
||||
//Pass all existing values to the observer.//
|
||||
for(IIterator iterator = valueIterator(); iterator.hasNext();) {
|
||||
observer.valueAdded(iterator.next());
|
||||
}//for//
|
||||
|
||||
observer.stopChanges();
|
||||
}//addCollectionObserver()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.IInlineCollectionObservable#removeCollectionObserver(com.foundation.util.IInlineCollectionObserver)
|
||||
*/
|
||||
public void removeCollectionObserver(IInlineCollectionObserver observer) {
|
||||
collectionObservers.remove(observer);
|
||||
}//removeCollectionObserver()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.IInlineCollectionObservable#getCollection()
|
||||
*/
|
||||
public ICollection getCollection() {
|
||||
return new LiteList(this);
|
||||
}//getCollection()//
|
||||
/**
|
||||
* Sets the flag for maintaining weak link back references used to prevent this collection from being GC'd while a collected object is being actively referenced (when the entity that references this collection flags it as part-of and weak).
|
||||
*/
|
||||
protected void setMaintainWeakLinkBackReferences() {
|
||||
if(!maintainWeakLinkBackReferences) {
|
||||
IIterator iterator = valueIterator();
|
||||
|
||||
maintainWeakLinkBackReferences = true;
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object next = iterator.next();
|
||||
|
||||
if(next instanceof ISupportsContainment) {
|
||||
TypeCallbackHandler handler = MetadataService.getSingleton().getTypeMetadata(next.getClass()).getTypeCallbackHandler();
|
||||
|
||||
if(handler != null) {
|
||||
handler.addWeakLinkBackReference(next, this);
|
||||
}//if//
|
||||
}//if//
|
||||
}//while//
|
||||
}//if//
|
||||
}//setMaintainWeakLinkBackReferences()//
|
||||
}//HashMapAdapter//
|
||||
96
Foundation/src/com/foundation/util/HashSet.java
Normal file
96
Foundation/src/com/foundation/util/HashSet.java
Normal file
@@ -0,0 +1,96 @@
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.comparison.IComparator;
|
||||
import com.common.util.ICollection;
|
||||
|
||||
/**
|
||||
* Just a place holder to prevent older code from breaking.
|
||||
* @deprecated Use ManagedHashSet instead.
|
||||
*/
|
||||
public class HashSet extends ManagedHashSet {
|
||||
|
||||
/**
|
||||
* HashSet constructor.
|
||||
*/
|
||||
public HashSet() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet constructor.
|
||||
* @param values
|
||||
* @param locateComparator
|
||||
* @param style
|
||||
*/
|
||||
public HashSet(ICollection values, IComparator locateComparator, int style) {
|
||||
super(values, locateComparator, style);
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet constructor.
|
||||
* @param values
|
||||
* @param initialCapacity
|
||||
* @param loadFactor
|
||||
* @param locateComparator
|
||||
* @param style
|
||||
*/
|
||||
public HashSet(ICollection values, int initialCapacity, float loadFactor, IComparator locateComparator, int style) {
|
||||
super(values, initialCapacity, loadFactor, locateComparator, style);
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet constructor.
|
||||
* @param values
|
||||
*/
|
||||
public HashSet(ICollection values) {
|
||||
super(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet constructor.
|
||||
* @param initialCapacity
|
||||
* @param loadFactor
|
||||
* @param locateComparator
|
||||
* @param style
|
||||
*/
|
||||
public HashSet(int initialCapacity, float loadFactor, IComparator locateComparator, int style) {
|
||||
super(initialCapacity, loadFactor, locateComparator, style);
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet constructor.
|
||||
* @param initialCapacity
|
||||
*/
|
||||
public HashSet(int initialCapacity) {
|
||||
super(initialCapacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet constructor.
|
||||
* @param original
|
||||
*/
|
||||
public HashSet(ManagedHashSet original) {
|
||||
super(original);
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet constructor.
|
||||
* @param values
|
||||
* @param initialCapacity
|
||||
* @param loadFactor
|
||||
* @param locateComparator
|
||||
* @param style
|
||||
*/
|
||||
public HashSet(Object[] values, int initialCapacity, float loadFactor, IComparator locateComparator, int style) {
|
||||
super(values, initialCapacity, loadFactor, locateComparator, style);
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet constructor.
|
||||
* @param values
|
||||
*/
|
||||
public HashSet(Object[] values) {
|
||||
super(values);
|
||||
}
|
||||
|
||||
}
|
||||
856
Foundation/src/com/foundation/util/HashSetAdapter.java
Normal file
856
Foundation/src/com/foundation/util/HashSetAdapter.java
Normal file
@@ -0,0 +1,856 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2009 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.debug.*;
|
||||
import com.common.exception.*;
|
||||
import com.common.thread.Monitor;
|
||||
import com.common.thread.ThreadService;
|
||||
import com.common.util.ICollection;
|
||||
import com.common.util.IIterator;
|
||||
import com.common.util.LiteHashSet;
|
||||
import com.common.util.LiteList;
|
||||
import com.common.comparison.*;
|
||||
import com.foundation.attribute.AttributeSupport;
|
||||
import com.foundation.common.BackReferenceNode;
|
||||
import com.foundation.common.IEntity;
|
||||
import com.foundation.common.MetadataContainer;
|
||||
import com.foundation.metadata.CloneContext;
|
||||
import com.foundation.metadata.ISupportsContainment;
|
||||
import com.foundation.metadata.LoadAttributesContext;
|
||||
import com.foundation.metadata.MetadataService;
|
||||
import com.foundation.metadata.TypeCallbackHandler;
|
||||
import com.foundation.util.ListAdapter.Converter;
|
||||
import com.foundation.util.ListAdapter.IFilter;
|
||||
import com.foundation.util.Updater.UpdaterRunnable;
|
||||
|
||||
/**
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* <p>TODO: Add the ability to disconnect the map.</p>
|
||||
* <p>TODO: Add serialization code and test.</p>
|
||||
*/
|
||||
public class HashSetAdapter extends LiteHashSet implements ISupportsContainment, IInlineCollectionObservable {
|
||||
protected static final int CHANGE_TYPE_ADD = 0;
|
||||
protected static final int CHANGE_TYPE_REMOVE = 1;
|
||||
protected static final int CHANGE_TYPE_REMOVE_ALL = 2;
|
||||
protected static final int CHANGE_TYPE_START_CHANGES = 3;
|
||||
protected static final int CHANGE_TYPE_STOP_CHANGES = 4;
|
||||
|
||||
/** An identifier used by the collection observer. */
|
||||
private static final Integer ADD = new Integer(0);
|
||||
/** An identifier used by the collection observer. */
|
||||
private static final Integer REMOVE = new Integer(1);
|
||||
/** An identifier used by the collection observer. */
|
||||
private static final Integer REMOVE_ALL = new Integer(2);
|
||||
|
||||
protected static final TypeCallbackHandler TYPE_CALLBACK_HANDLER = new TypeCallbackHandler() {
|
||||
public Monitor getMonitor(Object instance) {
|
||||
return ((ManagedCollection) instance).getMonitor();
|
||||
}//getMonitor()//
|
||||
public void setMonitor(Object instance, IEntity parent, boolean isPartOf) {
|
||||
if(parent == null) {
|
||||
if(((HashSetAdapter) instance).getPartOfEntityCounter() != 0) {
|
||||
((HashSetAdapter) instance).setPartOfEntityCounter(((HashSetAdapter) instance).getPartOfEntityCounter() - 1);
|
||||
|
||||
if(((HashSetAdapter) instance).getPartOfEntityCounter() == 0) {
|
||||
((HashSetAdapter) instance).setPartOfEntity(null);
|
||||
((HashSetAdapter) instance).isPartOf(false);
|
||||
}//if//
|
||||
}//if//
|
||||
}//if//
|
||||
else if(((HashSetAdapter) instance).getPartOfEntity() == parent) {
|
||||
((HashSetAdapter) instance).setPartOfEntityCounter(((HashSetAdapter) instance).getPartOfEntityCounter() + 1);
|
||||
}//else if//
|
||||
else if(((HashSetAdapter) instance).getPartOfEntity() != null) {
|
||||
if(((HashSetAdapter) instance).getMonitor() != parent.getMonitor()) {
|
||||
Debug.log(new RuntimeException("Error: Invalid monitor state: A managed hash map cannot be contained by more than one object or collection."));
|
||||
//TODO: Throw a custom exception and catch it in the code that is setting up the containment.//
|
||||
}//if//
|
||||
}//else if//
|
||||
else {
|
||||
((HashSetAdapter) instance).setPartOfEntityCounter(1);
|
||||
((HashSetAdapter) instance).setPartOfEntity(parent);
|
||||
((HashSetAdapter) instance).isPartOf(isPartOf);
|
||||
}//else//
|
||||
}//setMonitor()//
|
||||
public AttributeSupport getAttributeSupport(Object instance) {
|
||||
return null;
|
||||
}//getAttributeSupport()//
|
||||
public void preClone(Object instance, MetadataContainer metadata, CloneContext cloneContext) {
|
||||
//Does nothing.//
|
||||
}//preClone()//
|
||||
public ISupportsContainment clone(Object instance, MetadataContainer metadata, CloneContext cloneContext) {
|
||||
//TODO: Implement the clone functionality?
|
||||
|
||||
return null;
|
||||
}//clone()//
|
||||
public void loadAttributes(Object instance, LoadAttributesContext context) {
|
||||
//Does nothing since it is dependant on another collection.//
|
||||
}//loadAttributes()//
|
||||
public void postLoadAttributes(Object instance, LoadAttributesContext context) {
|
||||
//Does nothing since it is dependant on another collection.//
|
||||
}//postLoadAttributes()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#getIsVirtualObjectChanged(java.lang.Object)
|
||||
*/
|
||||
public boolean getIsVirtualObjectChanged(Object instance) {
|
||||
//Always false since the adapter is dependant on another collection and cannot be modified except through the dependant collection.//
|
||||
return false;
|
||||
}//getIsVirtualObjectChanged()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#resetVirtualObjectChangeFlags(java.lang.Object)
|
||||
*/
|
||||
public void resetVirtualObjectChangeFlags(Object instance) {
|
||||
//Does nothing since it is dependant on another collection.//
|
||||
}//resetVirtualObjectChangeFlags()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#reverseVirtualObjectChanges(java.lang.Object)
|
||||
*/
|
||||
public void reverseVirtualObjectChanges(Object instance) {
|
||||
//Does nothing since it is dependant on another collection.//
|
||||
}//reverseVirtualObjectChanges()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#getIsVirtualObjectAltered(java.lang.Object)
|
||||
*/
|
||||
public boolean getIsVirtualObjectAltered(Object instance) {
|
||||
//Always false since the adapter is dependant on another collection and cannot be modified except through the dependant collection.//
|
||||
return false;
|
||||
}//getIsVirtualObjectAltered()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#resetVirtualObjectAlteredFlags(java.lang.Object)
|
||||
*/
|
||||
public void resetVirtualObjectAlteredFlags(Object instance) {
|
||||
//Does nothing.//
|
||||
}//resetVirtualObjectAlteredFlags()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#setMaintainWeakLinkBackReferences(java.lang.Object)
|
||||
*/
|
||||
public void setMaintainWeakLinkBackReferences(Object instance) {
|
||||
((HashSetAdapter) instance).setMaintainWeakLinkBackReferences();
|
||||
}//setMaintainWeakLinkBackReferences()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#addWeakLinkBackReference(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public void addWeakLinkBackReference(Object instance, Object collection) {
|
||||
((HashSetAdapter) instance).weakLinkBackReferenceRootNode = new BackReferenceNode(collection, ((HashSetAdapter) instance).weakLinkBackReferenceRootNode);
|
||||
}//addWeakLinkBackReference()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.TypeCallbackHandler#removeWeakLinkBackReference(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public void removeWeakLinkBackReference(Object instance, Object collection) {
|
||||
BackReferenceNode previous = null;
|
||||
BackReferenceNode next = ((HashSetAdapter) instance).weakLinkBackReferenceRootNode;
|
||||
|
||||
while(next != null && next.getReference() != collection) {
|
||||
previous = next;
|
||||
next = next.getNext();
|
||||
}//while//
|
||||
|
||||
if(next != null) {
|
||||
if(previous != null) {
|
||||
previous.setNext(next.getNext());
|
||||
}//if//
|
||||
else {
|
||||
((HashSetAdapter) instance).weakLinkBackReferenceRootNode = next.getNext();
|
||||
}//else//
|
||||
}//if//
|
||||
}//removeWeakLinkBackReference()//
|
||||
};//TypeCallbackHandler//
|
||||
|
||||
static {
|
||||
MetadataService.getSingleton().setTypeCallbackHandler(HashSetAdapter.class, TYPE_CALLBACK_HANDLER);
|
||||
}//static//
|
||||
|
||||
/**
|
||||
* Defines a collection operation that may make multiple changes to the collection.
|
||||
* The collection operation makes making changes more efficient since only one event is fired for a set of changes.
|
||||
*/
|
||||
public interface ICollectionOperation {
|
||||
public void run(HashSetAdapter collection);
|
||||
}//ICollectionOperation//
|
||||
|
||||
/** A collection of ICollectionObserver instances which will be provided immediate inline change notification. */
|
||||
private LiteList collectionObservers = null;
|
||||
/** The number of times the part of entity has been set to the same value. */
|
||||
private volatile int partOfEntityCounter = 0;
|
||||
/** A reference to the entity that this collection is a part of. If the collection is not a part of an entity then this will be null. */
|
||||
private volatile IEntity partOfEntity = null;
|
||||
/** The monitor for this collection or null if this map object is to be used as the monitor. Users will synchronize on this monitor prior to accessing the public methods. */
|
||||
private volatile Monitor entityMonitor = null;
|
||||
/** TODO: It would be nice if this hashmap had the monitor built in instead of creating a separate object. This will require changing the hierarchy which is probably best anyways to allow for reflectable hashmaps and advanced behavior. */
|
||||
// private final Monitor localMonitor = new Monitor(this);
|
||||
/** Whether this collection is part of another object (logically an integrated component and cannot exist outside that context). */
|
||||
private boolean isPartOf = false;
|
||||
/** A flag that is used to track whether the object may have been altered. This is intended to be less accuate than hasChanged and the added and removed values collections. The intended use is to improve view validation by only validating objects that may have been altered. */
|
||||
private boolean isAltered = false;
|
||||
/** Whether back references should be maintained between collected items and the collection to prevent the model referencing this collection from GC'ing the collection while collected items are referenced. */
|
||||
private boolean maintainWeakLinkBackReferences = false;
|
||||
/** The root node in the linked list of back references used when the object is referenced by a collection that is referenced by an entity using the part-of and weak flags. */
|
||||
private BackReferenceNode weakLinkBackReferenceRootNode = null;
|
||||
/** The observer used to listen to changes in the parent. */
|
||||
private CollectionObserver observer = new CollectionObserver();
|
||||
/** The filter used to determine what is added to the adapter. */
|
||||
private transient IFilter filter = null;
|
||||
/** The converter used to convert values added to the adapter. */
|
||||
private transient Converter converter = null;
|
||||
|
||||
/**
|
||||
* Observes to the attached collection for changes.
|
||||
*/
|
||||
private class CollectionObserver implements IInlineCollectionObserver {
|
||||
/** The changed queued up, interleved with identifiers for ADD, REMOVE, and REMOVE_ALL. */
|
||||
private LiteList queuedChanges = null;
|
||||
|
||||
private class CollectionObserverUpdaterRunnable extends UpdaterRunnable {
|
||||
private Object value;
|
||||
private Integer command;
|
||||
private Monitor monitor;
|
||||
|
||||
public CollectionObserverUpdaterRunnable(Monitor monitor, Integer command, Object value) {
|
||||
this.command = command;
|
||||
this.value = value;
|
||||
this.monitor = monitor;
|
||||
}//CollectionObserverUpdaterRunnable()//
|
||||
public Monitor getMonitor() {
|
||||
return monitor;
|
||||
}//getMonitor()//
|
||||
public void run() {
|
||||
internalProcessCommand(command, value);
|
||||
}//run()//
|
||||
}//CollectionObserverUpdaterRunnable//
|
||||
|
||||
public CollectionObserver() {
|
||||
}//CollectionObserver()//
|
||||
public void valueAdded(final Object value) {
|
||||
if((filter == null) || (filter.include(value))) {
|
||||
if(queuedChanges != null) {
|
||||
queuedChanges.add(ADD);
|
||||
queuedChanges.add(value);
|
||||
}//if//
|
||||
else {
|
||||
//Thread the changes if we are not in a single threaded context (in which case we will presume to be running on the context's thread.//
|
||||
if(getMonitor() != null && !ThreadService.getIsSingleThreadedContext()) {
|
||||
Updater.getSingleton().run(new CollectionObserverUpdaterRunnable(getMonitor(), ADD, value));
|
||||
}//if//
|
||||
else {
|
||||
internalValueAdded(value);
|
||||
}//else//
|
||||
}//else//
|
||||
}//if//
|
||||
}//valueAdded()//
|
||||
public void valueRemoved(final Object value) {
|
||||
if((filter == null) || (filter.include(value))) {
|
||||
if(queuedChanges != null) {
|
||||
queuedChanges.add(REMOVE);
|
||||
queuedChanges.add(value);
|
||||
}//if//
|
||||
else {
|
||||
//Thread the changes if we are not in a single threaded context (in which case we will presume to be running on the context's thread.//
|
||||
if(getMonitor() != null && !ThreadService.getIsSingleThreadedContext()) {
|
||||
Updater.getSingleton().run(new CollectionObserverUpdaterRunnable(getMonitor(), REMOVE, value));
|
||||
}//if//
|
||||
else {
|
||||
internalValueRemoved(value);
|
||||
}//else//
|
||||
}//else//
|
||||
}//if//
|
||||
}//valueRemoved()//
|
||||
public void removingAll() {
|
||||
if(queuedChanges != null) {
|
||||
queuedChanges.add(REMOVE_ALL);
|
||||
queuedChanges.add(null);
|
||||
}//if//
|
||||
else {
|
||||
//Thread the changes if we are not in a single threaded context (in which case we will presume to be running on the context's thread.//
|
||||
if(getMonitor() != null && !ThreadService.getIsSingleThreadedContext()) {
|
||||
Updater.getSingleton().run(new CollectionObserverUpdaterRunnable(getMonitor(), REMOVE_ALL, null));
|
||||
}//if//
|
||||
else {
|
||||
internalRemovingAll();
|
||||
}//else//
|
||||
}//else//
|
||||
}//removingAll()//
|
||||
public void startChanges(int changeCount) {
|
||||
queuedChanges = new LiteList(changeCount > 0 ? changeCount : 100, 1000);
|
||||
}//startChanges()//
|
||||
public void stopChanges() {
|
||||
//Thread the changes if we are not in a single threaded context (in which case we will presume to be running on the context's thread.//
|
||||
if(getMonitor() != null && !ThreadService.getIsSingleThreadedContext()) {
|
||||
Updater.getSingleton().run(new UpdaterRunnable() {
|
||||
public void run() {
|
||||
internalStopChanges();
|
||||
}//run()//
|
||||
public Monitor getMonitor() {
|
||||
return HashSetAdapter.this.getMonitor();
|
||||
}//getMonitor()//
|
||||
});
|
||||
}//if//
|
||||
else {
|
||||
if(queuedChanges != null && queuedChanges.getSize() > 0) {
|
||||
internalStopChanges();
|
||||
}//if//
|
||||
}//else//
|
||||
}//stopChanges()//
|
||||
/**
|
||||
* Proces the queued changes in batch.
|
||||
*/
|
||||
private void internalStopChanges() {
|
||||
if(collectionObservers != null) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).startChanges(queuedChanges.getSize() >> 1);
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
for(int index = 0; index < queuedChanges.getSize(); index ++) {
|
||||
internalProcessCommand((Integer) queuedChanges.get(index++), queuedChanges.get(index));
|
||||
}//for//
|
||||
|
||||
if(collectionObservers != null) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).stopChanges();
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
queuedChanges.removeAll();
|
||||
queuedChanges = null;
|
||||
}//internalStopChanges()//
|
||||
private void internalProcessCommand(Integer command, Object value) {
|
||||
switch(command.intValue()) {
|
||||
case 0: { //ADD
|
||||
internalValueAdded(value);
|
||||
break;
|
||||
}//case//
|
||||
case 1: { //REMOVE
|
||||
internalValueRemoved(value);
|
||||
break;
|
||||
}//case//
|
||||
case 2: { //REMOVING ALL
|
||||
internalRemovingAll();
|
||||
break;
|
||||
}//case//
|
||||
}//switch//
|
||||
}//internalProcessCommand()//
|
||||
private void internalValueAdded(Object value) {
|
||||
Object newValue = value;
|
||||
|
||||
if(converter != null) {
|
||||
newValue = converter.internalAdd(newValue);
|
||||
}//if//
|
||||
|
||||
internalAdd(newValue);
|
||||
|
||||
if(collectionObservers != null) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).valueAdded(value);
|
||||
}//for//
|
||||
}//if//
|
||||
}//internalValueAdded()//
|
||||
private void internalValueRemoved(Object value) {
|
||||
Object oldValue = value;
|
||||
|
||||
if(converter != null) {
|
||||
oldValue = converter.internalRemove(oldValue);
|
||||
}//if//
|
||||
|
||||
internalRemove(oldValue);
|
||||
|
||||
if(collectionObservers != null) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).valueRemoved(value);
|
||||
}//for//
|
||||
}//if//
|
||||
}//internalValueRemoved()//
|
||||
private void internalRemovingAll() {
|
||||
if(collectionObservers != null) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).removingAll();
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
if(converter != null) {
|
||||
converter.getConversionMap().removeAll();
|
||||
}//if//
|
||||
|
||||
internalRemoveAll();
|
||||
}//internalRemovingAll()//
|
||||
}//CollectionObserver//
|
||||
/**
|
||||
* HashSetAdapter constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
*/
|
||||
protected HashSetAdapter() {
|
||||
super();
|
||||
}//HashSetAdapter()//
|
||||
/**
|
||||
* HashSetAdapter constructor.
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @throws IllegalArgumentException If the initial capacity or load factor are not within their valid ranges.
|
||||
*/
|
||||
public HashSetAdapter(IInlineCollectionObservable parent) {
|
||||
initialize(parent, DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_COMPARATOR, DEFAULT_STYLE);
|
||||
}//HashSetAdapter()//
|
||||
/**
|
||||
* HashSetAdapter constructor.
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param initialCapacity Determines the size of the array holding the set values.
|
||||
* @throws IllegalArgumentException If the initial capacity or load factor are not within their valid ranges.
|
||||
*/
|
||||
public HashSetAdapter(IInlineCollectionObservable parent, int initialCapacity) {
|
||||
initialize(parent, initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_COMPARATOR, DEFAULT_STYLE);
|
||||
}//HashSetAdapter()//
|
||||
/**
|
||||
* HashSetAdapter constructor.
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param initialCapacity Determines the size of the array holding the set values.
|
||||
* @param filter A filter used to determine whether values should be included in this filtered collection.
|
||||
* @param converter A converter used to convert the external value into the internal value.
|
||||
* @throws IllegalArgumentException If the initial capacity or load factor are not within their valid ranges.
|
||||
*/
|
||||
public HashSetAdapter(IInlineCollectionObservable parent, int initialCapacity, IFilter filter, Converter converter) {
|
||||
initialize(parent, initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_COMPARATOR, DEFAULT_STYLE);
|
||||
this.filter = filter;
|
||||
this.converter = converter;
|
||||
}//HashSetAdapter()//
|
||||
/**
|
||||
* HashSetAdapter constructor.
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param initialCapacity Determines the size of the array holding the set values.
|
||||
* @param loadFactor The ratio used to determine when to increase the size of the array holding the set values.
|
||||
* @param locateComparator The comparator used by this collection for locating values. This may be null in which case the default comparator will be used (it uses logical equality for comparisons).
|
||||
* @param allowMultipleInstanceReferences Whether multiple references to the same object instance can be stored in this collection. This is normally false.
|
||||
* @throws IllegalArgumentException If the initial capacity or load factor are not within their valid ranges.
|
||||
*/
|
||||
public HashSetAdapter(IInlineCollectionObservable parent, int initialCapacity, float loadFactor, IComparator locateComparator, int style) {
|
||||
initialize(parent, initialCapacity, loadFactor, locateComparator, style);
|
||||
}//HashSetAdapter()//
|
||||
/**
|
||||
* HashSetAdapter constructor.
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param initialCapacity Determines the size of the array holding the set values.
|
||||
* @param loadFactor The ratio used to determine when to increase the size of the array holding the set values.
|
||||
* @param locateComparator The comparator used by this collection for locating values. This may be null in which case the default comparator will be used (it uses logical equality for comparisons).
|
||||
* @param allowMultipleInstanceReferences Whether multiple references to the same object instance can be stored in this collection. This is normally false.
|
||||
* @param filter A filter used to determine whether values should be included in this filtered collection.
|
||||
* @param converter A converter used to convert the external value into the internal value.
|
||||
* @throws IllegalArgumentException If the initial capacity or load factor are not within their valid ranges.
|
||||
*/
|
||||
public HashSetAdapter(IInlineCollectionObservable parent, int initialCapacity, float loadFactor, IComparator locateComparator, int style, IFilter filter, Converter converter) {
|
||||
initialize(parent, initialCapacity, loadFactor, locateComparator, style);
|
||||
this.filter = filter;
|
||||
this.converter = converter;
|
||||
}//HashSetAdapter()//
|
||||
/**
|
||||
* Initializes the read only map.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The map's parent source of collection values.
|
||||
* @param keyHandler The handler that will retreive each collection value's key.
|
||||
*/
|
||||
protected void initialize(IInlineCollectionObservable parent, int initialCapacity, float loadFactor, IComparator locateComparator, int style) {
|
||||
initialize(initialCapacity, loadFactor, locateComparator, style);
|
||||
//Add this object as a listener on the adaptable collection. The collection will notify us of all existing values.//
|
||||
parent.addCollectionObserver(observer);
|
||||
}//initialize()//
|
||||
/**
|
||||
* Gets whether the object has been altered in some way.
|
||||
* <p>
|
||||
* The altered flag errors on the side of false positives with no possibility of a false negative.
|
||||
* The intended use of the altered flag is to improve validation efficiency.
|
||||
* </p>
|
||||
*/
|
||||
public boolean getIsAltered() {
|
||||
return isAltered;
|
||||
}//getIsAltered()//
|
||||
/**
|
||||
* Resets the altered flag which is used to identify when the object may have been altered.
|
||||
* <p>
|
||||
* The altered flag errors on the side of false positives with no possibility of a false negative.
|
||||
* The intended use of the altered flag is to improve validation efficiency.
|
||||
* </p>
|
||||
*/
|
||||
public void resetAlteredFlag() {
|
||||
if(isAltered) {
|
||||
TypeCallbackHandler handler = MetadataService.getSingleton().getTypeMetadata(getPartOfEntity().getClass()).getTypeCallbackHandler();
|
||||
|
||||
handler.updateVirtualObjectAlteredCounter(getPartOfEntity(), false, 1);
|
||||
}//if//
|
||||
|
||||
isAltered = false;
|
||||
}//resetAlteredFlag()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.util.LiteCollection#internalAdd(java.lang.Object)
|
||||
*/
|
||||
protected int internalAdd(Object value) {
|
||||
HashSetEntry[] entries = getEntries();
|
||||
|
||||
//Ensure that null values are valid.//
|
||||
if(value == null) {
|
||||
value = NULL_VALUE;
|
||||
}//if//
|
||||
|
||||
int hash = getLocateComparator().hash(value);
|
||||
int index = (hash & 0x7FFFFFFF) % entries.length;
|
||||
HashSetEntry entry = null;
|
||||
|
||||
if(getStyle() != STYLE_ADD_DUPLICATES) {
|
||||
for(entry = entries[index]; entry != null; entry = entry.next) {
|
||||
if((entry.hash == hash) && (Comparator.isEqual(getLocateComparator().compare(entry.value, value)))) {
|
||||
if(getStyle() == STYLE_NO_DUPLICATES) {
|
||||
return -1;
|
||||
}//if//
|
||||
else {
|
||||
entry.count++;
|
||||
return 0;
|
||||
}//else//
|
||||
}//if//
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
if(getSize() >= getThreshold()) {
|
||||
rehash();
|
||||
|
||||
return add(value);
|
||||
}//if//
|
||||
|
||||
entry = createEntry();
|
||||
entry.hash = hash;
|
||||
entry.value = value;
|
||||
entry.next = entries[index];
|
||||
entry.count = 1;
|
||||
entries[index] = entry;
|
||||
setSize(getSize() + 1);
|
||||
|
||||
if(value != null) {
|
||||
setContainment(value, true);
|
||||
}//if//
|
||||
|
||||
notifyCollectionObserversOnAdd(value);
|
||||
|
||||
return 0;
|
||||
}//internalAdd()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.util.LiteCollection#internalRemove(java.lang.Object)
|
||||
*/
|
||||
protected boolean internalRemove(Object value) {
|
||||
HashSetEntry[] entries = getEntries();
|
||||
|
||||
//Ensure that null values are valid.//
|
||||
if(value == null) {
|
||||
value = NULL_VALUE;
|
||||
}//if//
|
||||
|
||||
int hash = getLocateComparator().hash(value);
|
||||
int index = (hash & 0x7FFFFFFF) % entries.length;
|
||||
HashSetEntry entry = null;
|
||||
HashSetEntry previous = null;
|
||||
|
||||
for(entry = entries[index], previous = null; entry != null; previous = entry, entry = entry.next) {
|
||||
if((entry.hash == hash) && (Comparator.isEqual(getLocateComparator().compare(entry.value, value)))) {
|
||||
entry.count--;
|
||||
|
||||
if(entry.count == 0) {
|
||||
if(previous != null) {
|
||||
previous.next = entry.next;
|
||||
}//if//
|
||||
else {
|
||||
entries[index] = entry.next;
|
||||
}//else//
|
||||
|
||||
setSize(getSize() - 1);
|
||||
destroyEntry(entry);
|
||||
|
||||
if(value != null) {
|
||||
setContainment(value, false);
|
||||
}//if//
|
||||
|
||||
notifyCollectionObserversOnRemove(value);
|
||||
}//if//
|
||||
|
||||
return true;
|
||||
}//if//
|
||||
}//for//
|
||||
|
||||
return false;
|
||||
}//internalRemove()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.util.LiteCollection#internalRemoveAll()
|
||||
*/
|
||||
protected void internalRemoveAll() {
|
||||
LiteList removedData = new LiteList(iterator(), getSize(), 10, false);
|
||||
|
||||
notifyCollectionObserversOnRemovingAll();
|
||||
super.internalRemoveAll();
|
||||
|
||||
if(removedData != null) {
|
||||
//Clear containments.//
|
||||
if(isPartOf) {
|
||||
for(int index = 0; index < removedData.getSize(); index++) {
|
||||
setContainment(removedData.get(index), false);
|
||||
}//for//
|
||||
}//if//
|
||||
}//if//
|
||||
}//internalRemoveAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.util.LiteCollection#internalReplace(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
protected boolean internalReplace(Object oldValue, Object newValue) {
|
||||
//Note: If this is ever supported, don't forget to replace null's with NULL_VALUE.//
|
||||
throw new MethodNotSupportedException();
|
||||
}//internalReplace()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.IInlineCollectionObservable#getCollection()
|
||||
*/
|
||||
public ICollection getCollection() {
|
||||
return new LiteList((IIterator) iterator(), this.getSize(), 10, true);
|
||||
}//getCollection()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.IInlineCollectionObservable#addCollectionObserver(com.foundation.util.IInlineCollectionObserver)
|
||||
*/
|
||||
public void addCollectionObserver(IInlineCollectionObserver observer) {
|
||||
if(collectionObservers == null) {
|
||||
collectionObservers = new LiteList(2, 4);
|
||||
}//if//
|
||||
|
||||
collectionObservers.add(observer);
|
||||
observer.startChanges(getSize());
|
||||
|
||||
//Pass all existing values to the observer.//
|
||||
for(IIterator iterator = iterator(); iterator.hasNext();) {
|
||||
observer.valueAdded(iterator.next());
|
||||
}//for//
|
||||
|
||||
observer.stopChanges();
|
||||
}//addCollectionObserver()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.IInlineCollectionObservable#removeCollectionObserver(com.foundation.util.IInlineCollectionObserver)
|
||||
*/
|
||||
public void removeCollectionObserver(IInlineCollectionObserver observer) {
|
||||
collectionObservers.remove(observer);
|
||||
}//removeCollectionObserver()//
|
||||
/**
|
||||
* Gets the monitor used to synchronize on this entity.
|
||||
* @return The monitor used by the entity if it is contained by another entity, or null if it is not contained by another entity.
|
||||
*/
|
||||
private Monitor getEntityMonitor() {
|
||||
return entityMonitor;
|
||||
}//getEntityMonitor()//
|
||||
/**
|
||||
* Sets the monitor used to synchronize on this entity.
|
||||
* @param entityMonitor The monitor used by the entity if it is contained by another entity, or null if it is not contained by another entity.
|
||||
*/
|
||||
private void setEntityMonitor(Monitor entityMonitor) {
|
||||
this.entityMonitor = entityMonitor;
|
||||
}//setEntityMonitor()//
|
||||
/**
|
||||
* Gets whether the collection and its collected values are contained by another object.
|
||||
* @return Whether the collected values are part of this collection's referencer.
|
||||
*/
|
||||
protected boolean isPartOf() {
|
||||
return isPartOf;
|
||||
}//isPartOf()//
|
||||
/**
|
||||
* Gets the count of times the part-of entity has been set to the current value.
|
||||
* @return The counter for setting the part of entity.
|
||||
*/
|
||||
private int getPartOfEntityCounter() {
|
||||
return partOfEntityCounter;
|
||||
}//getPartOfEntityCounter()//
|
||||
/**
|
||||
* Sets the count of times the part-of entity has been set to the current value.
|
||||
* @param partOfEntityCounter The counter for setting the part of entity.
|
||||
*/
|
||||
private void setPartOfEntityCounter(int partOfEntityCounter) {
|
||||
this.partOfEntityCounter = partOfEntityCounter;
|
||||
}//setPartOfEntityCounter()//
|
||||
/**
|
||||
* Gets the entity the collection is part of.
|
||||
* @return The entity that this collection is a part of. This may be null.
|
||||
*/
|
||||
private IEntity getPartOfEntity() {
|
||||
return partOfEntity;
|
||||
}//getPartOfEntity()//
|
||||
/**
|
||||
* Sets the entity the collection is part of.
|
||||
* @param partOfEntity The entity that this collection is a part of. This may be null.
|
||||
*/
|
||||
private void setPartOfEntity(IEntity partOfEntity) {
|
||||
this.partOfEntity = partOfEntity;
|
||||
setEntityMonitor(partOfEntity != null ? partOfEntity.getMonitor() : null);
|
||||
}//setPartOfEntity()//
|
||||
/**
|
||||
* Sets whether the collection and its collected values are contained by another object.
|
||||
* @param isPartOf Whether the collected values are part of this collection's referencer.
|
||||
*/
|
||||
private void isPartOf(boolean isPartOf) {
|
||||
if(/*(!isReflection()) && */(this.isPartOf != isPartOf)) {
|
||||
IIterator iterator = iterator();
|
||||
|
||||
this.isPartOf = isPartOf;
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object next = iterator.next();
|
||||
|
||||
if(next instanceof ISupportsContainment) {
|
||||
MetadataService.getSingleton().getTypeMetadata(next.getClass()).getTypeCallbackHandler().setMonitor(next, isPartOf ? getPartOfEntity() : null, false);
|
||||
}//if//
|
||||
}//while//
|
||||
}//if//
|
||||
}//isPartOf()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.metadata.ISupportsContainment#getMonitor()
|
||||
*/
|
||||
public Monitor getMonitor() {
|
||||
Monitor monitor = getEntityMonitor();
|
||||
|
||||
if((monitor != null) && (monitor.getSupported() instanceof ISupportsContainment) && (monitor.getSupported() != this)) {
|
||||
monitor = ((ISupportsContainment) monitor.getSupported()).getMonitor();
|
||||
}//if//
|
||||
|
||||
return monitor;
|
||||
}//getMonitor()//
|
||||
/**
|
||||
* Executes an operation on this collection such that events are condensed into one.
|
||||
* @param operation the operation to be run.
|
||||
*/
|
||||
public void execute(ICollectionOperation operation) {
|
||||
notifyCollectionObserversOnStart(0);
|
||||
operation.run(this);
|
||||
notifyCollectionObserversOnStop();
|
||||
}//execute()//
|
||||
/**
|
||||
* Sets whether the value is part of the collection's referencer.
|
||||
* @param value The collection value.
|
||||
* @param isAdding Whether the list is adding the value to the collection.
|
||||
*/
|
||||
protected final void setContainment(Object value, boolean isAdding) {
|
||||
if(/*(!isReflection()) && */(isPartOf) && (value != null) && (value instanceof ISupportsContainment)) {
|
||||
MetadataService.getSingleton().getTypeMetadata(value.getClass()).getTypeCallbackHandler().setMonitor(value, isAdding ? getPartOfEntity() : null, false);
|
||||
}//if//
|
||||
}//setContainment()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.clone.ICloneable#cloneObject(com.foundation.metadata.CloneContext, com.foundation.common.MetadataContainer)
|
||||
*/
|
||||
public Object cloneObject(CloneContext context, MetadataContainer metadata) {
|
||||
return TYPE_CALLBACK_HANDLER.clone(this, metadata, context);
|
||||
}//cloneObject()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#clone()
|
||||
*/
|
||||
protected Object clone() {
|
||||
return null;
|
||||
}//clone()//
|
||||
/**
|
||||
* Loads attributes within the given context. The context controls which attributes are loaded from which objects.
|
||||
* @param context The context for the load operation.
|
||||
*/
|
||||
protected void loadAttributes(LoadAttributesContext context) {
|
||||
if(isPartOf()) {
|
||||
IIterator iterator = iterator();
|
||||
|
||||
addCollectionObserver(context);
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object value = iterator.next();
|
||||
|
||||
if(value instanceof ISupportsContainment) {
|
||||
context.include(value);
|
||||
}//if//
|
||||
}//while//
|
||||
}//if//
|
||||
}//loadAttributes()//
|
||||
/**
|
||||
* Called after the loadAttributes method and after the attributes have been used as needed.
|
||||
* @param context The context for the load operation.
|
||||
*/
|
||||
protected void postLoadAttributes(LoadAttributesContext context) {
|
||||
if(isPartOf()) {
|
||||
removeCollectionObserver(context);
|
||||
}//if//
|
||||
}//postLoadAttributes()//
|
||||
/**
|
||||
* Determines whether there are any observers to this collection.
|
||||
* @return Whether there are any observer objects attached to this collection.
|
||||
*/
|
||||
protected boolean hasCollectionObservers() {
|
||||
return (collectionObservers != null) && (collectionObservers.getSize() > 0);
|
||||
}//hasCollectionObservers()//
|
||||
/**
|
||||
* Notifies any collection listeners of a change in the collection values.
|
||||
* @param value The value added.
|
||||
*/
|
||||
protected void notifyCollectionObserversOnAdd(Object value) {
|
||||
if((collectionObservers != null) && (collectionObservers.getSize() > 0)) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).valueAdded(value);
|
||||
}//for//
|
||||
}//if//
|
||||
}//notifyCollectionObserversOnAdd()//
|
||||
/**
|
||||
* Notifies any collection listeners of a change in the collection values.
|
||||
* @param value The value removed.
|
||||
*/
|
||||
protected void notifyCollectionObserversOnRemove(Object value) {
|
||||
if((collectionObservers != null) && (collectionObservers.getSize() > 0)) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).valueRemoved(value);
|
||||
}//for//
|
||||
}//if//
|
||||
}//notifyCollectionObserversOnRemove()//
|
||||
/**
|
||||
* Notifies any collection listeners of a change in the collection values.
|
||||
*/
|
||||
protected void notifyCollectionObserversOnRemovingAll() {
|
||||
if((collectionObservers != null) && (collectionObservers.getSize() > 0)) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).removingAll();
|
||||
}//for//
|
||||
}//if//
|
||||
}//notifyCollectionObserversOnRemovingAll()//
|
||||
/**
|
||||
* Notifies any collection listeners that a set of changes to the collection is beginning.
|
||||
* @param changeCount The number of changes anticipated, or <= 0 if unkown.
|
||||
*/
|
||||
protected void notifyCollectionObserversOnStart(int changeCount) {
|
||||
if((collectionObservers != null) && (collectionObservers.getSize() > 0)) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).startChanges(changeCount);
|
||||
}//for//
|
||||
}//if//
|
||||
}//notifyCollectionObserversOnStart()//
|
||||
/**
|
||||
* Notifies any collection listeners that the set of changes to the collection has ended.
|
||||
*/
|
||||
protected void notifyCollectionObserversOnStop() {
|
||||
if((collectionObservers != null) && (collectionObservers.getSize() > 0)) {
|
||||
for(int index = 0; index < collectionObservers.getSize(); index++) {
|
||||
((IInlineCollectionObserver) collectionObservers.get(index)).stopChanges();
|
||||
}//for//
|
||||
}//if//
|
||||
}//notifyCollectionObserversOnStop()//
|
||||
/**
|
||||
* Sets the flag for maintaining weak link back references used to prevent this collection from being GC'd while a collected object is being actively referenced (when the entity that references this collection flags it as part-of and weak).
|
||||
*/
|
||||
protected void setMaintainWeakLinkBackReferences() {
|
||||
if(!maintainWeakLinkBackReferences) {
|
||||
IIterator iterator = iterator();
|
||||
|
||||
maintainWeakLinkBackReferences = true;
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object next = iterator.next();
|
||||
|
||||
if(next instanceof ISupportsContainment) {
|
||||
TypeCallbackHandler handler = MetadataService.getSingleton().getTypeMetadata(next.getClass()).getTypeCallbackHandler();
|
||||
|
||||
if(handler != null) {
|
||||
handler.addWeakLinkBackReference(next, this);
|
||||
}//if//
|
||||
}//if//
|
||||
}//while//
|
||||
}//if//
|
||||
}//setMaintainWeakLinkBackReferences()//
|
||||
}//HashSet//
|
||||
28
Foundation/src/com/foundation/util/HashSetManager.java
Normal file
28
Foundation/src/com/foundation/util/HashSetManager.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package com.foundation.util;
|
||||
|
||||
public class HashSetManager extends CollectionManager {
|
||||
public static final HashSetManager DEFAULT_MANAGER = new HashSetManager();
|
||||
/**
|
||||
* HashSetManager constructor.
|
||||
*/
|
||||
public HashSetManager() {
|
||||
super();
|
||||
}//HashSetManager()//
|
||||
/**
|
||||
* Reads the collection manager from a stream.
|
||||
* @param in The input stream to deserialize from.
|
||||
*/
|
||||
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
|
||||
/*byte version = */in.readByte();
|
||||
|
||||
super.readExternal(in);
|
||||
}//readExternal()//
|
||||
/**
|
||||
* Writes the collection manager to the stream.
|
||||
* @param out The output stream to serialize to.
|
||||
*/
|
||||
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
|
||||
out.writeByte(0);
|
||||
super.writeExternal(out);
|
||||
}//writeExternal()//
|
||||
}//HashSetManager//
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.util.ICollection;
|
||||
import com.foundation.metadata.ISupportsContainment;
|
||||
|
||||
/**
|
||||
* This interface defines a collection which accepts inline collection observers.
|
||||
* <p><b>Warning: The notification is inlined in the altering of the observed collection. Users should take extra care that the thread is not held up and exceptions are not thrown.</b></p>
|
||||
* <p>This interface is generally intended for internal foundation use. Great care should be taken when using this.
|
||||
* The collections that allow use of this interface do also fire standard change events which are much safer to listen to since they arrive on a separate thread.</p>
|
||||
*/
|
||||
public interface IInlineCollectionObservable extends ISupportsContainment {
|
||||
/**
|
||||
* Adds a collection observer.
|
||||
* <p><b>Warning: The notification is inlined in the altering of the observed collection. Users should take extra care that the thread is not held up and exceptions are not thrown.</b></p>
|
||||
* <p><b>Warning: The creator of the observer should have synchronized on this collection's monitor during the creation of the observer so that other threads are not modifying the collection while the observer is being initialized.</b></p>
|
||||
* <p>This interface is generally intended for internal foundation use. Great care should be taken when using this.
|
||||
* The collections that allow use of this interface do also fire standard change events which are much safer to listen to since they arrive on a separate thread.</p>
|
||||
* <p>Note: Collection listeners will be provided updates in this call for all existing values in the collection.</p>
|
||||
* @param listener Called by the collection as values are added and removed. The listener must remove its self when it no longer requires updates.
|
||||
* @see #removeCollectionObserver(IInlineCollectionObserver)
|
||||
*/
|
||||
public void addCollectionObserver(IInlineCollectionObserver observer);
|
||||
/**
|
||||
* Removes a collection observer.
|
||||
* @param listener The listener to be removed and no longer notified of collection changes.
|
||||
* @see #addCollectionObserver(IInlineCollectionObserver)
|
||||
*/
|
||||
public void removeCollectionObserver(IInlineCollectionObserver observer);
|
||||
/**
|
||||
* Gets the observable collection.
|
||||
* @return A collection that can be observed.
|
||||
*/
|
||||
public ICollection getCollection();
|
||||
}//IInlineCollectionObservable//
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
/**
|
||||
* Listeners implementing this interface who are bound to a collection will receive notification immediatly when the bound collection is altered.
|
||||
* <p><b>Warning: The notification is inlined in the altering of the observed collection. Users should take extra care that the thread is not held up and exceptions are not thrown.</b></p>
|
||||
* <p>This interface is generally intended for internal foundation use. Great care should be taken when using this.
|
||||
* The collections that allow use of this interface do also fire standard change events which are much safer to listen to since they arrive on a separate thread.</p>
|
||||
* <p>Warning: Adding an observer to a collection will fire add events for each item already in the collection.</p>
|
||||
*/
|
||||
public interface IInlineCollectionObserver {
|
||||
/**
|
||||
* Called by the collection when all values are about to be removed.
|
||||
*/
|
||||
public void removingAll();
|
||||
/**
|
||||
* Called by the collection when a value is added.
|
||||
* @param value The added value.
|
||||
*/
|
||||
public void valueAdded(Object value);
|
||||
/**
|
||||
* Called by the collection when a value is removed.
|
||||
* @param value The removed value.
|
||||
*/
|
||||
public void valueRemoved(Object value);
|
||||
/**
|
||||
* Called by the collection before making a set of changes.
|
||||
* <p>Warning: This may not be called if only one value is being added or removed, or all values are being removed.</p>
|
||||
* @param changeCount The estimated number of changes to be passed, or <= 0 if the number cannot be determined.
|
||||
*/
|
||||
public void startChanges(int changeCount);
|
||||
/**
|
||||
* Called by the collection after making a set of changes.
|
||||
* <p>Warning: This may not be called if only one value is being added or removed, or all values are being removed.</p>
|
||||
*/
|
||||
public void stopChanges();
|
||||
}//IInlineCollectionListener//
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
/**
|
||||
* This interface defines a collection which accepts inline indexed collection observers.
|
||||
* <p><b>Warning: The notification is inlined in the altering of the observed collection. Users should take extra care that the thread is not held up and exceptions are not thrown.</b></p>
|
||||
* <p>This interface is generally intended for internal foundation use. Great care should be taken when using this.
|
||||
* The collections that allow use of this interface do also fire standard change events which are much safer to listen to since they arrive on a separate thread.</p>
|
||||
*/
|
||||
public interface IInlineIndexedCollectionObservable {
|
||||
/**
|
||||
* Adds an indexed collection observer.
|
||||
* <p><b>Warning: The notification is inlined in the altering of the observed collection. Users should take extra care that the thread is not held up and exceptions are not thrown.</b></p>
|
||||
* <p><b>Warning: The creator of the observer should have synchronized on this collection's monitor during the creation of the observer so that other threads are not modifying the collection while the observer is being initialized.</b></p>
|
||||
* <p>This interface is generally intended for internal foundation use. Great care should be taken when using this.
|
||||
* The collections that allow use of this interface do also fire standard change events which are much safer to listen to since they arrive on a separate thread.</p>
|
||||
* @param listener Called by the collection as values are added and removed. The listener must remove its self when it no longer requires updates.
|
||||
* @see #removeCollectionObserver(IInlineIndexedCollectionObserver)
|
||||
*/
|
||||
public void addCollectionObserver(IInlineIndexedCollectionObserver observer);
|
||||
/**
|
||||
* Removes an indexed collection observer.
|
||||
* @param listener The listener to be removed and no longer notified of collection changes.
|
||||
* @see #addCollectionObserver(IInlineIndexedCollectionObserver)
|
||||
*/
|
||||
public void removeCollectionObserver(IInlineIndexedCollectionObserver observer);
|
||||
}//IInlineCollectionObservable//
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
/**
|
||||
* Listeners implementing this interface who are bound to an indexed collection will receive notification immediatly when the bound collection is altered.
|
||||
* <p><b>Warning: The notification is inlined in the altering of the observed collection. Users should take extra care that the thread is not held up and exceptions are not thrown.</b></p>
|
||||
* <p>This interface is generally intended for internal foundation use. Great care should be taken when using this.
|
||||
* The collections that allow use of this interface do also fire standard change events which are much safer to listen to since they can arrive on a separate thread.</p>
|
||||
* <p>Warning: Adding an observer to a collection will fire add events for each item already in the collection.</p>
|
||||
*/
|
||||
public interface IInlineIndexedCollectionObserver {
|
||||
/**
|
||||
* Called by the collection when all values are about to be removed.
|
||||
*/
|
||||
public void removingAll();
|
||||
/**
|
||||
* Called by the collection when a value is added.
|
||||
* @param value The added value.
|
||||
* @param index The index that it was added at.
|
||||
*/
|
||||
public void valueAdded(Object value, int index);
|
||||
/**
|
||||
* Called by the collection when a value is removed.
|
||||
* @param value The removed value.
|
||||
* @param index The index that it was removed at.
|
||||
*/
|
||||
public void valueRemoved(Object value, int index);
|
||||
/**
|
||||
* Called by the collection when the values have been re-sorted (ie re-indexed).
|
||||
* @param mapping A mapping of new positions to old positions. The index is the new position and the value is the old position.
|
||||
*/
|
||||
public void valuesSorted(int[] mapping);
|
||||
/**
|
||||
* Called by the collection before making a set of changes.
|
||||
* <p>Warning: This may not be called if only one value is being added or removed, or all values are being removed.</p>
|
||||
* @param changeCount The estimated number of changes to be passed, or <= 0 if the number cannot be determined.
|
||||
*/
|
||||
public void startChanges(int changeCount);
|
||||
/**
|
||||
* Called by the collection after making a set of changes.
|
||||
* <p>Warning: This may not be called if only one value is being added or removed, or all values are being removed.</p>
|
||||
*/
|
||||
public void stopChanges();
|
||||
}//IInlineIndexedCollectionListener//
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
/**
|
||||
* This interface defines a tree collection which accepts inline collection observers.
|
||||
* <p><b>Warning: The notification is inlined in the altering of the observed tree. Users should take extra care that the thread is not held up and exceptions are not thrown.</b></p>
|
||||
* <p>This interface is generally intended for internal foundation use. Great care should be taken when using this.
|
||||
* The collections that allow use of this interface do also fire standard change events which are much safer to listen to since they arrive on a separate thread.</p>
|
||||
*/
|
||||
public interface IInlineTreeCollectionObservable {
|
||||
/**
|
||||
* Adds a tree collection observer.
|
||||
* <p><b>Warning: The notification is inlined in the altering of the observed collection. Users should take extra care that the thread is not held up and exceptions are not thrown.</b></p>
|
||||
* <p><b>Warning: The creator of the observer should have synchronized on this collection's monitor during the creation of the observer so that other threads are not modifying the collection while the observer is being initialized.</b></p>
|
||||
* <p>This interface is generally intended for internal foundation use. Great care should be taken when using this.
|
||||
* The collections that allow use of this interface do also fire standard change events which are much safer to listen to since they arrive on a separate thread.</p>
|
||||
* <p>Note: Tree listeners will be provided updates in this call for all existing values in the tree.</p>
|
||||
* @param listener Called by the collection as values are added and removed. The listener must remove its self when it no longer requires updates.
|
||||
* @see #removeCollectionObserver(IInlineTreeCollectionObserver)
|
||||
*/
|
||||
public void addCollectionObserver(IInlineTreeCollectionObserver observer);
|
||||
/**
|
||||
* Removes a tree collection observer.
|
||||
* @param listener The listener to be removed and no longer notified of collection changes.
|
||||
* @see #addCollectionObserver(IInlineTreeCollectionObserver)
|
||||
*/
|
||||
public void removeCollectionObserver(IInlineTreeCollectionObserver observer);
|
||||
}//IInlineTreeCollectionObservable//
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
/**
|
||||
* Listeners implementing this interface who are bound to a tree collection will receive notification immediatly when the bound tree is altered.
|
||||
* <p><b>Warning: The notification is inlined in the altering of the observed collection. Users should take extra care that the thread is not held up and exceptions are not thrown.</b></p>
|
||||
* <p>This interface is generally intended for internal foundation use. Great care should be taken when using this.
|
||||
* The collections that allow use of this interface do also fire standard change events which are much safer to listen to since they arrive on a separate thread.</p>
|
||||
* <p>Warning: Adding an observer to a collection will fire add events for each item already in the collection.</p>
|
||||
*/
|
||||
public interface IInlineTreeCollectionObserver {
|
||||
/**
|
||||
* Called by the collection when all values are about to be removed.
|
||||
*/
|
||||
public void removingAll();
|
||||
/**
|
||||
* Called by the tree collection when a value is added.
|
||||
* @param parent The added value's parent, or null if it is a root value.
|
||||
* @param value The added value.
|
||||
*/
|
||||
public void valueAdded(Object parent, Object value);
|
||||
/**
|
||||
* Called by the tree collection when a value is removed.
|
||||
* @param parent The removed value's parent, or null if it is a root value.
|
||||
* @param value The removed value.
|
||||
*/
|
||||
public void valueRemoved(Object parent, Object value);
|
||||
/**
|
||||
* Called by the collection before making a set of changes.
|
||||
* @param changeCount The estimated number of changes to be passed, or <= 0 if the number cannot be determined.
|
||||
*/
|
||||
public void startChanges(int changeCount);
|
||||
/**
|
||||
* Called by the collection after making a set of changes.
|
||||
*/
|
||||
public void stopChanges();
|
||||
}//IInlineTreeCollectionObserver//
|
||||
20
Foundation/src/com/foundation/util/IKeyExtractor.java
Normal file
20
Foundation/src/com/foundation/util/IKeyExtractor.java
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
/**
|
||||
* Extracts a key from a value for use in maps.
|
||||
*/
|
||||
public interface IKeyExtractor {
|
||||
/**
|
||||
* Gets a key object given a collection value.
|
||||
* @param value The value whose key is to be retreived.
|
||||
* @return The key for the given value.
|
||||
*/
|
||||
public Object getKey(Object value);
|
||||
}//IKeyExtractor//
|
||||
63
Foundation/src/com/foundation/util/IManagedCollection.java
Normal file
63
Foundation/src/com/foundation/util/IManagedCollection.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.util.ICollection;
|
||||
import com.foundation.attribute.IReflectCollectionSupport;
|
||||
import com.foundation.attribute.IReflectableCollection;
|
||||
import com.foundation.event.IEventEmitter;
|
||||
import com.foundation.metadata.Event;
|
||||
|
||||
/**
|
||||
* Defines a managed collection as a collection that is at least partially integrated into the containing object and is smart in that it can notify listeners when changes occur and can track the changes.
|
||||
*/
|
||||
public interface IManagedCollection extends ICollection, ITrackedCollection, IReflectableCollection, IReflectCollectionSupport, IEventEmitter, IInlineCollectionObservable {
|
||||
/** Identifies a trusted change to the collection which does not need validation and should not be tracked. */
|
||||
public static final byte CONTEXT_TRUSTED = com.foundation.attribute.AttributeSupport.CONTEXT_TRUSTED;
|
||||
/** Identifies an untrusted change to the collection which requires change tracking. */
|
||||
public static final byte CONTEXT_UNTRUSTED = com.foundation.attribute.AttributeSupport.CONTEXT_UNTRUSTED;
|
||||
/**
|
||||
* The event fired by the collection when it is altered. This can be listened to by other objects in the system to receive basic change notification.
|
||||
* <p>
|
||||
* <ul> Parameters:
|
||||
* <li> <code>com.foundation.util.CollectionChangeEvent</code> A container for adds and removes.
|
||||
* </ul>
|
||||
*/
|
||||
public static final Event EVENT = com.foundation.metadata.MetadataService.getSingleton().addEvent(IManagedCollection.class, "event");
|
||||
/**
|
||||
* The event fired by the collection when the size changes. This can be listened to by other objects in the system to receive size change notification.
|
||||
* <p>
|
||||
* <ul> Parameters:
|
||||
* <li> None
|
||||
* </ul>
|
||||
*/
|
||||
public static final Event SIZE = com.foundation.metadata.MetadataService.getSingleton().addEvent(IManagedCollection.class, "size");
|
||||
|
||||
/**
|
||||
* Defines a collection operation that may make multiple changes to the collection.
|
||||
* The collection operation makes making changes more efficient since only one event is fired for a set of changes.
|
||||
*/
|
||||
public interface ICollectionOperation {
|
||||
public void run(ManagedCollection collection);
|
||||
}//ICollectionOperation//
|
||||
/**
|
||||
* Executes an operation on this collection such that events are condensed into one.
|
||||
* @param operation the operation to be run.
|
||||
*/
|
||||
public void execute(ICollectionOperation operation);
|
||||
/**
|
||||
* Gets the extended error information regarding the last operation. This may be set by the application from within the collection's manager and then retrieved by the application after the operation fails.
|
||||
* @return The application defined error data for the current or last operation performed.
|
||||
*/
|
||||
public Object getErrorInfo();
|
||||
/**
|
||||
* Sets the extended error information regarding the last operation. This may be set by the application from within the collection's manager and then retrieved by the application after the operation fails.
|
||||
* @param errorInfo The application defined error data for the current or last operation performed.
|
||||
*/
|
||||
public void setErrorInfo(Object errorInfo);
|
||||
}//IManagedCollection//
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2006,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
/**
|
||||
* This mapping allows a managed collection to make changes to a related collection in a trusted context.
|
||||
* The two collections are then linked such that an add to one is an add to the other and so on.
|
||||
* The advantage to this is that the mapping between the two objects (the bidirectional reference) is only stored once when the objects are updated in a repository.
|
||||
*/
|
||||
public interface IManagedCollectionMapping {
|
||||
/**
|
||||
* Gets a mapped collection from the given value.
|
||||
* @param collectionValue The value in the collection utilizing this mapping.
|
||||
* @return The value's mapped collection.
|
||||
*/
|
||||
public ManagedCollection getMappedCollection(Object collectionValue);
|
||||
}//IManagedCollectionMapping//
|
||||
6
Foundation/src/com/foundation/util/IManagedHashSet.java
Normal file
6
Foundation/src/com/foundation/util/IManagedHashSet.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.util.IHashSet;
|
||||
|
||||
public interface IManagedHashSet extends IHashSet {
|
||||
}//IManagedHashSet//
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.util.IIndexedCollection;
|
||||
import com.foundation.metadata.Event;
|
||||
|
||||
public interface IManagedIndexedCollection extends IIndexedCollection, IManagedCollection, IInlineIndexedCollectionObservable {
|
||||
/**
|
||||
* The event fired by the indexed collection when it is sorted. This can be listened to by other objects in the system to receive basic sort notification.
|
||||
* <p>
|
||||
* <ul> Parameters:
|
||||
* <li> <code>int[]</code> A mapping of new positions to old positions. The index is the new position and the value is the old position.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static final Event SORT_EVENT = com.foundation.metadata.MetadataService.getSingleton().addEvent(IManagedIndexedCollection.class, "collectionSorted");
|
||||
}//IManagedIndexedCollection//
|
||||
11
Foundation/src/com/foundation/util/IManagedList.java
Normal file
11
Foundation/src/com/foundation/util/IManagedList.java
Normal file
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
public interface IManagedList extends com.common.util.IList, IManagedIndexedCollection {
|
||||
}//IManagedList//
|
||||
41
Foundation/src/com/foundation/util/ITrackedCollection.java
Normal file
41
Foundation/src/com/foundation/util/ITrackedCollection.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.util.ICollection;
|
||||
|
||||
public interface ITrackedCollection extends ICollection {
|
||||
/**
|
||||
* Determines whether the collection has any changes.
|
||||
* @return Whether the collection as any adds or removes.
|
||||
*/
|
||||
public boolean hasCollectionChanges();
|
||||
/**
|
||||
* Creates the collection of adds and removes since the change flags were last reset.
|
||||
* @param added The collection to be filled with added values. This can be null if adds are ignored.
|
||||
* @param removed The collection to be filled with removed values. This can be null if removes are ignored.
|
||||
*/
|
||||
public void getCollectionChanges(ICollection added, ICollection removed);
|
||||
/**
|
||||
* Resets the change tracking collections.
|
||||
* <p>Does nothing if the collection is a reflection.</p>
|
||||
*/
|
||||
public void resetChangeTracking();
|
||||
/**
|
||||
* Resets the change tracking for this object and all part-of objects.
|
||||
*/
|
||||
public void resetVirtualObjectChangeFlags();
|
||||
/**
|
||||
* Reverses any changes to this object (requires that change tracking be enabled which it is by default).
|
||||
*/
|
||||
public void reverseObjectChanges();
|
||||
/**
|
||||
* Reverses any changes to this object and to any objects that are marked as being part of this object.
|
||||
*/
|
||||
public void reverseVirtualObjectChanges();
|
||||
}//ITrackedCollection//
|
||||
230
Foundation/src/com/foundation/util/IndexedCollectionManager.java
Normal file
230
Foundation/src/com/foundation/util/IndexedCollectionManager.java
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.util.IIterator;
|
||||
import com.common.util.ICollection;
|
||||
|
||||
/**
|
||||
* A simple implementation of the IIndexedCollectionManager interface.
|
||||
* Applications are encouraged to extend this class to provide application specific changes.
|
||||
*/
|
||||
public abstract class IndexedCollectionManager extends CollectionManager {
|
||||
/**
|
||||
* IndexedCollectionManager constructor.
|
||||
*/
|
||||
public IndexedCollectionManager() {
|
||||
super();
|
||||
}//IndexedCollectionManager()//
|
||||
/**
|
||||
* Determines whether the value can be added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param index The index that the value will be added in the managed collection.
|
||||
* @param value The value that may be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether the value can be added to the collection.
|
||||
*/
|
||||
public boolean canAdd(IManagedIndexedCollection managed, int index, Object value, byte context) {
|
||||
return canAdd(managed, value, context);
|
||||
}//canAdd()//
|
||||
/**
|
||||
* Determines whether the value can be added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param index The index where the values will be added in the managed collection.
|
||||
* @param values The values that may be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether the values can be added to the collection.
|
||||
*/
|
||||
public boolean canAddAll(IManagedIndexedCollection managed, int index, Object[] values, byte context) {
|
||||
boolean retVal = true;
|
||||
|
||||
for(int valuesIndex = 0; (valuesIndex < values.length) && (retVal); valuesIndex++) {
|
||||
retVal = canAdd(managed, index++, values[valuesIndex], context);
|
||||
}//for//
|
||||
|
||||
return retVal;
|
||||
}//canAddAll()//
|
||||
/**
|
||||
* Determines whether the value can be added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param index The index where the values will be added in the managed collection.
|
||||
* @param values The values that may be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether the values can be added to the collection.
|
||||
*/
|
||||
public boolean canAddAll(IManagedIndexedCollection managed, int index, ICollection values, byte context) {
|
||||
boolean retVal = true;
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
while((retVal) && (iterator.hasNext())) {
|
||||
retVal = canAdd(managed, index++, iterator.next(), context);
|
||||
}//while//
|
||||
|
||||
return retVal;
|
||||
}//canAddAll()//
|
||||
/**
|
||||
* Determines whether the value can be removed from the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param index The index of the value that will be removed from the managed collection.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether the value can be removed from the collection.
|
||||
*/
|
||||
public boolean canRemove(IManagedIndexedCollection managed, int index, byte context) {
|
||||
return canRemove(managed, managed.get(index), context);
|
||||
}//canRemove()//
|
||||
/**
|
||||
* Determines whether the value can be swapped in the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param index The index of the value that will be replaced in the managed collection.
|
||||
* @param newValue The value that may replace the old one.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether the value can be replaced in the collection with the new value.
|
||||
*/
|
||||
public boolean canReplace(IManagedIndexedCollection managed, int index, Object newValue, byte context) {
|
||||
return canReplace(managed, managed.get(index), newValue, context);
|
||||
}//canReplace()//
|
||||
/**
|
||||
* Allows the manager to provide functionality after a value has been added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param index The index that the value will be added in the managed collection.
|
||||
* @param value The value that has be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #preAdd(IManagedIndexedCollection, index, value)
|
||||
*/
|
||||
public void postAdd(IManagedIndexedCollection managed, int index, Object value, byte context) {
|
||||
postAdd(managed, value, context);
|
||||
}//postAdd()//
|
||||
/**
|
||||
* Allows the manager to provide functionality after values are added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param index The index where the values were added in the managed collection.
|
||||
* @param values The values that have been added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #preAddAll(IManagedIndexedCollection, int, Object[])
|
||||
*/
|
||||
public void postAddAll(IManagedIndexedCollection managed, int index, Object[] values, byte context) {
|
||||
for(int valuesIndex = 0; valuesIndex < values.length; valuesIndex++) {
|
||||
postAdd(managed, index++, values[valuesIndex], context);
|
||||
}//for//
|
||||
}//postAddAll()//
|
||||
/**
|
||||
* Allows the manager to pprovide functionality after values are added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param index The index where the values were added in the managed collection.
|
||||
* @param values The values that have been added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #preAddAll(IManagedIndexedCollection, index, ICollection)
|
||||
*/
|
||||
public void postAddAll(IManagedIndexedCollection managed, int index, ICollection values, byte context) {
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
postAdd(managed, index++, iterator.next(), context);
|
||||
}//while//
|
||||
}//postAddAll()//
|
||||
/**
|
||||
* Allows the manager to provide functionality after a value has been removed from the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param index The index of the value that was removed from the managed collection.
|
||||
* @param value The value that has be removed.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #preRemove(IManagedIndexedCollection, int)
|
||||
*/
|
||||
public void postRemove(IManagedIndexedCollection managed, int index, Object value, byte context) {
|
||||
postRemove(managed, value, context);
|
||||
}//postRemove()//
|
||||
/**
|
||||
* Allows the manager to provide functionality after one value replaces another in the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param index The index of the value that was replaced in the managed collection.
|
||||
* @param oldValue The value that was replaced.
|
||||
* @param newValue The value that did replace the old one.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #preReplace(IManagedIndexedCollection, int, Object)
|
||||
*/
|
||||
public void postReplace(IManagedIndexedCollection managed, int index, Object oldValue, Object newValue, byte context) {
|
||||
postReplace(managed, oldValue, newValue, context);
|
||||
}//postReplace()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to the value being added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param index The index that the value will be added in the managed collection.
|
||||
* @param value The value that will be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #canAdd(IManagedIndexedCollection, int, Object)
|
||||
*/
|
||||
public void preAdd(IManagedIndexedCollection managed, int index, Object value, byte context) {
|
||||
preAdd(managed, value, context);
|
||||
}//preAdd()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to the values being added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param index The index where the values will be added in the managed collection.
|
||||
* @param values The values that will be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #canAddAll(IManagedIndexedCollection, int, Object[])
|
||||
*/
|
||||
public void preAddAll(IManagedIndexedCollection managed, int index, Object[] values, byte context) {
|
||||
for(int valuesIndex = 0; valuesIndex < values.length; valuesIndex++) {
|
||||
preAdd(managed, index++, values[valuesIndex], context);
|
||||
}//for//
|
||||
}//preAddAll()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to the values being added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param index The index where the values will be added in the managed collection.
|
||||
* @param values The values that will be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #canAddAll(IManagedIndexedCollection, int, ICollection)
|
||||
*/
|
||||
public void preAddAll(IManagedIndexedCollection managed, int index, ICollection values, byte context) {
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
preAdd(managed, index++, iterator.next(), context);
|
||||
}//while//
|
||||
}//preAddAll()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to the value being removed from the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param index The index of the value that will be removed from the managed collection.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #canRemove(IManagedIndexedCollection, int)
|
||||
*/
|
||||
public void preRemove(IManagedIndexedCollection managed, int index, byte context) {
|
||||
preRemove(managed, managed.get(index), context);
|
||||
}//preRemove()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to one value replacing another in the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param index The index of the value that will be replaced in the managed collection.
|
||||
* @param newValue The value that will replace the old one.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @see #canReplace(IManagedIndexedCollection, int, Object)
|
||||
*/
|
||||
public void preReplace(IManagedIndexedCollection managed, int index, Object newValue, byte context) {
|
||||
preReplace(managed, managed.get(index), newValue, context);
|
||||
}//preReplace()//
|
||||
/**
|
||||
* Reads the collection manager from a stream.
|
||||
* @param in The input stream to deserialize from.
|
||||
*/
|
||||
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
|
||||
/*byte version = */in.readByte();
|
||||
|
||||
super.readExternal(in);
|
||||
}//readExternal()//
|
||||
/**
|
||||
* Writes the collection manager to the stream.
|
||||
* @param out The output stream to serialize to.
|
||||
*/
|
||||
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
|
||||
out.writeByte(0);
|
||||
super.writeExternal(out);
|
||||
}//writeExternal()//
|
||||
}//IndexedCollectionManager//
|
||||
1054
Foundation/src/com/foundation/util/ListAdapter.java
Normal file
1054
Foundation/src/com/foundation/util/ListAdapter.java
Normal file
File diff suppressed because it is too large
Load Diff
569
Foundation/src/com/foundation/util/ListAggregator.java
Normal file
569
Foundation/src/com/foundation/util/ListAggregator.java
Normal file
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.thread.Monitor;
|
||||
import com.common.util.*;
|
||||
import com.common.debug.*;
|
||||
import com.foundation.event.*;
|
||||
import com.foundation.common.*;
|
||||
|
||||
/**
|
||||
* <p><b>TODO: This code is not properly tested. It is not recomended that it be used.</b></p>
|
||||
* <p>The <b>alternative</b> to using this code is to use the ModelListener class.
|
||||
* The following is a snipit of code from a test scenario that aggregates all Bar instances from all Foo instances (from com.foundation.aggregatecollection.test.AggregateCollectionApplication in the Foundation Test project [2007]):<br>
|
||||
* <pre>
|
||||
* final HashSet set = new HashSet(20, HashSet.DEFAULT_LOAD_FACTOR, HashSet.DEFAULT_COMPARATOR, HashSet.STYLE_COUNT_DUPLICATES);
|
||||
* ModelListener listener = new ModelListener(this);
|
||||
* listener.addBinding(new AttributeBinding(AggregateCollectionApplication.class, FOOS, AttributeBinding.FLAG_LAZY_LOAD_ATTRIBUTE));
|
||||
* listener.addBinding(new AttributeBinding(Foo.class, Foo.BARS, AttributeBinding.FLAG_LAZY_LOAD_ATTRIBUTE, null, new IModelListenerCollectionHandler[] {new IModelListenerCollectionHandler() {
|
||||
* public Class getReferenceType() {
|
||||
* return Bar.class;
|
||||
* }//getReferenceType()//
|
||||
* public void run(Object object, int flags, IList addedValues, IList removedValues) {
|
||||
* set.addAll(addedValues);
|
||||
* set.removeAll(removedValues);
|
||||
* }//run()//
|
||||
* }}));
|
||||
* listener.initialize();
|
||||
* result = set;
|
||||
* </pre>
|
||||
* </p>
|
||||
* A read only collection wrapper which provides a list view on another set of collections.
|
||||
* The point is to abstract listening to changes in one or more collections and all the objects to get to those collections, in order to create a master list.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* <p>TODO: Currently the collection could concievably be altered using the add/remove methods and passing a trusted context flag. This should be prevented in the future. Perhaps an internal interface to these methods with outside access for select objects (such as the transaction service).</p>
|
||||
* <p>TODO: Add serialization code and test. Make sure to test that this adapter can be sorted independantly of the obeservable it is attached to.</p>
|
||||
* <p>TODO: Is the ReferenceLink class really necessary? It looks like it is no longer really used, or some code was forgotten. We really should clean this up.</p>
|
||||
*/
|
||||
public class ListAggregator extends ManagedList {
|
||||
private Object parent = null;
|
||||
/** The collection of references used to get the next value in the chain and to register and unregister changed events. */
|
||||
private IReference[] referenceChain = null;
|
||||
/** A matching collection of reference links which are used to track the registered events and receive updates. */
|
||||
private ReferenceLink[] referenceLinks = null;
|
||||
/** A matching collection of collection links which are used to track the collection changes and receive updates. */
|
||||
private CollectionLink[] collectionLinks = null;
|
||||
/** Whether this aggregator is used in a single threaded environment, such as in a view context. This should be true if dealing with objects in a view since they are required to be accessed by a single thread. Otherwise this should be false. */
|
||||
private boolean isThreadSafe = true;
|
||||
|
||||
/**
|
||||
* Defines one link in the chain of attributes leading to the values in this collection.
|
||||
*/
|
||||
public interface IReference {
|
||||
/**
|
||||
* Requests that the handler be registered with the necessary events identifying when the value returned by getValue(..) has changed.
|
||||
* @param entity The entity with whom the handler is registered.
|
||||
* @param handler The handler to be registered.
|
||||
*/
|
||||
public void registerChangeHandler(IEntity entity, IEventHandler handler);
|
||||
/**
|
||||
* Requests that the handler be unregistered with the previously registered events that identify when the value returned by getValue(..) has changed.
|
||||
* @param entity The entity with whom the handler is unregistered.
|
||||
* @param handler The handler to be unregistered.
|
||||
*/
|
||||
public void unregisterChangeHandler(IEntity entity, IEventHandler handler);
|
||||
/**
|
||||
* Gets the value from the given entity.
|
||||
* @param entity The entity containing a value in the reference chain.
|
||||
* @return The value being referenced.
|
||||
*/
|
||||
public Object getValue(IEntity entity);
|
||||
}//IReference//
|
||||
|
||||
private class ReferenceLink implements IEventHandler {
|
||||
/** The index of the reference in the reference chain. */
|
||||
//private int chainIndex = -1;
|
||||
|
||||
public ReferenceLink() {
|
||||
}//ReferenceLink()//
|
||||
private ReferenceLink(int chainIndex) {
|
||||
//this.chainIndex = chainIndex;
|
||||
}//ReferenceLink()//
|
||||
public void evaluate(IEventEmitter eventEmitter, int eventNumber, Object[] eventParameters, int flags) {
|
||||
}//evaluate()//
|
||||
public void evaluate(int eventNumber, Object[] eventParameters, int flags) {
|
||||
}//evaluate()//
|
||||
}//ReferenceLink//
|
||||
|
||||
/**
|
||||
* Observes a collection for changes.
|
||||
*/
|
||||
private class CollectionLink implements IEventHandler {
|
||||
/** The next link in the reference chain, or -1 if this is the last part of the reference chain. */
|
||||
private int nextChainIndex = -1;
|
||||
|
||||
public CollectionLink() {
|
||||
}//CollectionLink()//
|
||||
public CollectionLink(int nextChainIndex) {
|
||||
this.nextChainIndex = nextChainIndex;
|
||||
}//CollectionLink()//
|
||||
public void evaluate(IEventEmitter eventEmitter, int eventNumber, Object[] eventParameters, int flags) {
|
||||
if(EventSupport.isStandardEvent(flags)) {
|
||||
if(eventNumber == IManagedCollection.EVENT.getNumber()) {
|
||||
CollectionChangeEvent eventData = (CollectionChangeEvent) eventParameters[0];
|
||||
|
||||
//Extract the adds and removes.//
|
||||
if(eventData.hasAdds()) {
|
||||
if(eventData.getAddedObjects() == null) {
|
||||
valueAdded(eventEmitter, eventData.getAddedObject());
|
||||
}//if//
|
||||
else {
|
||||
IIterator iterator = eventData.getAddedObjects().iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
valueAdded(eventEmitter, iterator.next());
|
||||
}//while//
|
||||
}//else//
|
||||
}//if//
|
||||
|
||||
if(eventData.hasRemoves()) {
|
||||
if(eventData.getRemovedObjects() == null) {
|
||||
valueRemoved(eventEmitter, eventData.getRemovedObject());
|
||||
}//if//
|
||||
else {
|
||||
IIterator iterator = eventData.getRemovedObjects().iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
valueRemoved(eventEmitter, iterator.next());
|
||||
}//while//
|
||||
}//else//
|
||||
}//if//
|
||||
}//if//
|
||||
}//if//
|
||||
}//evaluate()//
|
||||
public void evaluate(int eventNumber, Object[] eventParameters, int flags) {
|
||||
//Never called.//
|
||||
}//evaluate()//
|
||||
public void valueAdded(IEventEmitter eventEmitter, Object value) {
|
||||
if(nextChainIndex == -1) {
|
||||
if(!isThreadSafe) {
|
||||
Monitor monitor = getMonitor();
|
||||
|
||||
lock(monitor);
|
||||
|
||||
try {
|
||||
add(value, CONTEXT_TRUSTED);
|
||||
}//try//
|
||||
finally {
|
||||
unlock(monitor);
|
||||
}//finally//
|
||||
}//if//
|
||||
else {
|
||||
add(value, CONTEXT_TRUSTED);
|
||||
}//else//
|
||||
}//if//
|
||||
else {
|
||||
if(!isThreadSafe) {
|
||||
registerEventsSafe(value, nextChainIndex);
|
||||
}//if//
|
||||
else {
|
||||
registerEvents(value, nextChainIndex);
|
||||
}//else//
|
||||
}//else//
|
||||
}//valueAdded()//
|
||||
public void valueRemoved(IEventEmitter eventEmitter, Object value) {
|
||||
if(nextChainIndex == -1) {
|
||||
if(!isThreadSafe) {
|
||||
Monitor monitor = getMonitor();
|
||||
|
||||
lock(monitor);
|
||||
|
||||
try {
|
||||
remove(value, CONTEXT_TRUSTED);
|
||||
}//try//
|
||||
finally {
|
||||
unlock(monitor);
|
||||
}//finally//
|
||||
}//if//
|
||||
else {
|
||||
remove(value, CONTEXT_TRUSTED);
|
||||
}//else//
|
||||
}//if//
|
||||
else {
|
||||
if(!isThreadSafe) {
|
||||
unregisterEventsSafe(value, nextChainIndex);
|
||||
}//if//
|
||||
else {
|
||||
unregisterEvents(value, nextChainIndex);
|
||||
}//else//
|
||||
}//else//
|
||||
}//valueRemoved()//
|
||||
}//CollectionLink//
|
||||
/**
|
||||
* ListAggregator constructor.
|
||||
* <p><b>Warning: This constructor is intended for use only by the serialization code. Calling this externally would fail to setup the list properly.</b></p>
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
*/
|
||||
public ListAggregator() {
|
||||
super();
|
||||
}//ListAggregator()//
|
||||
/**
|
||||
* ListAggregator constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The parent entity or collection of entities.
|
||||
* @param referenceChain The chain of references (usually attributes) from the parent to the items in the collection.
|
||||
* @param isThreadSafe Whether this aggregator is used in a single threaded environment, such as in a view context. This should be true if dealing with objects in a view since they are required to be accessed by a single thread. Otherwise this should be false.
|
||||
*/
|
||||
public ListAggregator(Object parent, IReference[] referenceChain, boolean isThreadSafe) {
|
||||
super(DEFAULT_INITIAL_SIZE, DEFAULT_CAPACITY_INCREMENT, FLAG_IS_READ_ONLY | FLAG_NO_CHANGE_TRACKING);
|
||||
|
||||
initialize(parent, referenceChain, isThreadSafe);
|
||||
}//ListAggregator()//
|
||||
/**
|
||||
* ListAggregator constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The parent entity or collection of entities.
|
||||
* @param referenceChain The chain of references (usually attributes) from the parent to the items in the collection.
|
||||
* @param isThreadSafe Whether this aggregator is used in a single threaded environment, such as in a view context. This should be true if dealing with objects in a view since they are required to be accessed by a single thread. Otherwise this should be false.
|
||||
* @param initialCapacity The initial size of the collection.
|
||||
*/
|
||||
public ListAggregator(Object parent, IReference[] referenceChain, boolean isThreadSafe, int initialCapacity) {
|
||||
super(initialCapacity, DEFAULT_CAPACITY_INCREMENT, FLAG_IS_READ_ONLY | FLAG_NO_CHANGE_TRACKING);
|
||||
|
||||
initialize(parent, referenceChain, isThreadSafe);
|
||||
}//ListAggregator()//
|
||||
/**
|
||||
* ListAggregator constructor.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The parent entity or collection of entities.
|
||||
* @param referenceChain The chain of references (usually attributes) from the parent to the items in the collection.
|
||||
* @param isThreadSafe Whether this aggregator is used in a single threaded environment, such as in a view context. This should be true if dealing with objects in a view since they are required to be accessed by a single thread. Otherwise this should be false.
|
||||
* @param initialCapacity The initial size of the collection.
|
||||
* @param capacityIncrement How much space is added at a minimum each time the collection runs out of space.
|
||||
*/
|
||||
public ListAggregator(Object parent, IReference[] referenceChain, boolean isThreadSafe, int initialCapacity, int capacityIncrement) {
|
||||
super(initialCapacity, capacityIncrement, FLAG_IS_READ_ONLY | FLAG_NO_CHANGE_TRACKING);
|
||||
|
||||
initialize(parent, referenceChain, isThreadSafe);
|
||||
}//ListAggregator()//
|
||||
/**
|
||||
* Initializes the read only collection.
|
||||
* <p><b>Warning: The creating thread must have synchronous access to the parent (must synchronize on the parent's getMonitor() object, or must have exclusive access to the parent collection).<b></p>
|
||||
* @param parent The initial source for the reference chain.
|
||||
* @param referenceChain The chain of references (usually attributes) from the parent to the items in the collection.
|
||||
* @param isThreadSafe Whether this aggregator is used in a single threaded environment, such as in a view context. This should be true if dealing with objects in a view since they are required to be accessed by a single thread. Otherwise this should be false.
|
||||
*/
|
||||
protected void initialize(Object parent, IReference[] referenceChain, boolean isThreadSafe) {
|
||||
this.parent = parent;
|
||||
this.referenceChain = referenceChain;
|
||||
this.referenceLinks = new ReferenceLink[referenceChain.length];
|
||||
this.collectionLinks = new CollectionLink[referenceChain.length + 1];
|
||||
this.isThreadSafe = isThreadSafe;
|
||||
|
||||
//Setup all the reference links for each link of the chain.//
|
||||
for(int index = 0; index < referenceLinks.length; index++) {
|
||||
referenceLinks[index] = new ReferenceLink(index);
|
||||
}//for//
|
||||
|
||||
//Setup all the collection links for each link of the chain.//
|
||||
for(int index = 0; index < collectionLinks.length; index++) {
|
||||
collectionLinks[index] = new CollectionLink(index);
|
||||
}//for//
|
||||
|
||||
//Add the last collection link which is a tail.//
|
||||
collectionLinks[collectionLinks.length - 1] = new CollectionLink(-1);
|
||||
|
||||
//Register for events and build the collection.//
|
||||
if(!isThreadSafe) {
|
||||
registerEventsSafe(parent, 0);
|
||||
}//if//
|
||||
else {
|
||||
registerEvents(parent, 0);
|
||||
}//else//
|
||||
}//initialize()//
|
||||
/**
|
||||
* Registers recursively for the events starting at the given chain index.
|
||||
* @param object The object to be registered with.
|
||||
* @param chainIndex The index in the chain to start registering.
|
||||
*/
|
||||
protected void registerEvents(Object object, int chainIndex) {
|
||||
if(chainIndex == -1) {
|
||||
if(object instanceof IManagedCollection) { //TODO: Allow the user to specify whether collection items are added, or the collection its self is added.//
|
||||
((IManagedCollection) object).registerListener(IManagedCollection.EVENT, collectionLinks[collectionLinks.length - 1], true);
|
||||
addAll((IManagedCollection) object, CONTEXT_TRUSTED);
|
||||
}//if//
|
||||
else {
|
||||
add(object, CONTEXT_TRUSTED);
|
||||
}//else//
|
||||
}//if//
|
||||
else if(object instanceof IEntity) {
|
||||
IEntity entity = (IEntity) object;
|
||||
IReference reference = referenceChain[chainIndex];
|
||||
|
||||
//Register an event to receive change notification.//
|
||||
reference.registerChangeHandler(entity, referenceLinks[chainIndex]);
|
||||
//Register for events down the chain.//
|
||||
registerEvents(reference.getValue(entity), chainIndex < referenceChain.length - 1 ? chainIndex + 1 : -1);
|
||||
}//else if//
|
||||
else if(object instanceof IManagedCollection) {
|
||||
IManagedCollection collection = (IManagedCollection) object;
|
||||
IIterator iterator = collection.iterator();
|
||||
|
||||
//Listen for the collection contents chainging.//
|
||||
collection.registerListener(IManagedCollection.EVENT, collectionLinks[chainIndex], true);
|
||||
|
||||
//Register all the collection items.//
|
||||
while(iterator.hasNext()) {
|
||||
registerEvents(iterator.next(), chainIndex);
|
||||
}//while//
|
||||
}//else if//
|
||||
else {
|
||||
//TODO: Should we just ignore this, or throw an error?//
|
||||
Debug.log("Warning: The list aggregator encountered an unknown object type in the chain.");
|
||||
}//else//
|
||||
}//registerEvents()//
|
||||
/**
|
||||
* Registers recursively for the events starting at the given chain index.
|
||||
* <p>This is the thread safe version of this method.</p>
|
||||
* @param object The object to be registered with.
|
||||
* @param chainIndex The index in the chain to start registering.
|
||||
*/
|
||||
protected void registerEventsSafe(Object object, int chainIndex) {
|
||||
Monitor monitor = getMonitor();
|
||||
|
||||
lock(monitor);
|
||||
|
||||
try {
|
||||
internalRegisterEventsSafe(object, chainIndex);
|
||||
}//try//
|
||||
finally {
|
||||
unlock(monitor);
|
||||
}//finally//
|
||||
}//registerEventsSafe()//
|
||||
/**
|
||||
* Registers recursively for the events starting at the given chain index.
|
||||
* <p>This is the thread safe version of this method.</p>
|
||||
* @param object The object to be registered with.
|
||||
* @param chainIndex The index in the chain to start registering.
|
||||
*/
|
||||
private void internalRegisterEventsSafe(Object object, int chainIndex) {
|
||||
if(chainIndex == -1) {
|
||||
if(object instanceof IManagedCollection) { //TODO: Allow the user to specify whether collection items are added, or the collection its self is added.//
|
||||
IManagedCollection collection = (IManagedCollection) object;
|
||||
LiteList items = null;
|
||||
Monitor monitor = collection.getMonitor();
|
||||
|
||||
lock(monitor);
|
||||
|
||||
try {
|
||||
//Save the current set of items so we can register them outside the synchronization.//
|
||||
items = new LiteList(collection);
|
||||
//Listen for the collection contents chainging.//
|
||||
collection.registerListener(IManagedCollection.EVENT, collectionLinks[collectionLinks.length - 1], false);
|
||||
}//try//
|
||||
finally {
|
||||
unlock(monitor);
|
||||
}//finally//
|
||||
|
||||
addAll(items, CONTEXT_TRUSTED);
|
||||
}//if//
|
||||
else {
|
||||
add(object, CONTEXT_TRUSTED);
|
||||
}//else//
|
||||
}//if//
|
||||
else if(object instanceof IEntity) {
|
||||
IEntity entity = (IEntity) object;
|
||||
IReference reference = referenceChain[chainIndex];
|
||||
Object value = null;
|
||||
Monitor monitor = entity.getMonitor();
|
||||
|
||||
lock(monitor);
|
||||
|
||||
try {
|
||||
//Register an event to receive change notification.//
|
||||
reference.registerChangeHandler(entity, referenceLinks[chainIndex]);
|
||||
//Get the current value for the reference.//
|
||||
value = reference.getValue(entity);
|
||||
}//try//
|
||||
finally {
|
||||
unlock(monitor);
|
||||
}//finally//
|
||||
|
||||
//Register outside the synchronization block for events down the chain.//
|
||||
internalRegisterEventsSafe(value, chainIndex < referenceChain.length ? chainIndex + 1 : -1);
|
||||
}//else if//
|
||||
else if(object instanceof IManagedCollection) {
|
||||
IManagedCollection collection = (IManagedCollection) object;
|
||||
LiteList items = null;
|
||||
Monitor monitor = collection.getMonitor();
|
||||
|
||||
lock(monitor);
|
||||
|
||||
try {
|
||||
//Save the current set of items so we can register them outside the synchronization.//
|
||||
items = new LiteList(collection);
|
||||
//Listen for the collection contents chainging.//
|
||||
collection.registerListener(IManagedCollection.EVENT, collectionLinks[chainIndex], false);
|
||||
}//try//
|
||||
finally {
|
||||
unlock(monitor);
|
||||
}//finally//
|
||||
|
||||
//Register all the collection items.//
|
||||
for(int index = 0; index < items.getSize(); index++) {
|
||||
internalRegisterEventsSafe(items.get(index), chainIndex);
|
||||
}//while//
|
||||
}//else if//
|
||||
else {
|
||||
//TODO: Should we just ignore this, or throw an error?//
|
||||
Debug.log("Warning: The list aggregator encountered an unknown object type in the chain.");
|
||||
}//else//
|
||||
}//internalRegisterEventsSafe()//
|
||||
/**
|
||||
* Unregisters recursively for the events starting at the given chain index.
|
||||
* @param object The object to be unregistered with.
|
||||
* @param chainIndex The index in the chain to start unregistering.
|
||||
*/
|
||||
protected void unregisterEvents(Object object, int chainIndex) {
|
||||
if(chainIndex == -1) {
|
||||
if(object instanceof IManagedCollection) { //TODO: Allow the user to specify whether collection items are added, or the collection its self is added.//
|
||||
IManagedCollection collection = (IManagedCollection) object;
|
||||
|
||||
collection.unregisterListener(IManagedCollection.EVENT, collectionLinks[collectionLinks.length - 1]);
|
||||
removeAll((IManagedCollection) object, CONTEXT_TRUSTED);
|
||||
}//if//
|
||||
else {
|
||||
remove(object, CONTEXT_TRUSTED);
|
||||
}//else//
|
||||
}//if//
|
||||
else if(object instanceof IEntity) {
|
||||
IEntity entity = (IEntity) object;
|
||||
IReference reference = referenceChain[chainIndex];
|
||||
|
||||
//Unregister an event to receive change notification.//
|
||||
reference.unregisterChangeHandler(entity, referenceLinks[chainIndex]);
|
||||
//Unregister for events down the chain.//
|
||||
unregisterEvents(reference.getValue(entity), chainIndex < referenceChain.length -1 ? chainIndex + 1 : -1);
|
||||
}//else if//
|
||||
else if(object instanceof IManagedCollection) {
|
||||
IManagedCollection collection = (IManagedCollection) object;
|
||||
IIterator iterator = collection.iterator();
|
||||
|
||||
//Stop listening for the collection contents chainging.//
|
||||
collection.unregisterListener(IManagedCollection.EVENT, collectionLinks[chainIndex]);
|
||||
|
||||
//Unregister all the collection items.//
|
||||
while(iterator.hasNext()) {
|
||||
unregisterEvents(iterator.next(), chainIndex);
|
||||
}//while//
|
||||
}//else if//
|
||||
else {
|
||||
//TODO: Should we just ignore this, or throw an error?//
|
||||
Debug.log("Warning: The list aggregator encountered an unknown object type in the chain.");
|
||||
}//else//
|
||||
}//unregisterEvents()//
|
||||
/**
|
||||
* Unregisters recursively for the events starting at the given chain index.
|
||||
* <p>This is the thread safe version of this method.</p>
|
||||
* @param object The object to be unregistered with.
|
||||
* @param chainIndex The index in the chain to start unregistering.
|
||||
*/
|
||||
protected void unregisterEventsSafe(Object object, int chainIndex) {
|
||||
Monitor monitor = getMonitor();
|
||||
|
||||
lock(monitor);
|
||||
|
||||
try {
|
||||
internalUnregisterEventsSafe(object, chainIndex);
|
||||
}//try//
|
||||
finally {
|
||||
unlock(monitor);
|
||||
}//finally//
|
||||
}//unregisterEventsSafe()//
|
||||
/**
|
||||
* Unregisters recursively for the events starting at the given chain index.
|
||||
* <p>This is the thread safe version of this method.</p>
|
||||
* @param object The object to be unregistered with.
|
||||
* @param chainIndex The index in the chain to start unregistering.
|
||||
*/
|
||||
private void internalUnregisterEventsSafe(Object object, int chainIndex) {
|
||||
if(chainIndex == -1) {
|
||||
if(object instanceof IManagedCollection) { //TODO: Allow the user to specify whether collection items are added, or the collection its self is added.//
|
||||
IManagedCollection collection = (IManagedCollection) object;
|
||||
LiteList items = null;
|
||||
Monitor monitor = collection.getMonitor();
|
||||
|
||||
lock(monitor);
|
||||
|
||||
try {
|
||||
//Save the current set of items so we can register them outside the synchronization.//
|
||||
items = new LiteList(collection);
|
||||
//Stop listening for the collection contents chainging.//
|
||||
collection.unregisterListener(IManagedCollection.EVENT, collectionLinks[collectionLinks.length - 1]);
|
||||
}//try//
|
||||
finally {
|
||||
unlock(monitor);
|
||||
}//finally//
|
||||
|
||||
removeAll(items, CONTEXT_TRUSTED);
|
||||
}//if//
|
||||
else {
|
||||
remove(object, CONTEXT_TRUSTED);
|
||||
}//else//
|
||||
}//if//
|
||||
else if(object instanceof IEntity) {
|
||||
IEntity entity = (IEntity) object;
|
||||
IReference reference = referenceChain[chainIndex];
|
||||
Object value = null;
|
||||
Monitor monitor = entity.getMonitor();
|
||||
|
||||
lock(monitor);
|
||||
|
||||
try {
|
||||
//Unregister an event to receive change notification.//
|
||||
reference.unregisterChangeHandler(entity, referenceLinks[chainIndex]);
|
||||
//Get the current value for the reference.//
|
||||
value = reference.getValue(entity);
|
||||
}//try//
|
||||
finally {
|
||||
unlock(monitor);
|
||||
}//finally//
|
||||
|
||||
//Register outside the synchronization block for events down the chain.//
|
||||
internalUnregisterEventsSafe(value, chainIndex < referenceChain.length ? chainIndex + 1 : -1);
|
||||
}//else if//
|
||||
else if(object instanceof IManagedCollection) {
|
||||
IManagedCollection collection = (IManagedCollection) object;
|
||||
LiteList items = null;
|
||||
Monitor monitor = collection.getMonitor();
|
||||
|
||||
lock(monitor);
|
||||
|
||||
try {
|
||||
//Save the current set of items so we can register them outside the synchronization.//
|
||||
items = new LiteList(collection);
|
||||
//Stop listening for the collection contents chainging.//
|
||||
collection.unregisterListener(IManagedCollection.EVENT, collectionLinks[chainIndex]);
|
||||
}//try//
|
||||
finally {
|
||||
unlock(monitor);
|
||||
}//finally//
|
||||
|
||||
//Unregister all the collection items.//
|
||||
for(int index = 0; index < items.getSize(); index++) {
|
||||
internalUnregisterEventsSafe(items.get(index), chainIndex);
|
||||
}//while//
|
||||
}//else if//
|
||||
else {
|
||||
//TODO: Should we just ignore this, or throw an error?//
|
||||
Debug.log("Warning: The list aggregator encountered an unknown object type in the chain.");
|
||||
}//else//
|
||||
}//internalUnregisterEventsSafe()//
|
||||
/**
|
||||
* Unregisters all events.
|
||||
*/
|
||||
public void release() {
|
||||
if(isThreadSafe) {
|
||||
unregisterEvents(parent, 0);
|
||||
}//if//
|
||||
else {
|
||||
unregisterEventsSafe(parent, 0);
|
||||
}//else//
|
||||
}//release()//
|
||||
}//ListAggregator//
|
||||
39
Foundation/src/com/foundation/util/ListManager.java
Normal file
39
Foundation/src/com/foundation/util/ListManager.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
/**
|
||||
* A simple implementation of the IListManager interface.
|
||||
* Applications are encouraged to extend this class to provide application specific changes.
|
||||
*/
|
||||
public class ListManager extends IndexedCollectionManager {
|
||||
public static final ListManager DEFAULT_MANAGER = new ListManager();
|
||||
/**
|
||||
* ListManager constructor.
|
||||
*/
|
||||
public ListManager() {
|
||||
super();
|
||||
}//ListManager()//
|
||||
/**
|
||||
* Reads the collection manager from a stream.
|
||||
* @param in The input stream to deserialize from.
|
||||
*/
|
||||
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
|
||||
/*byte version = */in.readByte();
|
||||
|
||||
super.readExternal(in);
|
||||
}//readExternal()//
|
||||
/**
|
||||
* Writes the collection manager to the stream.
|
||||
* @param out The output stream to serialize to.
|
||||
*/
|
||||
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
|
||||
out.writeByte(0);
|
||||
super.writeExternal(out);
|
||||
}//writeExternal()//
|
||||
}//ListManager//
|
||||
1942
Foundation/src/com/foundation/util/ManagedCollection.java
Normal file
1942
Foundation/src/com/foundation/util/ManagedCollection.java
Normal file
File diff suppressed because it is too large
Load Diff
1253
Foundation/src/com/foundation/util/ManagedHashSet.java
Normal file
1253
Foundation/src/com/foundation/util/ManagedHashSet.java
Normal file
File diff suppressed because it is too large
Load Diff
1741
Foundation/src/com/foundation/util/ManagedIndexedCollection.java
Normal file
1741
Foundation/src/com/foundation/util/ManagedIndexedCollection.java
Normal file
File diff suppressed because it is too large
Load Diff
2566
Foundation/src/com/foundation/util/ManagedList.java
Normal file
2566
Foundation/src/com/foundation/util/ManagedList.java
Normal file
File diff suppressed because it is too large
Load Diff
1311
Foundation/src/com/foundation/util/ManagedNonIndexedCollection.java
Normal file
1311
Foundation/src/com/foundation/util/ManagedNonIndexedCollection.java
Normal file
File diff suppressed because it is too large
Load Diff
221
Foundation/src/com/foundation/util/ObservableAggregator.java
Normal file
221
Foundation/src/com/foundation/util/ObservableAggregator.java
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (c) 2006,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.thread.Monitor;
|
||||
import com.common.thread.ThreadService;
|
||||
import com.common.util.ICollection;
|
||||
import com.common.util.LiteHashMap;
|
||||
import com.common.util.LiteList;
|
||||
import com.foundation.util.Updater.UpdaterRunnable;
|
||||
|
||||
/**
|
||||
* This base class provides functionality for aggregators of zero or more observable collections.
|
||||
*/
|
||||
public abstract class ObservableAggregator {
|
||||
/** The number of times the startChanges() method has been called. This allows multiple threads to notify this aggregator of changes at the same time. */
|
||||
protected int changeStartCounter = 0;
|
||||
/** The set of listeners indexed by the collection they are listening to. */
|
||||
private LiteHashMap listenersByCollectionMap = new LiteHashMap(10);
|
||||
|
||||
/**
|
||||
* An instance of Listener should be created for each collection being listened to - each collection that makes up the aggregate collection.
|
||||
*/
|
||||
private class Listener implements IInlineCollectionObserver {
|
||||
/** The collection being listened to. */
|
||||
private IInlineCollectionObservable collection = null;
|
||||
/** A collection used to temporarily collect items being added to the aggregate collection. */
|
||||
protected LiteList addedItems = null;
|
||||
/** A collection used to temporarily collect items being removed from the aggregate collection. */
|
||||
protected LiteList removedItems = null;
|
||||
|
||||
/**
|
||||
* Listener constructor.
|
||||
* @param collection The collection being listened to.
|
||||
*/
|
||||
public Listener(IInlineCollectionObservable collection) {
|
||||
this.collection = collection;
|
||||
}//Listener()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.IInlineCollectionObserver#removingAll()
|
||||
*/
|
||||
public void removingAll() {
|
||||
removedItems.addAll(collection.getCollection());
|
||||
}//removingAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.IInlineCollectionObserver#valueAdded(java.lang.Object)
|
||||
*/
|
||||
public void valueAdded(Object value) {
|
||||
if(addedItems != null) {
|
||||
addedItems.add(value);
|
||||
}//if//
|
||||
else {
|
||||
final Object added = value;
|
||||
|
||||
applyChange(new Runnable() {
|
||||
public void run() {
|
||||
applyAddChange(added);
|
||||
}//run()//
|
||||
});
|
||||
}//else//
|
||||
}//valueAdded()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.IInlineCollectionObserver#valueRemoved(java.lang.Object)
|
||||
*/
|
||||
public void valueRemoved(Object value) {
|
||||
if(removedItems != null) {
|
||||
removedItems.add(value);
|
||||
}//if//
|
||||
else {
|
||||
final Object removed = value;
|
||||
|
||||
applyChange(new Runnable() {
|
||||
public void run() {
|
||||
applyRemoveChange(removed);
|
||||
}//run()//
|
||||
});
|
||||
}//else//
|
||||
}//valueRemoved()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.IInlineCollectionObserver#startChanges(int)
|
||||
*/
|
||||
public void startChanges(int changeCount) {
|
||||
changeStartCounter++;
|
||||
addedItems = new LiteList(changeCount);
|
||||
removedItems = new LiteList(changeCount);
|
||||
}//startChanges()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.IInlineCollectionObserver#stopChanges()
|
||||
*/
|
||||
public void stopChanges() {
|
||||
if(--changeStartCounter == 0) {
|
||||
final LiteList addedItems = this.addedItems;
|
||||
final LiteList removedItems = this.removedItems;
|
||||
|
||||
this.addedItems = null;
|
||||
this.removedItems = null;
|
||||
//Apply the changes.//
|
||||
applyChange(new Runnable() {
|
||||
public void run() {
|
||||
applyChanges(addedItems, removedItems);
|
||||
}//run()//
|
||||
});
|
||||
}//if//
|
||||
}//stopChanges()//
|
||||
}//Listener//
|
||||
/**
|
||||
* ObservableAggregator constructor.
|
||||
*/
|
||||
public ObservableAggregator() {
|
||||
super();
|
||||
}//ObservableAggregator()//
|
||||
/**
|
||||
* Releases the aggregator and stops all listeners.
|
||||
* <p>Warning: Failure to call this method may result in memory leaks and wasted cycles.</p>
|
||||
*/
|
||||
public void release() {
|
||||
IInlineCollectionObservable[] collections = new IInlineCollectionObservable[listenersByCollectionMap.getSize()];
|
||||
|
||||
listenersByCollectionMap.toKeyArray(collections);
|
||||
|
||||
for(int index = 0; index < collections.length; index++) {
|
||||
removeCollection(collections[index]);
|
||||
}//for//
|
||||
}//release()//
|
||||
/**
|
||||
* Adds the collection to this aggregator.
|
||||
* @param collection The collection to be added.
|
||||
*/
|
||||
public void addCollection(IInlineCollectionObservable collection) {
|
||||
Monitor monitor = collection.getMonitor();
|
||||
|
||||
Monitor.lock(monitor);
|
||||
|
||||
try {
|
||||
if(listenersByCollectionMap.containsKey(collection)) {
|
||||
//Cannot add a collection twice.//
|
||||
throw new IllegalArgumentException();
|
||||
}//if//
|
||||
|
||||
Listener listener = new Listener(collection);
|
||||
|
||||
collection.addCollectionObserver(listener);
|
||||
listenersByCollectionMap.put(collection, listener);
|
||||
}//try//
|
||||
finally {
|
||||
Monitor.unlock(monitor);
|
||||
}//finally//
|
||||
}//addCollection()//
|
||||
/**
|
||||
* Removes the collection from this aggregator.
|
||||
* @param collection The collection to be removed.
|
||||
*/
|
||||
public void removeCollection(IInlineCollectionObservable collection) {
|
||||
Monitor monitor = collection.getMonitor();
|
||||
|
||||
Monitor.lock(monitor);
|
||||
|
||||
try {
|
||||
Listener listener = (Listener) listenersByCollectionMap.get(collection);
|
||||
|
||||
if(listener != null) {
|
||||
collection.removeCollectionObserver(listener);
|
||||
}//if//
|
||||
else {
|
||||
//Cannot remove a collection not previously added.//
|
||||
throw new IllegalArgumentException();
|
||||
}//else//
|
||||
}//try//
|
||||
finally {
|
||||
Monitor.unlock(monitor);
|
||||
}//finally//
|
||||
}//removeCollection()//
|
||||
/**
|
||||
* Applies the changes represented by the runnable that will enact the changes.
|
||||
* @param runnable The object run to apply the changes.
|
||||
*/
|
||||
private void applyChange(final Runnable runnable) {
|
||||
if(getAggregateMonitor() != null && !ThreadService.getIsSingleThreadedContext()) {
|
||||
Updater.getSingleton().run(new UpdaterRunnable() {
|
||||
public void run() {
|
||||
runnable.run();
|
||||
}//run()//
|
||||
public Monitor getMonitor() {
|
||||
return getAggregateMonitor();
|
||||
}//getMonitor()//
|
||||
});
|
||||
}//if//
|
||||
else {
|
||||
runnable.run();
|
||||
}//else//
|
||||
}//applyChange()//
|
||||
/**
|
||||
* Gets the monitor for the aggregate.
|
||||
* @return The monitor used to lock the aggregate collection as changes get applied.
|
||||
*/
|
||||
protected abstract Monitor getAggregateMonitor();
|
||||
/**
|
||||
* Requests that the added and removed items are applied to the aggregate collection.
|
||||
* The caller will have already locked on the aggregate's monitor.
|
||||
* @param addedItems The items to be added.
|
||||
* @param removedItems The items to be removed.
|
||||
*/
|
||||
protected abstract void applyChanges(ICollection addedItems, ICollection removedItems);
|
||||
/**
|
||||
* Requests that the item be added to the aggregate collection.
|
||||
* The caller will have already locked on the aggregate's monitor.
|
||||
* @param item The item to be added.
|
||||
*/
|
||||
protected abstract void applyAddChange(Object item);
|
||||
/**
|
||||
* Requests that the item be removed from the aggregate collection.
|
||||
* The caller will have already locked on the aggregate's monitor.
|
||||
* @param item The item to be removed.
|
||||
*/
|
||||
protected abstract void applyRemoveChange(Object item);
|
||||
}//ObservableAggregator//
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.thread.Monitor;
|
||||
import com.common.util.*;
|
||||
|
||||
/*
|
||||
* Maintains a list of items in zero or more collections.
|
||||
* The collections will be listened to for changes which will update the aggregate managed list.
|
||||
*/
|
||||
public class ObservableAggregatorList extends ObservableAggregator {
|
||||
/** The list containing all the registered collection's items. */
|
||||
private IManagedList aggregate;
|
||||
/**
|
||||
* ObservableAggregatorList constructor.
|
||||
*/
|
||||
public ObservableAggregatorList() {
|
||||
super();
|
||||
this.aggregate = new ManagedList(25);
|
||||
}//ObservableAggregatorList()//
|
||||
/**
|
||||
* ObservableAggregatorList constructor.
|
||||
* @param aggregate The list that will serve as the container for the aggregated collections.
|
||||
*/
|
||||
public ObservableAggregatorList(IManagedList aggregate) {
|
||||
super();
|
||||
this.aggregate = aggregate;
|
||||
}//ObservableAggregatorList()//
|
||||
/**
|
||||
* Gets the aggregate collection.
|
||||
* @return The collection that will always contain the most up to date items from all added lists.
|
||||
*/
|
||||
public IManagedList getAggregate() {
|
||||
return aggregate;
|
||||
}//getAggregate()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.ObservableAggregator#applyAddChange(java.lang.Object)
|
||||
*/
|
||||
protected void applyAddChange(Object item) {
|
||||
aggregate.add(item);
|
||||
}//applyAddChange()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.ObservableAggregator#applyRemoveChange(java.lang.Object)
|
||||
*/
|
||||
protected void applyRemoveChange(Object item) {
|
||||
aggregate.remove(item);
|
||||
}//applyRemoveChange()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.ObservableAggregator#applyChanges(com.common.util.ICollection, com.common.util.ICollection)
|
||||
*/
|
||||
protected void applyChanges(final ICollection addedItems, final ICollection removedItems) {
|
||||
aggregate.execute(new IManagedCollection.ICollectionOperation() {
|
||||
public void run(ManagedCollection collection) {
|
||||
if(addedItems != null) {
|
||||
aggregate.addAll(addedItems);
|
||||
}//if//
|
||||
|
||||
if(removedItems != null) {
|
||||
aggregate.removeAll(removedItems);
|
||||
}//if//
|
||||
}//run()//
|
||||
});
|
||||
}//applyChanges()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.ObservableAggregator#getAggregateMonitor()
|
||||
*/
|
||||
protected Monitor getAggregateMonitor() {
|
||||
return aggregate.getMonitor();
|
||||
}//getAggregateMonitor()//
|
||||
}//ManagedCollectionAggregator//
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.comparison.Comparator;
|
||||
import com.common.comparison.IComparator;
|
||||
import com.common.thread.Monitor;
|
||||
import com.common.util.*;
|
||||
|
||||
/*
|
||||
* Maintains a set of items in zero or more collections.
|
||||
* The collections will be listened to for changes which will update the aggregate hash set.
|
||||
*/
|
||||
public class ObservableAggregatorSet extends ObservableAggregator {
|
||||
/** The set containing all the registered collection's items. */
|
||||
private ManagedHashSet aggregate;
|
||||
/**
|
||||
* ObservableAggregatorSet constructor.
|
||||
*/
|
||||
public ObservableAggregatorSet() {
|
||||
this(Comparator.getIdentityComparator());
|
||||
}//ObservableAggregatorSet()//
|
||||
/**
|
||||
* ObservableAggregatorSet constructor.
|
||||
* @param comparator The comparator used by the set of values.
|
||||
*/
|
||||
public ObservableAggregatorSet(IComparator comparator) {
|
||||
super();
|
||||
this.aggregate = new ManagedHashSet(25, ManagedHashSet.DEFAULT_LOAD_FACTOR, comparator, ManagedHashSet.STYLE_COUNT_DUPLICATES);
|
||||
}//ObservableAggregatorSet()//
|
||||
/**
|
||||
* ObservableAggregatorSet constructor.
|
||||
* @param aggregate The set that will contain the aggregated data.
|
||||
*/
|
||||
public ObservableAggregatorSet(ManagedHashSet aggregate) {
|
||||
super();
|
||||
|
||||
if(aggregate.getStyle() == ManagedHashSet.STYLE_NO_DUPLICATES) {
|
||||
throw new IllegalArgumentException("Cannot disallow duplicates in the aggregate set.");
|
||||
}//if//
|
||||
|
||||
this.aggregate = aggregate;
|
||||
}//ObservableAggregatorSet()//
|
||||
/**
|
||||
* Gets the aggregate collection.
|
||||
* @return The collection that will always contain the most up to date items from all added lists.
|
||||
*/
|
||||
public IHashSet getAggregate() {
|
||||
return aggregate;
|
||||
}//getAggregate()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.ObservableAggregator#applyAddChange(java.lang.Object)
|
||||
*/
|
||||
protected void applyAddChange(Object item) {
|
||||
aggregate.add(item);
|
||||
}//applyAddChange()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.ObservableAggregator#applyRemoveChange(java.lang.Object)
|
||||
*/
|
||||
protected void applyRemoveChange(Object item) {
|
||||
aggregate.remove(item);
|
||||
}//applyRemoveChange()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.ObservableAggregator#applyChanges(com.common.util.ICollection, com.common.util.ICollection)
|
||||
*/
|
||||
protected void applyChanges(final ICollection addedItems, final ICollection removedItems) {
|
||||
aggregate.execute(new ManagedHashSet.ICollectionOperation() {
|
||||
public void run(ManagedHashSet collection) {
|
||||
if(addedItems != null) {
|
||||
aggregate.addAll(addedItems);
|
||||
}//if//
|
||||
|
||||
if(removedItems != null) {
|
||||
aggregate.removeAll(removedItems);
|
||||
}//if//
|
||||
}//run()//
|
||||
});
|
||||
}//applyChanges()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.ObservableAggregator#getAggregateMonitor()
|
||||
*/
|
||||
protected Monitor getAggregateMonitor() {
|
||||
return aggregate.getMonitor();
|
||||
}//getAggregateMonitor()//
|
||||
}//ManagedCollectionSetAggregator//
|
||||
471
Foundation/src/com/foundation/util/SoftHashMap.java
Normal file
471
Foundation/src/com/foundation/util/SoftHashMap.java
Normal file
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Copyright (c) 2003,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
|
||||
import com.common.comparison.*;
|
||||
import com.common.util.Map;
|
||||
import com.common.util.IList;
|
||||
import com.common.util.IHashMap;
|
||||
import com.common.util.IIterator;
|
||||
import com.common.util.IReversableIterator;
|
||||
import com.common.util.LiteList;
|
||||
|
||||
/**
|
||||
* TODO: Verify that containment is properly managed for collection values that support containment.
|
||||
*/
|
||||
public class SoftHashMap extends HashMap {
|
||||
private LiteList keys = null;
|
||||
private ReferenceQueue referenceQueue = new ReferenceQueue();
|
||||
|
||||
/**
|
||||
* The Entry wrappers the key/value pair.
|
||||
*/
|
||||
public static class Entry extends SoftReference implements Map.IBasicEntry {
|
||||
public int hash = 0;
|
||||
public Entry next = null;
|
||||
protected final Object key;
|
||||
|
||||
public Entry(int hash, Object key, Object value, ReferenceQueue referenceQueue) {
|
||||
super(value, referenceQueue);
|
||||
this.key = key;
|
||||
this.hash = hash;
|
||||
}//Entry()//
|
||||
public int getHash() {
|
||||
return hash;
|
||||
}//getHash()//
|
||||
public void setHash(int hash) {
|
||||
this.hash = hash;
|
||||
}//setHash()//
|
||||
public Map.IBasicEntry getNext() {
|
||||
return next;
|
||||
}//getNext()//
|
||||
public void setNext(Map.IBasicEntry next) {
|
||||
this.next = (Entry) next;
|
||||
}//setNext()//
|
||||
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
|
||||
throw new java.io.IOException("Not supported.");
|
||||
}//readExternal()//
|
||||
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
|
||||
throw new java.io.IOException("Not supported.");
|
||||
}//writeExternal()//
|
||||
public void rehash() {
|
||||
hash = createKeyHash();
|
||||
}//rehash()//
|
||||
public int createKeyHash() {
|
||||
return key.hashCode();
|
||||
}//createKeyHash()//
|
||||
public String toString() {
|
||||
return super.toString() + "\r\n\tKey: " + (key == NULL_KEY ? "null" : key.toString()) + "\r\n\tValue: " + Entry.this.get() + (next != null ? "\r\n\t" + next.toString() : "");
|
||||
}//toString()//
|
||||
}//BasicEntry//
|
||||
|
||||
public static class KeyIterator extends Iterator implements IReversableIterator {
|
||||
public KeyIterator(SoftHashMap hashMap) {
|
||||
super(hashMap);
|
||||
}//KeyIterator()//
|
||||
public Object next() {
|
||||
Object result = ((Entry) nextEntry()).key;
|
||||
|
||||
if(result == NULL_KEY) {
|
||||
result = null;
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//next()//
|
||||
public Object previous() {
|
||||
Object result = ((Entry) previousEntry()).key;
|
||||
|
||||
if(result == NULL_KEY) {
|
||||
result = null;
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//previous()//
|
||||
}//KeyIterator//
|
||||
|
||||
public static class ValueIterator extends Iterator implements IIterator {
|
||||
public ValueIterator(SoftHashMap hashMap) {
|
||||
super(hashMap);
|
||||
}//ValueIterator()//
|
||||
public Object next() {
|
||||
return ((Entry) nextEntry()).get();
|
||||
}//next()//
|
||||
public Object previous() {
|
||||
return ((Entry) previousEntry()).get();
|
||||
}//previous()//
|
||||
}//ValueIterator//
|
||||
/**
|
||||
* SoftHashMap constructor comment.
|
||||
*/
|
||||
protected SoftHashMap() {
|
||||
super();
|
||||
}
|
||||
/**
|
||||
* SoftHashMap constructor comment.
|
||||
* @param initialCapacity int
|
||||
*/
|
||||
public SoftHashMap(int initialCapacity) {
|
||||
super(initialCapacity);
|
||||
}
|
||||
/**
|
||||
* SoftHashMap constructor comment.
|
||||
* @param initialCapacity int
|
||||
* @param loadFactor float
|
||||
*/
|
||||
public SoftHashMap(int initialCapacity, float loadFactor) {
|
||||
super(initialCapacity, loadFactor);
|
||||
}
|
||||
/**
|
||||
* SoftHashMap constructor comment.
|
||||
* @param initialCapacity int
|
||||
* @param loadFactor float
|
||||
* @param keyComparator com.common.comparison.IComparator
|
||||
* @param valueComparator com.common.comparison.IComparator
|
||||
*/
|
||||
public SoftHashMap(int initialCapacity, float loadFactor, com.common.comparison.IComparator keyComparator, com.common.comparison.IComparator valueComparator) {
|
||||
super(initialCapacity, loadFactor, keyComparator, valueComparator);
|
||||
}
|
||||
/**
|
||||
* SoftHashMap constructor comment.
|
||||
* @param initialCapacity int
|
||||
* @param keyComparator com.common.comparison.IComparator
|
||||
* @param valueComparator com.common.comparison.IComparator
|
||||
*/
|
||||
public SoftHashMap(int initialCapacity, com.common.comparison.IComparator keyComparator, com.common.comparison.IComparator valueComparator) {
|
||||
super(initialCapacity, keyComparator, valueComparator);
|
||||
}
|
||||
/**
|
||||
* SoftHashMap constructor comment.
|
||||
* @param keyComparator com.common.comparison.IComparator
|
||||
* @param valueComparator com.common.comparison.IComparator
|
||||
*/
|
||||
public SoftHashMap(com.common.comparison.IComparator keyComparator, com.common.comparison.IComparator valueComparator) {
|
||||
super(keyComparator, valueComparator);
|
||||
}
|
||||
/**
|
||||
* SoftHashMap constructor.
|
||||
* @param map A hashmap to copy.
|
||||
*/
|
||||
public SoftHashMap(IHashMap map) {
|
||||
super(map.getSize() > 10 ? map.getSize() : 10, map.getLoadFactor());
|
||||
IIterator iterator = map.keyIterator();
|
||||
|
||||
//Iterate over the existing map's keys and put the key value pairs in this map.//
|
||||
while(iterator.hasNext()) {
|
||||
Object key = iterator.next();
|
||||
Object value = map.get(key);
|
||||
|
||||
put(key, value);
|
||||
}//while//
|
||||
}//SoftHashMap()//
|
||||
/**
|
||||
* SoftHashMap constructor.
|
||||
* @param map A hashmap to copy.
|
||||
*/
|
||||
public SoftHashMap(SoftHashMap map) {
|
||||
super(map.getSize() > 10 ? map.getSize() : 10, map.getLoadFactor(), map.getKeyComparator(), map.getValueComparator());
|
||||
IIterator iterator = map.keyIterator();
|
||||
|
||||
//Iterate over the existing map's keys and put the key value pairs in this map.//
|
||||
while(iterator.hasNext()) {
|
||||
Object key = iterator.next();
|
||||
Object value = map.get(key);
|
||||
|
||||
put(key, value);
|
||||
}//while//
|
||||
}//SoftHashMap()//
|
||||
/**
|
||||
* Determines whether the key exists in the map.
|
||||
* @param key The key to look for.
|
||||
* @return Will be <code>true</code> if the key is already in the map.
|
||||
*/
|
||||
public boolean containsKey(Object key) {
|
||||
sweep();
|
||||
|
||||
return get(key) != null;
|
||||
}//containsKey()//
|
||||
/**
|
||||
* Gets an object in the map by its' key.
|
||||
* @param key The key whose value should be retieved.
|
||||
* @return The value associated with the key. A <code>null</code> value will be returned only if the key was not found.
|
||||
*/
|
||||
public Object get(Object key) {
|
||||
//Ensure that null keys are valid.//
|
||||
if(key == null) {
|
||||
key = NULL_KEY;
|
||||
}//if//
|
||||
|
||||
Map.IBasicEntry[] entries = getEntries();
|
||||
int hash = getKeyComparator().hash(key);
|
||||
int index = (hash & 0x7FFFFFFF) % entries.length;
|
||||
|
||||
for(Entry entry = (Entry) entries[index]; entry != null; entry = (Entry) entry.next) {
|
||||
if((entry.hash == hash) && (Comparator.isEqual(getKeyComparator().compare(entry.key, key)))) {
|
||||
return entry.get();
|
||||
}//if//
|
||||
}//for//
|
||||
|
||||
return null;
|
||||
}//get()//
|
||||
/**
|
||||
* Gets the key at the given index.
|
||||
* <p>NOTE: This method is intended for use by the iterators and it is not advisable to use this method else where.
|
||||
* @param index The index in the list of keys.
|
||||
* @return The key at the given index.
|
||||
*/
|
||||
public Object getKey(int index) {
|
||||
sweep();
|
||||
|
||||
if(keys == null) {
|
||||
refreshKeys();
|
||||
}//if//
|
||||
|
||||
return keys.get(index);
|
||||
}//getKey()//
|
||||
/**
|
||||
* Gets the collection of all keys in the map.
|
||||
* @param keys A collection that will contain the keys.
|
||||
* @return The collection with the keys in it. This will be the same collection as the one passed if it is non-null.
|
||||
*/
|
||||
public IList getKeys(IList keys) {
|
||||
sweep();
|
||||
|
||||
if(this.keys == null) {
|
||||
refreshKeys();
|
||||
}//if//
|
||||
|
||||
if(keys == null) {
|
||||
keys = new LiteList(this.keys.getSize(), 10);
|
||||
}//if//
|
||||
|
||||
keys.addAll(this.keys);
|
||||
|
||||
return keys;
|
||||
}//getKeys()//
|
||||
/**
|
||||
* @link IMap.getSize()
|
||||
*/
|
||||
public int getSize() {
|
||||
sweep();
|
||||
|
||||
return super.getSize();
|
||||
}//getSize()//
|
||||
/**
|
||||
* Invalidates the collection of keys.
|
||||
* This should occur when a value is added/removed/changed in a way that invalidates the collection of keys.
|
||||
*/
|
||||
protected void invalidateKeys() {
|
||||
keys = null;
|
||||
}//invalidateKeys()//
|
||||
/**
|
||||
* Gets an iterator over the keys contained in this collection.
|
||||
* @return An iterator over the map keys.
|
||||
*/
|
||||
public IIterator keyIterator() {
|
||||
sweep();
|
||||
|
||||
return new KeyIterator(this);
|
||||
}//keyIterator()//
|
||||
/**
|
||||
* Places a key/value pair in the map.
|
||||
* The value can be retrieved later with the given key.
|
||||
* @param key The key that will be used to map the value.
|
||||
* @param value The value stored in map.
|
||||
* @return The value previously associated with the key.
|
||||
*/
|
||||
public Object put(Object key, Object value) {
|
||||
Object result = null;
|
||||
|
||||
//Ensure that null keys are valid.//
|
||||
if(key == null) {
|
||||
key = NULL_KEY;
|
||||
}//if//
|
||||
|
||||
sweep();
|
||||
|
||||
if(value == null) {
|
||||
//Remove the key if it exists because you cannot associate a key with a null value.//
|
||||
result = remove(key);
|
||||
}//if//
|
||||
else {
|
||||
Map.IBasicEntry[] entries = getEntries();
|
||||
int hash = getKeyComparator().hash(key);
|
||||
int index = (hash & 0x7FFFFFFF) % entries.length;
|
||||
Entry entry = null;
|
||||
Entry previous = null;
|
||||
|
||||
//Try to locate an existing value.//
|
||||
for(entry = (Entry) entries[index]; entry != null; previous = entry, entry = (Entry) entry.next) {
|
||||
if((entry.hash == hash) && (Comparator.isEqual(getKeyComparator().compare(entry.key, key)))) {
|
||||
Object oldValue = entry.get();
|
||||
|
||||
replaceEntry(index, previous, new Entry(hash, key, value, referenceQueue));
|
||||
|
||||
return oldValue;
|
||||
}//if//
|
||||
}//for//
|
||||
|
||||
//Determine if we need to re-hash.//
|
||||
if(resize(getSize() + 1)) {
|
||||
entries = getEntries();
|
||||
//Recalculate the insertion index if the map resized.//
|
||||
index = (hash & 0x7FFFFFFF) % entries.length;
|
||||
}//if//
|
||||
|
||||
//Create and add the new entry.//
|
||||
entry = new Entry(hash, key, value, referenceQueue);
|
||||
addEntry(index, entry);
|
||||
|
||||
if(keys != null) {
|
||||
keys.add(key); //Just add the key instead of invalidating the keys collection.//
|
||||
}//if//
|
||||
}//else//
|
||||
|
||||
if(result != null) {
|
||||
notifyCollectionObserversOnRemove(result);
|
||||
}//if//
|
||||
|
||||
if(value != null) {
|
||||
notifyCollectionObserversOnAdd(value);
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//put()//
|
||||
/**
|
||||
* Reads the array of entries from the stream.
|
||||
* @param in The input stream to read from.
|
||||
* @return The array of entries read from the stream.
|
||||
*/
|
||||
protected Map.IBasicEntry[] readEntries(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
|
||||
return (Map.IBasicEntry[]) in.readObject();
|
||||
}//readEntries()//
|
||||
/**
|
||||
* Recreates the collection of keys.
|
||||
*/
|
||||
protected void refreshKeys() {
|
||||
Map.IBasicEntry[] entries = getEntries();
|
||||
int index;
|
||||
Entry entry;
|
||||
|
||||
keys = new LiteList(getSize(), 20);
|
||||
|
||||
for(index = 0; index < entries.length; index++) {
|
||||
for(entry = (Entry) entries[index]; entry != null; entry = (Entry) entry.next) {
|
||||
Object key = entry.key;
|
||||
|
||||
if(key == NULL_KEY) {
|
||||
key = null;
|
||||
}//if//
|
||||
|
||||
keys.add(key);
|
||||
}//for//
|
||||
}//for//
|
||||
}//refreshKeys()//
|
||||
/**
|
||||
* Optimizes the collection of Entry objects to improve access time.
|
||||
* @param arrayLength The new length of the entry array.
|
||||
*/
|
||||
protected void rehash(int arrayLength) {
|
||||
super.rehash(arrayLength);
|
||||
//Invalidate the list of keys.//
|
||||
invalidateKeys();
|
||||
}//rehash()//
|
||||
/**
|
||||
* Removes a key/value pair from the map.
|
||||
* @param key The key that should be removed (with its' value) from the map.
|
||||
* @return Will be the value removed from map. A <code>null</code> value is returned if the key was not found.
|
||||
*/
|
||||
public Object remove(Object key) {
|
||||
//Ensure that null keys are valid.//
|
||||
if(key == null) {
|
||||
key = NULL_KEY;
|
||||
}//if//
|
||||
|
||||
Map.IBasicEntry[] entries = getEntries();
|
||||
int hash = getKeyComparator().hash(key);
|
||||
int index = (hash & 0x7FFFFFFF) % entries.length;
|
||||
Entry previousEntry = null;
|
||||
Entry entry = null;
|
||||
Object result = null;
|
||||
|
||||
sweep();
|
||||
|
||||
//Iterate through the entries stored at the key's hash location and remove the given key.//
|
||||
for(entry = (Entry) entries[index]; entry != null; entry = (Entry) entry.next) {
|
||||
if((entry.hash == hash) && (Comparator.isEqual(getKeyComparator().compare(entry.key, key)))) {
|
||||
//Save the removed value.//
|
||||
result = entry.get();
|
||||
//Remove the entry from the map.//
|
||||
removeEntry(index, previousEntry);
|
||||
//Could find the key in the collection and remove it, but that may take to long.//
|
||||
invalidateKeys();
|
||||
//Break from the loop so we can exit.//
|
||||
break;
|
||||
}//if//
|
||||
|
||||
previousEntry = entry;
|
||||
}//for//
|
||||
|
||||
if(result != null) {
|
||||
notifyCollectionObserversOnRemove(result);
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//remove()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.HashMap#removeAll()
|
||||
*/
|
||||
public void removeAll() {
|
||||
notifyCollectionObserversOnRemovingAll();
|
||||
sweep();
|
||||
invalidateKeys();
|
||||
removeAllEntries();
|
||||
}//removeAll()//
|
||||
/**
|
||||
* Sweeps up old map entries that no longer reference values.
|
||||
*/
|
||||
protected void sweep() {
|
||||
Entry entry = null;
|
||||
|
||||
while((entry = (Entry) referenceQueue.poll()) != null) {
|
||||
remove(entry.key);
|
||||
}//while//
|
||||
}//sweep()//
|
||||
/**
|
||||
* Gets the collection of all keys in the map.
|
||||
* @param keys An array of the necessary type to old the key values.
|
||||
* @return The collection with the keys in it. This will be the same collection as the one passed if it is non-null.
|
||||
*/
|
||||
public int toKeyArray(Object keyArray) {
|
||||
sweep();
|
||||
|
||||
if(keys == null) {
|
||||
refreshKeys();
|
||||
}//if//
|
||||
|
||||
return keys.toArray(keyArray);
|
||||
}//toKeyArray()//
|
||||
/**
|
||||
* Gets an iterator over the values contained in this collection.
|
||||
* @return An iterator over the map values.
|
||||
*/
|
||||
public IIterator valueIterator() {
|
||||
return new ValueIterator(this);
|
||||
}//valueIterator()//
|
||||
/**
|
||||
* Writes the array of entries to the stream.
|
||||
* @param out The output stream to write to.
|
||||
* @param entries The array of entries to be written to the stream.
|
||||
*/
|
||||
protected void writeEntries(java.io.ObjectOutput out, Map.IBasicEntry[] entries) throws java.io.IOException {
|
||||
out.writeObject(entries);
|
||||
}//writeEntries()//
|
||||
}//SoftHashMap//
|
||||
1139
Foundation/src/com/foundation/util/Tree.java
Normal file
1139
Foundation/src/com/foundation/util/Tree.java
Normal file
File diff suppressed because it is too large
Load Diff
178
Foundation/src/com/foundation/util/TreeCollectionManager.java
Normal file
178
Foundation/src/com/foundation/util/TreeCollectionManager.java
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) 2005,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.util.ICollection;
|
||||
import com.common.util.IIterator;
|
||||
import com.common.util.ITree;
|
||||
|
||||
public class TreeCollectionManager extends CollectionManager {
|
||||
/**
|
||||
* TreeCollectionManager constructor.
|
||||
*/
|
||||
public TreeCollectionManager() {
|
||||
super();
|
||||
}//TreeCollectionManager()//
|
||||
/**
|
||||
* Determines whether the value can be added to the tree under the given parent.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param parent The parent item for the new value.
|
||||
* @param value The value that may be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether the value can be added to the collection.
|
||||
*/
|
||||
public boolean canAdd(IManagedCollection managed, Object parent, Object value, byte context) {
|
||||
return true;
|
||||
}//canAdd()//
|
||||
/**
|
||||
* Determines whether the values can be added to the tree under the given parent.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param parent The parent item for the new values.
|
||||
* @param values The values that may be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether the values can be added to the collection.
|
||||
*/
|
||||
public boolean canAddAll(IManagedCollection managed, Object parent, Object[] values, byte context) {
|
||||
boolean retVal = true;
|
||||
|
||||
for(int index = 0; (index < values.length) && (retVal); index++) {
|
||||
retVal = canAdd(managed, parent, values[index], context);
|
||||
}//for//
|
||||
|
||||
return retVal;
|
||||
}//canAddAll()//
|
||||
/**
|
||||
* Determines whether the values can be added to the tree under the given parent.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param parent The parent item for the new values.
|
||||
* @param values The values that may be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether the values can be added to the collection.
|
||||
*/
|
||||
public boolean canAddAll(IManagedCollection managed, Object parent, ICollection values, byte context) {
|
||||
boolean retVal = true;
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
while((retVal) && (iterator.hasNext())) {
|
||||
retVal = canAdd(managed, parent, iterator.next(), context);
|
||||
}//while//
|
||||
|
||||
return retVal;
|
||||
}//canAddAll()//
|
||||
/**
|
||||
* Determines whether the tree of values can be added to the tree under the given parent.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param parent The parent item for the new values.
|
||||
* @param values The values that may be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
* @return Whether the values can be added to the collection.
|
||||
*/
|
||||
public boolean canAddAll(IManagedCollection managed, Object parent, ITree values, byte context) {
|
||||
return true;
|
||||
}//canAddAll()//
|
||||
/**
|
||||
* Allows the manager to provide functionality after a value has been added to the tree.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param parent The parent item for the new value.
|
||||
* @param value The value that has be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
*/
|
||||
public void postAdd(IManagedCollection managed, Object parent, Object value, byte context) {
|
||||
postAdd(managed, value, context);
|
||||
}//postAdd()//
|
||||
/**
|
||||
* Allows the manager to provide functionality after values are added to the tree.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param parent The parent item for the new values.
|
||||
* @param values The values that have been added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
*/
|
||||
public void postAddAll(IManagedCollection managed, Object parent, Object[] values, byte context) {
|
||||
for(int index = 0; index < values.length; index++) {
|
||||
postAdd(managed, parent, values[index], context);
|
||||
}//for//
|
||||
}//postAddAll()//
|
||||
/**
|
||||
* Allows the manager to pprovide functionality after values are added to the tree.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param parent The parent item for the new values.
|
||||
* @param values The values that have been added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
*/
|
||||
public void postAddAll(IManagedCollection managed, Object parent, ICollection values, byte context) {
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
postAdd(managed, parent, iterator.next(), context);
|
||||
}//while//
|
||||
}//postAddAll()//
|
||||
/**
|
||||
* Allows the manager to pprovide functionality after values are added to the tree.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param parent The parent item for the new values.
|
||||
* @param values The tree of values that have been added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
*/
|
||||
public void postAddAll(IManagedCollection managed, Object parent, ITree values, byte context) {
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
postAdd(managed, parent, iterator.next(), context);
|
||||
}//while//
|
||||
}//postAddAll()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to the value being added to the tree.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param parent The parent item for the new value.
|
||||
* @param value The value that will be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
*/
|
||||
public void preAdd(IManagedCollection managed, Object parent, Object value, byte context) {
|
||||
preAdd(managed, value, context);
|
||||
}//preAdd()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to the values being added to the tree.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param parent The parent item for the new values.
|
||||
* @param values The values that will be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
*/
|
||||
public void preAddAll(IManagedCollection managed, Object parent, Object[] values, byte context) {
|
||||
for(int index = 0; index < values.length; index++) {
|
||||
preAdd(managed, parent, values[index], context);
|
||||
}//for//
|
||||
}//preAddAll()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to the values being added to the tree.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param parent The parent item for the new values.
|
||||
* @param values The values that will be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
*/
|
||||
public void preAddAll(IManagedCollection managed, Object parent, ICollection values, byte context) {
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
preAdd(managed, parent, iterator.next(), context);
|
||||
}//while//
|
||||
}//preAddAll()//
|
||||
/**
|
||||
* Allows the manager to provide functionality prior to the values being added to the tree.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param parent The parent item for the new values.
|
||||
* @param values The tree of values that will be added.
|
||||
* @param context The context underwhich the operation is occuring.
|
||||
*/
|
||||
public void preAddAll(IManagedCollection managed, Object parent, ITree values, byte context) {
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
preAdd(managed, parent, iterator.next(), context);
|
||||
}//while//
|
||||
}//preAddAll()//
|
||||
}//TreeCollectionManager//
|
||||
122
Foundation/src/com/foundation/util/Updater.java
Normal file
122
Foundation/src/com/foundation/util/Updater.java
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util;
|
||||
|
||||
import com.common.debug.Debug;
|
||||
import com.common.thread.Monitor;
|
||||
import com.common.thread.ThreadService;
|
||||
import com.common.util.LiteList;
|
||||
|
||||
/**
|
||||
* Used to queue changes to the adapter and aggregator collections and execute them on a separate thread when operating in a multi-threaded environment.
|
||||
*/
|
||||
public class Updater implements Runnable {
|
||||
private static final Updater singleton = new Updater();
|
||||
private LiteList queue = new LiteList(10, 40);
|
||||
private boolean isRunning = false;
|
||||
|
||||
public static abstract class UpdaterRunnable implements Runnable {
|
||||
/** UpdaterRunnable constructor. */
|
||||
public UpdaterRunnable() {
|
||||
}//UpdaterRunnable()//
|
||||
/** Used to link runnables that use the same monitor. */
|
||||
public UpdaterRunnable next = null;
|
||||
/** Gets the monitor for the updater. */
|
||||
public abstract Monitor getMonitor();
|
||||
}//UpdaterRunnable//
|
||||
|
||||
/**
|
||||
* Gets the one and only instance of the Updater class.
|
||||
* @return The only instance of this class.
|
||||
*/
|
||||
public static Updater getSingleton() {
|
||||
return singleton;
|
||||
}//getSingleton()//
|
||||
/**
|
||||
* Queues and runs an update runnable such that the update occurs in order.
|
||||
* @param runnable
|
||||
*/
|
||||
public synchronized void run(UpdaterRunnable runnable) {
|
||||
boolean linked = false;
|
||||
|
||||
//Link runnables together that use the same monitor.//
|
||||
if(queue.getSize() > 0) {
|
||||
Monitor monitor = runnable.getMonitor();
|
||||
|
||||
for(int index = queue.getSize() - 1; index >= 0 && !linked; index--) {
|
||||
UpdaterRunnable next = (UpdaterRunnable) queue.get(index);
|
||||
|
||||
if(next.next == null && next.getMonitor() == monitor) {
|
||||
next.next = runnable;
|
||||
linked = true;
|
||||
}//if//
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
runnable.next = null;
|
||||
|
||||
if(!linked) {
|
||||
queue.add(runnable);
|
||||
}//if//
|
||||
|
||||
if(!isRunning) {
|
||||
isRunning = true;
|
||||
ThreadService.run(this);
|
||||
}//if//
|
||||
}//run()//
|
||||
/**
|
||||
* Not to be called externally.
|
||||
*/
|
||||
public void run() {
|
||||
UpdaterRunnable runnable = null;
|
||||
Monitor monitor = null;
|
||||
boolean running = true;
|
||||
|
||||
//Get the initial queued runnable.//
|
||||
synchronized(this) {
|
||||
runnable = (UpdaterRunnable) queue.remove(0);
|
||||
}//synchronized//
|
||||
|
||||
//Keep running stuff from the queue until there isn't any more.//
|
||||
while(running) {
|
||||
monitor = runnable.getMonitor();
|
||||
|
||||
if(monitor != null) {
|
||||
Monitor.lock(monitor);
|
||||
}//if//
|
||||
|
||||
try {
|
||||
//Run the chain of runnables that all use the same monitor.//
|
||||
while(runnable != null) {
|
||||
try {
|
||||
runnable.run();
|
||||
}//try//
|
||||
catch(Throwable e) {
|
||||
Debug.log(e);
|
||||
}//catch//
|
||||
|
||||
runnable = runnable.next;
|
||||
}//while//
|
||||
}//try//
|
||||
finally {
|
||||
Monitor.unlock(monitor);
|
||||
}//finally//
|
||||
|
||||
//Get the next queued runnable or stop the loop and release the thread.//
|
||||
synchronized(this) {
|
||||
if(queue.getSize() > 0) {
|
||||
runnable = (UpdaterRunnable) queue.remove(0);
|
||||
}//if//
|
||||
else {
|
||||
isRunning = false;
|
||||
running = false;
|
||||
}//else//
|
||||
}//synchronized//
|
||||
}//while//
|
||||
}//run()//
|
||||
}//Updater//
|
||||
846
Foundation/src/com/foundation/util/json/JSONArray.java
Normal file
846
Foundation/src/com/foundation/util/json/JSONArray.java
Normal file
@@ -0,0 +1,846 @@
|
||||
package com.foundation.util.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A JSONArray is an ordered sequence of values. Its external text form is a
|
||||
* string wrapped in square brackets with commas separating the values. The
|
||||
* internal form is an object having <code>get</code> and <code>opt</code>
|
||||
* methods for accessing the values by index, and <code>put</code> methods for
|
||||
* adding or replacing values. The values can be any of these types:
|
||||
* <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>,
|
||||
* <code>Number</code>, <code>String</code>, or the
|
||||
* <code>JSONObject.NULL object</code>.
|
||||
* <p>
|
||||
* The constructor can convert a JSON text into a Java object. The
|
||||
* <code>toString</code> method converts to JSON text.
|
||||
* <p>
|
||||
* A <code>get</code> method returns a value if one can be found, and throws an
|
||||
* exception if one cannot be found. An <code>opt</code> method returns a
|
||||
* default value instead of throwing an exception, and so is useful for
|
||||
* obtaining optional values.
|
||||
* <p>
|
||||
* The generic <code>get()</code> and <code>opt()</code> methods return an
|
||||
* object which you can cast or query for type. There are also typed
|
||||
* <code>get</code> and <code>opt</code> methods that do type checking and type
|
||||
* coercion for you.
|
||||
* <p>
|
||||
* The texts produced by the <code>toString</code> methods strictly conform to
|
||||
* JSON syntax rules. The constructors are more forgiving in the texts they will
|
||||
* accept:
|
||||
* <ul>
|
||||
* <li>An extra <code>,</code> <small>(comma)</small> may appear just
|
||||
* before the closing bracket.</li>
|
||||
* <li>The <code>null</code> value will be inserted when there is <code>,</code>
|
||||
* <small>(comma)</small> elision.</li>
|
||||
* <li>Strings may be quoted with <code>'</code> <small>(single
|
||||
* quote)</small>.</li>
|
||||
* <li>Strings do not need to be quoted at all if they do not begin with a quote
|
||||
* or single quote, and if they do not contain leading or trailing spaces, and
|
||||
* if they do not contain any of these characters:
|
||||
* <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers and
|
||||
* if they are not the reserved words <code>true</code>, <code>false</code>, or
|
||||
* <code>null</code>.</li>
|
||||
* <li>Values can be separated by <code>;</code> <small>(semicolon)</small> as
|
||||
* well as by <code>,</code> <small>(comma)</small>.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2012-04-20
|
||||
*/
|
||||
public class JSONArray {
|
||||
/** The arrayList where the JSONArray's properties are kept. */
|
||||
private final ArrayList myArrayList;
|
||||
/**
|
||||
* Construct an empty JSONArray.
|
||||
*/
|
||||
public JSONArray() {
|
||||
this.myArrayList = new ArrayList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from a JSONTokener.
|
||||
* @param x A JSONTokener
|
||||
* @throws JSONException If there is a syntax error.
|
||||
*/
|
||||
public JSONArray(JSONTokener x) throws JSONException {
|
||||
this();
|
||||
if(x.nextClean() != '[') {
|
||||
throw x.syntaxError("A JSONArray text must start with '['");
|
||||
}
|
||||
if(x.nextClean() != ']') {
|
||||
x.back();
|
||||
for(;;) {
|
||||
if(x.nextClean() == ',') {
|
||||
x.back();
|
||||
this.myArrayList.add(JSONObject.NULL);
|
||||
}
|
||||
else {
|
||||
x.back();
|
||||
this.myArrayList.add(x.nextValue());
|
||||
}
|
||||
switch(x.nextClean()) {
|
||||
case ';':
|
||||
case ',':
|
||||
if(x.nextClean() == ']') {
|
||||
return;
|
||||
}
|
||||
x.back();
|
||||
break;
|
||||
case ']':
|
||||
return;
|
||||
default:
|
||||
throw x.syntaxError("Expected a ',' or ']'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from a source JSON text.
|
||||
* @param source A string that begins with
|
||||
* <code>[</code> <small>(left bracket)</small>
|
||||
* and ends with <code>]</code> <small>(right bracket)</small>.
|
||||
* @throws JSONException If there is a syntax error.
|
||||
*/
|
||||
public JSONArray(String source) throws JSONException {
|
||||
this(new JSONTokener(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from a Collection.
|
||||
* @param collection A Collection.
|
||||
*/
|
||||
public JSONArray(Collection collection) {
|
||||
this.myArrayList = new ArrayList();
|
||||
if(collection != null) {
|
||||
Iterator iter = collection.iterator();
|
||||
while(iter.hasNext()) {
|
||||
this.myArrayList.add(JSONObject.wrap(iter.next()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from an array
|
||||
* @throws JSONException If not an array.
|
||||
*/
|
||||
public JSONArray(Object array) throws JSONException {
|
||||
this();
|
||||
if(array.getClass().isArray()) {
|
||||
int length = Array.getLength(array);
|
||||
for(int i = 0; i < length; i += 1) {
|
||||
this.put(JSONObject.wrap(Array.get(array, i)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new JSONException("JSONArray initial value should be a string or collection or array.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object value associated with an index.
|
||||
* @param index
|
||||
* The index must be between 0 and length() - 1.
|
||||
* @return An object value.
|
||||
* @throws JSONException If there is no value for the index.
|
||||
*/
|
||||
public Object get(int index) throws JSONException {
|
||||
Object object = this.opt(index);
|
||||
if(object == null) {
|
||||
throw new JSONException("JSONArray[" + index + "] not found.");
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the boolean value associated with an index.
|
||||
* The string values "true" and "false" are converted to boolean.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The truth.
|
||||
* @throws JSONException If there is no value for the index or if the
|
||||
* value is not convertible to boolean.
|
||||
*/
|
||||
public boolean getBoolean(int index) throws JSONException {
|
||||
Object object = this.get(index);
|
||||
if(object.equals(Boolean.FALSE) || (object instanceof String && ((String) object).equalsIgnoreCase("false"))) {
|
||||
return false;
|
||||
}
|
||||
else if(object.equals(Boolean.TRUE) || (object instanceof String && ((String) object).equalsIgnoreCase("true"))) {
|
||||
return true;
|
||||
}
|
||||
throw new JSONException("JSONArray[" + index + "] is not a boolean.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the double value associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
* @throws JSONException If the key is not found or if the value cannot
|
||||
* be converted to a number.
|
||||
*/
|
||||
public double getDouble(int index) throws JSONException {
|
||||
Object object = this.get(index);
|
||||
try {
|
||||
return object instanceof Number ? ((Number) object).doubleValue() : Double.parseDouble((String) object);
|
||||
}
|
||||
catch(Exception e) {
|
||||
throw new JSONException("JSONArray[" + index + "] is not a number.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the int value associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
* @throws JSONException If the key is not found or if the value is not a number.
|
||||
*/
|
||||
public int getInt(int index) throws JSONException {
|
||||
Object object = this.get(index);
|
||||
try {
|
||||
return object instanceof Number ? ((Number) object).intValue() : Integer.parseInt((String) object);
|
||||
}
|
||||
catch(Exception e) {
|
||||
throw new JSONException("JSONArray[" + index + "] is not a number.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JSONArray associated with an index.
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return A JSONArray value.
|
||||
* @throws JSONException If there is no value for the index. or if the
|
||||
* value is not a JSONArray
|
||||
*/
|
||||
public JSONArray getJSONArray(int index) throws JSONException {
|
||||
Object object = this.get(index);
|
||||
if(object instanceof JSONArray) {
|
||||
return (JSONArray) object;
|
||||
}
|
||||
throw new JSONException("JSONArray[" + index + "] is not a JSONArray.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JSONObject associated with an index.
|
||||
* @param index subscript
|
||||
* @return A JSONObject value.
|
||||
* @throws JSONException If there is no value for the index or if the
|
||||
* value is not a JSONObject
|
||||
*/
|
||||
public JSONObject getJSONObject(int index) throws JSONException {
|
||||
Object object = this.get(index);
|
||||
if(object instanceof JSONObject) {
|
||||
return (JSONObject) object;
|
||||
}
|
||||
throw new JSONException("JSONArray[" + index + "] is not a JSONObject.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the long value associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
* @throws JSONException If the key is not found or if the value cannot
|
||||
* be converted to a number.
|
||||
*/
|
||||
public long getLong(int index) throws JSONException {
|
||||
Object object = this.get(index);
|
||||
try {
|
||||
return object instanceof Number ? ((Number) object).longValue() : Long.parseLong((String) object);
|
||||
}
|
||||
catch(Exception e) {
|
||||
throw new JSONException("JSONArray[" + index + "] is not a number.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string associated with an index.
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return A string value.
|
||||
* @throws JSONException If there is no string value for the index.
|
||||
*/
|
||||
public String getString(int index) throws JSONException {
|
||||
Object object = this.get(index);
|
||||
if(object instanceof String) {
|
||||
return (String) object;
|
||||
}
|
||||
throw new JSONException("JSONArray[" + index + "] not a string.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the value is null.
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return true if the value at the index is null, or if there is no value.
|
||||
*/
|
||||
public boolean isNull(int index) {
|
||||
return JSONObject.NULL.equals(this.opt(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a string from the contents of this JSONArray. The
|
||||
* <code>separator</code> string is inserted between each element.
|
||||
* Warning: This method assumes that the data structure is acyclical.
|
||||
* @param separator A string that will be inserted between the elements.
|
||||
* @return a string.
|
||||
* @throws JSONException If the array contains an invalid number.
|
||||
*/
|
||||
public String join(String separator) throws JSONException {
|
||||
int len = this.length();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
for(int i = 0; i < len; i += 1) {
|
||||
if(i > 0) {
|
||||
sb.append(separator);
|
||||
}
|
||||
sb.append(JSONObject.valueToString(this.myArrayList.get(i)));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of elements in the JSONArray, included nulls.
|
||||
*
|
||||
* @return The length (or size).
|
||||
*/
|
||||
public int length() {
|
||||
return this.myArrayList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional object value associated with an index.
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return An object value, or null if there is no
|
||||
* object at that index.
|
||||
*/
|
||||
public Object opt(int index) {
|
||||
return (index < 0 || index >= this.length()) ? null : this.myArrayList.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional boolean value associated with an index.
|
||||
* It returns false if there is no value at that index,
|
||||
* or if the value is not Boolean.TRUE or the String "true".
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The truth.
|
||||
*/
|
||||
public boolean optBoolean(int index) {
|
||||
return this.optBoolean(index, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional boolean value associated with an index.
|
||||
* It returns the defaultValue if there is no value at that index or if
|
||||
* it is not a Boolean or the String "true" or "false" (case insensitive).
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @param defaultValue A boolean default.
|
||||
* @return The truth.
|
||||
*/
|
||||
public boolean optBoolean(int index, boolean defaultValue) {
|
||||
try {
|
||||
return this.getBoolean(index);
|
||||
}
|
||||
catch(Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional double value associated with an index.
|
||||
* NaN is returned if there is no value for the index,
|
||||
* or if the value is not a number and cannot be converted to a number.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
*/
|
||||
public double optDouble(int index) {
|
||||
return this.optDouble(index, Double.NaN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional double value associated with an index.
|
||||
* The defaultValue is returned if there is no value for the index,
|
||||
* or if the value is not a number and cannot be converted to a number.
|
||||
*
|
||||
* @param index subscript
|
||||
* @param defaultValue The default value.
|
||||
* @return The value.
|
||||
*/
|
||||
public double optDouble(int index, double defaultValue) {
|
||||
try {
|
||||
return this.getDouble(index);
|
||||
}
|
||||
catch(Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional int value associated with an index.
|
||||
* Zero is returned if there is no value for the index,
|
||||
* or if the value is not a number and cannot be converted to a number.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
*/
|
||||
public int optInt(int index) {
|
||||
return this.optInt(index, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional int value associated with an index.
|
||||
* The defaultValue is returned if there is no value for the index,
|
||||
* or if the value is not a number and cannot be converted to a number.
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @param defaultValue The default value.
|
||||
* @return The value.
|
||||
*/
|
||||
public int optInt(int index, int defaultValue) {
|
||||
try {
|
||||
return this.getInt(index);
|
||||
}
|
||||
catch(Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional JSONArray associated with an index.
|
||||
* @param index subscript
|
||||
* @return A JSONArray value, or null if the index has no value,
|
||||
* or if the value is not a JSONArray.
|
||||
*/
|
||||
public JSONArray optJSONArray(int index) {
|
||||
Object o = this.opt(index);
|
||||
return o instanceof JSONArray ? (JSONArray) o : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional JSONObject associated with an index.
|
||||
* Null is returned if the key is not found, or null if the index has
|
||||
* no value, or if the value is not a JSONObject.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return A JSONObject value.
|
||||
*/
|
||||
public JSONObject optJSONObject(int index) {
|
||||
Object o = this.opt(index);
|
||||
return o instanceof JSONObject ? (JSONObject) o : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional long value associated with an index.
|
||||
* Zero is returned if there is no value for the index,
|
||||
* or if the value is not a number and cannot be converted to a number.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
*/
|
||||
public long optLong(int index) {
|
||||
return this.optLong(index, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional long value associated with an index.
|
||||
* The defaultValue is returned if there is no value for the index,
|
||||
* or if the value is not a number and cannot be converted to a number.
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @param defaultValue The default value.
|
||||
* @return The value.
|
||||
*/
|
||||
public long optLong(int index, long defaultValue) {
|
||||
try {
|
||||
return this.getLong(index);
|
||||
}
|
||||
catch(Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional string value associated with an index. It returns an
|
||||
* empty string if there is no value at that index. If the value
|
||||
* is not a string and is not null, then it is coverted to a string.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return A String value.
|
||||
*/
|
||||
public String optString(int index) {
|
||||
return this.optString(index, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional string associated with an index.
|
||||
* The defaultValue is returned if the key is not found.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @param defaultValue The default value.
|
||||
* @return A String value.
|
||||
*/
|
||||
public String optString(int index, String defaultValue) {
|
||||
Object object = this.opt(index);
|
||||
return JSONObject.NULL.equals(object) ? defaultValue : object.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a boolean value. This increases the array's length by one.
|
||||
*
|
||||
* @param value A boolean value.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(boolean value) {
|
||||
this.put(value ? Boolean.TRUE : Boolean.FALSE);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a value in the JSONArray, where the value will be a
|
||||
* JSONArray which is produced from a Collection.
|
||||
* @param value A Collection value.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(Collection value) {
|
||||
this.put(new JSONArray(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a double value. This increases the array's length by one.
|
||||
*
|
||||
* @param value A double value.
|
||||
* @throws JSONException if the value is not finite.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(double value) throws JSONException {
|
||||
Double d = new Double(value);
|
||||
JSONObject.testValidity(d);
|
||||
this.put(d);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an int value. This increases the array's length by one.
|
||||
*
|
||||
* @param value An int value.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(int value) {
|
||||
this.put(new Integer(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an long value. This increases the array's length by one.
|
||||
*
|
||||
* @param value A long value.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(long value) {
|
||||
this.put(new Long(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a value in the JSONArray, where the value will be a
|
||||
* JSONObject which is produced from a Map.
|
||||
* @param value A Map value.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(Map value) {
|
||||
this.put(new JSONObject(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an object value. This increases the array's length by one.
|
||||
* @param value An object value. The value should be a
|
||||
* Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
|
||||
* JSONObject.NULL object.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(Object value) {
|
||||
this.myArrayList.add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put or replace a boolean value in the JSONArray. If the index is greater
|
||||
* than the length of the JSONArray, then null elements will be added as
|
||||
* necessary to pad it out.
|
||||
* @param index The subscript.
|
||||
* @param value A boolean value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative.
|
||||
*/
|
||||
public JSONArray put(int index, boolean value) throws JSONException {
|
||||
this.put(index, value ? Boolean.TRUE : Boolean.FALSE);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a value in the JSONArray, where the value will be a
|
||||
* JSONArray which is produced from a Collection.
|
||||
* @param index The subscript.
|
||||
* @param value A Collection value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative or if the value is
|
||||
* not finite.
|
||||
*/
|
||||
public JSONArray put(int index, Collection value) throws JSONException {
|
||||
this.put(index, new JSONArray(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put or replace a double value. If the index is greater than the length of
|
||||
* the JSONArray, then null elements will be added as necessary to pad
|
||||
* it out.
|
||||
* @param index The subscript.
|
||||
* @param value A double value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative or if the value is
|
||||
* not finite.
|
||||
*/
|
||||
public JSONArray put(int index, double value) throws JSONException {
|
||||
this.put(index, new Double(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put or replace an int value. If the index is greater than the length of
|
||||
* the JSONArray, then null elements will be added as necessary to pad
|
||||
* it out.
|
||||
* @param index The subscript.
|
||||
* @param value An int value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative.
|
||||
*/
|
||||
public JSONArray put(int index, int value) throws JSONException {
|
||||
this.put(index, new Integer(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put or replace a long value. If the index is greater than the length of
|
||||
* the JSONArray, then null elements will be added as necessary to pad
|
||||
* it out.
|
||||
* @param index The subscript.
|
||||
* @param value A long value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative.
|
||||
*/
|
||||
public JSONArray put(int index, long value) throws JSONException {
|
||||
this.put(index, new Long(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a value in the JSONArray, where the value will be a
|
||||
* JSONObject that is produced from a Map.
|
||||
* @param index The subscript.
|
||||
* @param value The Map value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative or if the the value is
|
||||
* an invalid number.
|
||||
*/
|
||||
public JSONArray put(int index, Map value) throws JSONException {
|
||||
this.put(index, new JSONObject(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put or replace an object value in the JSONArray. If the index is greater
|
||||
* than the length of the JSONArray, then null elements will be added as
|
||||
* necessary to pad it out.
|
||||
* @param index The subscript.
|
||||
* @param value The value to put into the array. The value should be a
|
||||
* Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
|
||||
* JSONObject.NULL object.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative or if the the value is
|
||||
* an invalid number.
|
||||
*/
|
||||
public JSONArray put(int index, Object value) throws JSONException {
|
||||
JSONObject.testValidity(value);
|
||||
if(index < 0) {
|
||||
throw new JSONException("JSONArray[" + index + "] not found.");
|
||||
}
|
||||
if(index < this.length()) {
|
||||
this.myArrayList.set(index, value);
|
||||
}
|
||||
else {
|
||||
while(index != this.length()) {
|
||||
this.put(JSONObject.NULL);
|
||||
}
|
||||
this.put(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an index and close the hole.
|
||||
* @param index The index of the element to be removed.
|
||||
* @return The value that was associated with the index,
|
||||
* or null if there was no value.
|
||||
*/
|
||||
public Object remove(int index) {
|
||||
Object o = this.opt(index);
|
||||
this.myArrayList.remove(index);
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONObject by combining a JSONArray of names with the values
|
||||
* of this JSONArray.
|
||||
* @param names A JSONArray containing a list of key strings. These will be
|
||||
* paired with the values.
|
||||
* @return A JSONObject, or null if there are no names or if this JSONArray
|
||||
* has no values.
|
||||
* @throws JSONException If any of the names are null.
|
||||
*/
|
||||
public JSONObject toJSONObject(JSONArray names) throws JSONException {
|
||||
if(names == null || names.length() == 0 || this.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
JSONObject jo = new JSONObject();
|
||||
for(int i = 0; i < names.length(); i += 1) {
|
||||
jo.put(names.getString(i), this.opt(i));
|
||||
}
|
||||
return jo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a JSON text of this JSONArray. For compactness, no
|
||||
* unnecessary whitespace is added. If it is not possible to produce a
|
||||
* syntactically correct JSON text then null will be returned instead. This
|
||||
* could occur if the array contains an invalid number.
|
||||
* <p>
|
||||
* Warning: This method assumes that the data structure is acyclical.
|
||||
*
|
||||
* @return a printable, displayable, transmittable
|
||||
* representation of the array.
|
||||
*/
|
||||
public String toString() {
|
||||
try {
|
||||
return '[' + this.join(",") + ']';
|
||||
}
|
||||
catch(Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a prettyprinted JSON text of this JSONArray.
|
||||
* Warning: This method assumes that the data structure is acyclical.
|
||||
* @param indentFactor The number of spaces to add to each level of
|
||||
* indentation.
|
||||
* @return a printable, displayable, transmittable
|
||||
* representation of the object, beginning
|
||||
* with <code>[</code> <small>(left bracket)</small> and ending
|
||||
* with <code>]</code> <small>(right bracket)</small>.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public String toString(int indentFactor) throws JSONException {
|
||||
StringWriter sw = new StringWriter();
|
||||
synchronized(sw.getBuffer()) {
|
||||
return this.write(sw, indentFactor, 0).toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the contents of the JSONArray as JSON text to a writer. For
|
||||
* compactness, no whitespace is added.
|
||||
* <p>
|
||||
* Warning: This method assumes that the data structure is acyclical.
|
||||
*
|
||||
* @return The writer.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public Writer write(Writer writer) throws JSONException {
|
||||
return this.write(writer, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the contents of the JSONArray as JSON text to a writer. For
|
||||
* compactness, no whitespace is added.
|
||||
* <p>
|
||||
* Warning: This method assumes that the data structure is acyclical.
|
||||
*
|
||||
* @param indentFactor
|
||||
* The number of spaces to add to each level of indentation.
|
||||
* @param indent
|
||||
* The indention of the top level.
|
||||
* @return The writer.
|
||||
* @throws JSONException
|
||||
*/
|
||||
Writer write(Writer writer, int indentFactor, int indent) throws JSONException {
|
||||
try {
|
||||
boolean commanate = false;
|
||||
int length = this.length();
|
||||
writer.write('[');
|
||||
|
||||
if(length == 1) {
|
||||
JSONObject.writeValue(writer, this.myArrayList.get(0), indentFactor, indent);
|
||||
}
|
||||
else if(length != 0) {
|
||||
final int newindent = indent + indentFactor;
|
||||
|
||||
for(int i = 0; i < length; i += 1) {
|
||||
if(commanate) {
|
||||
writer.write(',');
|
||||
}
|
||||
if(indentFactor > 0) {
|
||||
writer.write('\n');
|
||||
}
|
||||
JSONObject.indent(writer, newindent);
|
||||
JSONObject.writeValue(writer, this.myArrayList.get(i), indentFactor, newindent);
|
||||
commanate = true;
|
||||
}
|
||||
if(indentFactor > 0) {
|
||||
writer.write('\n');
|
||||
}
|
||||
JSONObject.indent(writer, indent);
|
||||
}
|
||||
writer.write(']');
|
||||
return writer;
|
||||
}
|
||||
catch(IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Foundation/src/com/foundation/util/json/JSONException.java
Normal file
27
Foundation/src/com/foundation/util/json/JSONException.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package com.foundation.util.json;
|
||||
|
||||
/**
|
||||
* The JSONException is thrown by the JSON.org classes when things are amiss.
|
||||
* @author JSON.org
|
||||
* @version 2010-12-24
|
||||
*/
|
||||
public class JSONException extends Exception {
|
||||
private static final long serialVersionUID = 0;
|
||||
private Throwable cause;
|
||||
/**
|
||||
* Constructs a JSONException with an explanatory message.
|
||||
* @param message Detail about the reason for the exception.
|
||||
*/
|
||||
public JSONException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JSONException(Throwable cause) {
|
||||
super(cause.getMessage());
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
public Throwable getCause() {
|
||||
return this.cause;
|
||||
}
|
||||
}
|
||||
1454
Foundation/src/com/foundation/util/json/JSONObject.java
Normal file
1454
Foundation/src/com/foundation/util/json/JSONObject.java
Normal file
File diff suppressed because it is too large
Load Diff
19
Foundation/src/com/foundation/util/json/JSONString.java
Normal file
19
Foundation/src/com/foundation/util/json/JSONString.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package com.foundation.util.json;
|
||||
|
||||
/**
|
||||
* The <code>JSONString</code> interface allows a <code>toJSONString()</code>
|
||||
* method so that a class can change the behavior of
|
||||
* <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>,
|
||||
* and <code>JSONWriter.value(</code>Object<code>)</code>. The
|
||||
* <code>toJSONString</code> method will be used instead of the default behavior
|
||||
* of using the Object's <code>toString()</code> method and quoting the result.
|
||||
*/
|
||||
public interface JSONString {
|
||||
/**
|
||||
* The <code>toJSONString</code> method allows a class to produce its own JSON
|
||||
* serialization.
|
||||
*
|
||||
* @return A strictly syntactically correct JSON text.
|
||||
*/
|
||||
public String toJSONString();
|
||||
}
|
||||
78
Foundation/src/com/foundation/util/json/JSONStringer.java
Normal file
78
Foundation/src/com/foundation/util/json/JSONStringer.java
Normal file
@@ -0,0 +1,78 @@
|
||||
package com.foundation.util.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2006 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* JSONStringer provides a quick and convenient way of producing JSON text.
|
||||
* The texts produced strictly conform to JSON syntax rules. No whitespace is
|
||||
* added, so the results are ready for transmission or storage. Each instance of
|
||||
* JSONStringer can produce one JSON text.
|
||||
* <p>
|
||||
* A JSONStringer instance provides a <code>value</code> method for appending
|
||||
* values to the
|
||||
* text, and a <code>key</code>
|
||||
* method for adding keys before values in objects. There are <code>array</code>
|
||||
* and <code>endArray</code> methods that make and bound array values, and
|
||||
* <code>object</code> and <code>endObject</code> methods which make and bound
|
||||
* object values. All of these methods return the JSONWriter instance,
|
||||
* permitting cascade style. For example, <pre>
|
||||
* myString = new JSONStringer()
|
||||
* .object()
|
||||
* .key("JSON")
|
||||
* .value("Hello, World!")
|
||||
* .endObject()
|
||||
* .toString();</pre> which produces the string <pre>
|
||||
* {"JSON":"Hello, World!"}</pre>
|
||||
* <p>
|
||||
* The first method called must be <code>array</code> or <code>object</code>.
|
||||
* There are no methods for adding commas or colons. JSONStringer adds them for
|
||||
* you. Objects and arrays can be nested up to 20 levels deep.
|
||||
* <p>
|
||||
* This can sometimes be easier than using a JSONObject to build a string.
|
||||
* @author JSON.org
|
||||
* @version 2008-09-18
|
||||
*/
|
||||
public class JSONStringer extends JSONWriter {
|
||||
/**
|
||||
* Make a fresh JSONStringer. It can be used to build one JSON text.
|
||||
*/
|
||||
public JSONStringer() {
|
||||
super(new StringWriter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JSON text. This method is used to obtain the product of the
|
||||
* JSONStringer instance. It will return <code>null</code> if there was a
|
||||
* problem in the construction of the JSON text (such as the calls to
|
||||
* <code>array</code> were not properly balanced with calls to
|
||||
* <code>endArray</code>).
|
||||
* @return The JSON text.
|
||||
*/
|
||||
public String toString() {
|
||||
return this.mode == 'd' ? this.writer.toString() : null;
|
||||
}
|
||||
}
|
||||
446
Foundation/src/com/foundation/util/json/JSONTokener.java
Normal file
446
Foundation/src/com/foundation/util/json/JSONTokener.java
Normal file
@@ -0,0 +1,446 @@
|
||||
package com.foundation.util.json;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A JSONTokener takes a source string and extracts characters and tokens from
|
||||
* it. It is used by the JSONObject and JSONArray constructors to parse
|
||||
* JSON source strings.
|
||||
* @author JSON.org
|
||||
* @version 2012-02-16
|
||||
*/
|
||||
public class JSONTokener {
|
||||
|
||||
private long character;
|
||||
private boolean eof;
|
||||
private long index;
|
||||
private long line;
|
||||
private char previous;
|
||||
private Reader reader;
|
||||
private boolean usePrevious;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from a Reader.
|
||||
*
|
||||
* @param reader A reader.
|
||||
*/
|
||||
public JSONTokener(Reader reader) {
|
||||
this.reader = reader.markSupported()
|
||||
? reader
|
||||
: new BufferedReader(reader);
|
||||
this.eof = false;
|
||||
this.usePrevious = false;
|
||||
this.previous = 0;
|
||||
this.index = 0;
|
||||
this.character = 1;
|
||||
this.line = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from an InputStream.
|
||||
*/
|
||||
public JSONTokener(InputStream inputStream) throws JSONException {
|
||||
this(new InputStreamReader(inputStream));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from a string.
|
||||
*
|
||||
* @param s A source string.
|
||||
*/
|
||||
public JSONTokener(String s) {
|
||||
this(new StringReader(s));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Back up one character. This provides a sort of lookahead capability,
|
||||
* so that you can test for a digit or letter before attempting to parse
|
||||
* the next number or identifier.
|
||||
*/
|
||||
public void back() throws JSONException {
|
||||
if (this.usePrevious || this.index <= 0) {
|
||||
throw new JSONException("Stepping back two steps is not supported");
|
||||
}
|
||||
this.index -= 1;
|
||||
this.character -= 1;
|
||||
this.usePrevious = true;
|
||||
this.eof = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the hex value of a character (base16).
|
||||
* @param c A character between '0' and '9' or between 'A' and 'F' or
|
||||
* between 'a' and 'f'.
|
||||
* @return An int between 0 and 15, or -1 if c was not a hex digit.
|
||||
*/
|
||||
public static int dehexchar(char c) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
if (c >= 'A' && c <= 'F') {
|
||||
return c - ('A' - 10);
|
||||
}
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
return c - ('a' - 10);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public boolean end() {
|
||||
return this.eof && !this.usePrevious;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the source string still contains characters that next()
|
||||
* can consume.
|
||||
* @return true if not yet at the end of the source.
|
||||
*/
|
||||
public boolean more() throws JSONException {
|
||||
this.next();
|
||||
if (this.end()) {
|
||||
return false;
|
||||
}
|
||||
this.back();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next character in the source string.
|
||||
*
|
||||
* @return The next character, or 0 if past the end of the source string.
|
||||
*/
|
||||
public char next() throws JSONException {
|
||||
int c;
|
||||
if (this.usePrevious) {
|
||||
this.usePrevious = false;
|
||||
c = this.previous;
|
||||
} else {
|
||||
try {
|
||||
c = this.reader.read();
|
||||
} catch (IOException exception) {
|
||||
throw new JSONException(exception);
|
||||
}
|
||||
|
||||
if (c <= 0) { // End of stream
|
||||
this.eof = true;
|
||||
c = 0;
|
||||
}
|
||||
}
|
||||
this.index += 1;
|
||||
if (this.previous == '\r') {
|
||||
this.line += 1;
|
||||
this.character = c == '\n' ? 0 : 1;
|
||||
} else if (c == '\n') {
|
||||
this.line += 1;
|
||||
this.character = 0;
|
||||
} else {
|
||||
this.character += 1;
|
||||
}
|
||||
this.previous = (char) c;
|
||||
return this.previous;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Consume the next character, and check that it matches a specified
|
||||
* character.
|
||||
* @param c The character to match.
|
||||
* @return The character.
|
||||
* @throws JSONException if the character does not match.
|
||||
*/
|
||||
public char next(char c) throws JSONException {
|
||||
char n = this.next();
|
||||
if (n != c) {
|
||||
throw this.syntaxError("Expected '" + c + "' and instead saw '" +
|
||||
n + "'");
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next n characters.
|
||||
*
|
||||
* @param n The number of characters to take.
|
||||
* @return A string of n characters.
|
||||
* @throws JSONException
|
||||
* Substring bounds error if there are not
|
||||
* n characters remaining in the source string.
|
||||
*/
|
||||
public String next(int n) throws JSONException {
|
||||
if (n == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
char[] chars = new char[n];
|
||||
int pos = 0;
|
||||
|
||||
while (pos < n) {
|
||||
chars[pos] = this.next();
|
||||
if (this.end()) {
|
||||
throw this.syntaxError("Substring bounds error");
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next char in the string, skipping whitespace.
|
||||
* @throws JSONException
|
||||
* @return A character, or 0 if there are no more characters.
|
||||
*/
|
||||
public char nextClean() throws JSONException {
|
||||
for (;;) {
|
||||
char c = this.next();
|
||||
if (c == 0 || c > ' ') {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the characters up to the next close quote character.
|
||||
* Backslash processing is done. The formal JSON format does not
|
||||
* allow strings in single quotes, but an implementation is allowed to
|
||||
* accept them.
|
||||
* @param quote The quoting character, either
|
||||
* <code>"</code> <small>(double quote)</small> or
|
||||
* <code>'</code> <small>(single quote)</small>.
|
||||
* @return A String.
|
||||
* @throws JSONException Unterminated string.
|
||||
*/
|
||||
public String nextString(char quote) throws JSONException {
|
||||
char c;
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (;;) {
|
||||
c = this.next();
|
||||
switch (c) {
|
||||
case 0:
|
||||
case '\n':
|
||||
case '\r':
|
||||
throw this.syntaxError("Unterminated string");
|
||||
case '\\':
|
||||
c = this.next();
|
||||
switch (c) {
|
||||
case 'b':
|
||||
sb.append('\b');
|
||||
break;
|
||||
case 't':
|
||||
sb.append('\t');
|
||||
break;
|
||||
case 'n':
|
||||
sb.append('\n');
|
||||
break;
|
||||
case 'f':
|
||||
sb.append('\f');
|
||||
break;
|
||||
case 'r':
|
||||
sb.append('\r');
|
||||
break;
|
||||
case 'u':
|
||||
sb.append((char)Integer.parseInt(this.next(4), 16));
|
||||
break;
|
||||
case '"':
|
||||
case '\'':
|
||||
case '\\':
|
||||
case '/':
|
||||
sb.append(c);
|
||||
break;
|
||||
default:
|
||||
throw this.syntaxError("Illegal escape.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (c == quote) {
|
||||
return sb.toString();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the text up but not including the specified character or the
|
||||
* end of line, whichever comes first.
|
||||
* @param delimiter A delimiter character.
|
||||
* @return A string.
|
||||
*/
|
||||
public String nextTo(char delimiter) throws JSONException {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (;;) {
|
||||
char c = this.next();
|
||||
if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
|
||||
if (c != 0) {
|
||||
this.back();
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the text up but not including one of the specified delimiter
|
||||
* characters or the end of line, whichever comes first.
|
||||
* @param delimiters A set of delimiter characters.
|
||||
* @return A string, trimmed.
|
||||
*/
|
||||
public String nextTo(String delimiters) throws JSONException {
|
||||
char c;
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (;;) {
|
||||
c = this.next();
|
||||
if (delimiters.indexOf(c) >= 0 || c == 0 ||
|
||||
c == '\n' || c == '\r') {
|
||||
if (c != 0) {
|
||||
this.back();
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next value. The value can be a Boolean, Double, Integer,
|
||||
* JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
|
||||
* @throws JSONException If syntax error.
|
||||
*
|
||||
* @return An object.
|
||||
*/
|
||||
public Object nextValue() throws JSONException {
|
||||
char c = this.nextClean();
|
||||
String string;
|
||||
|
||||
switch (c) {
|
||||
case '"':
|
||||
case '\'':
|
||||
return this.nextString(c);
|
||||
case '{':
|
||||
this.back();
|
||||
return new JSONObject(this);
|
||||
case '[':
|
||||
this.back();
|
||||
return new JSONArray(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle unquoted text. This could be the values true, false, or
|
||||
* null, or it can be a number. An implementation (such as this one)
|
||||
* is allowed to also accept non-standard forms.
|
||||
*
|
||||
* Accumulate characters until we reach the end of the text or a
|
||||
* formatting character.
|
||||
*/
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
|
||||
sb.append(c);
|
||||
c = this.next();
|
||||
}
|
||||
this.back();
|
||||
|
||||
string = sb.toString().trim();
|
||||
if ("".equals(string)) {
|
||||
throw this.syntaxError("Missing value");
|
||||
}
|
||||
return JSONObject.stringToValue(string);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Skip characters until the next character is the requested character.
|
||||
* If the requested character is not found, no characters are skipped.
|
||||
* @param to A character to skip to.
|
||||
* @return The requested character, or zero if the requested character
|
||||
* is not found.
|
||||
*/
|
||||
public char skipTo(char to) throws JSONException {
|
||||
char c;
|
||||
try {
|
||||
long startIndex = this.index;
|
||||
long startCharacter = this.character;
|
||||
long startLine = this.line;
|
||||
this.reader.mark(1000000);
|
||||
do {
|
||||
c = this.next();
|
||||
if (c == 0) {
|
||||
this.reader.reset();
|
||||
this.index = startIndex;
|
||||
this.character = startCharacter;
|
||||
this.line = startLine;
|
||||
return c;
|
||||
}
|
||||
} while (c != to);
|
||||
} catch (IOException exc) {
|
||||
throw new JSONException(exc);
|
||||
}
|
||||
|
||||
this.back();
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make a JSONException to signal a syntax error.
|
||||
*
|
||||
* @param message The error message.
|
||||
* @return A JSONException object, suitable for throwing
|
||||
*/
|
||||
public JSONException syntaxError(String message) {
|
||||
return new JSONException(message + this.toString());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make a printable string of this JSONTokener.
|
||||
*
|
||||
* @return " at {index} [character {character} line {line}]"
|
||||
*/
|
||||
public String toString() {
|
||||
return " at " + this.index + " [character " + this.character + " line " +
|
||||
this.line + "]";
|
||||
}
|
||||
}
|
||||
271
Foundation/src/com/foundation/util/json/JSONWriter.java
Normal file
271
Foundation/src/com/foundation/util/json/JSONWriter.java
Normal file
@@ -0,0 +1,271 @@
|
||||
package com.foundation.util.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/*
|
||||
Copyright (c) 2006 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JSONWriter provides a quick and convenient way of producing JSON text.
|
||||
* The texts produced strictly conform to JSON syntax rules. No whitespace is
|
||||
* added, so the results are ready for transmission or storage. Each instance of
|
||||
* JSONWriter can produce one JSON text.
|
||||
* <p>
|
||||
* A JSONWriter instance provides a <code>value</code> method for appending
|
||||
* values to the
|
||||
* text, and a <code>key</code>
|
||||
* method for adding keys before values in objects. There are <code>array</code>
|
||||
* and <code>endArray</code> methods that make and bound array values, and
|
||||
* <code>object</code> and <code>endObject</code> methods which make and bound
|
||||
* object values. All of these methods return the JSONWriter instance,
|
||||
* permitting a cascade style. For example, <pre>
|
||||
* new JSONWriter(myWriter)
|
||||
* .object()
|
||||
* .key("JSON")
|
||||
* .value("Hello, World!")
|
||||
* .endObject();</pre> which writes <pre>
|
||||
* {"JSON":"Hello, World!"}</pre>
|
||||
* <p>
|
||||
* The first method called must be <code>array</code> or <code>object</code>.
|
||||
* There are no methods for adding commas or colons. JSONWriter adds them for
|
||||
* you. Objects and arrays can be nested up to 20 levels deep.
|
||||
* <p>
|
||||
* This can sometimes be easier than using a JSONObject to build a string.
|
||||
* @author JSON.org
|
||||
* @version 2011-11-24
|
||||
*/
|
||||
public class JSONWriter {
|
||||
private static final int maxdepth = 200;
|
||||
/** The comma flag determines if a comma should be output before the next value. */
|
||||
private boolean comma;
|
||||
/** The current mode. Values: 'a' (array), 'd' (done), 'i' (initial), 'k' (key), 'o' (object). */
|
||||
protected char mode;
|
||||
/** The object/array stack. */
|
||||
private final JSONObject stack[];
|
||||
/** The stack top index. A value of 0 indicates that the stack is empty. */
|
||||
private int top;
|
||||
/** The writer that will receive the output. */
|
||||
protected Writer writer;
|
||||
/**
|
||||
* Make a fresh JSONWriter. It can be used to build one JSON text.
|
||||
*/
|
||||
public JSONWriter(Writer w) {
|
||||
this.comma = false;
|
||||
this.mode = 'i';
|
||||
this.stack = new JSONObject[maxdepth];
|
||||
this.top = 0;
|
||||
this.writer = w;
|
||||
}
|
||||
/**
|
||||
* Append a value.
|
||||
* @param string A string value.
|
||||
* @return this
|
||||
* @throws JSONException If the value is out of sequence.
|
||||
*/
|
||||
private JSONWriter append(String string) throws JSONException {
|
||||
if(string == null) {
|
||||
throw new JSONException("Null pointer");
|
||||
}
|
||||
if(this.mode == 'o' || this.mode == 'a') {
|
||||
try {
|
||||
if(this.comma && this.mode == 'a') {
|
||||
this.writer.write(',');
|
||||
}
|
||||
this.writer.write(string);
|
||||
}
|
||||
catch(IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
if(this.mode == 'o') {
|
||||
this.mode = 'k';
|
||||
}
|
||||
this.comma = true;
|
||||
return this;
|
||||
}
|
||||
throw new JSONException("Value out of sequence.");
|
||||
}
|
||||
/**
|
||||
* Begin appending a new array. All values until the balancing <code>endArray</code> will be appended to this array. The <code>endArray</code> method must be called to mark the array's end.
|
||||
* @return this
|
||||
* @throws JSONException If the nesting is too deep, or if the object is started in the wrong place (for example as a key or after the end of the outermost array or object).
|
||||
*/
|
||||
public JSONWriter array() throws JSONException {
|
||||
if(this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
|
||||
this.push(null);
|
||||
this.append("[");
|
||||
this.comma = false;
|
||||
return this;
|
||||
}
|
||||
throw new JSONException("Misplaced array.");
|
||||
}
|
||||
/**
|
||||
* End something.
|
||||
* @param mode Mode
|
||||
* @param c Closing character
|
||||
* @return this
|
||||
* @throws JSONException If unbalanced.
|
||||
*/
|
||||
private JSONWriter end(char mode, char c) throws JSONException {
|
||||
if(this.mode != mode) {
|
||||
throw new JSONException(mode == 'a' ? "Misplaced endArray." : "Misplaced endObject.");
|
||||
}
|
||||
this.pop(mode);
|
||||
try {
|
||||
this.writer.write(c);
|
||||
}
|
||||
catch(IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
this.comma = true;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* End an array. This method most be called to balance calls to <code>array</code>.
|
||||
* @return this
|
||||
* @throws JSONException If incorrectly nested.
|
||||
*/
|
||||
public JSONWriter endArray() throws JSONException {
|
||||
return this.end('a', ']');
|
||||
}
|
||||
/**
|
||||
* End an object. This method most be called to balance calls to <code>object</code>.
|
||||
* @return this
|
||||
* @throws JSONException If incorrectly nested.
|
||||
*/
|
||||
public JSONWriter endObject() throws JSONException {
|
||||
return this.end('k', '}');
|
||||
}
|
||||
/**
|
||||
* Append a key. The key will be associated with the next value. In an object, every value must be preceded by a key.
|
||||
* @param string A key string.
|
||||
* @return this
|
||||
* @throws JSONException If the key is out of place. For example, keys do not belong in arrays or if the key is null.
|
||||
*/
|
||||
public JSONWriter key(String string) throws JSONException {
|
||||
if(string == null) {
|
||||
throw new JSONException("Null key.");
|
||||
}
|
||||
if(this.mode == 'k') {
|
||||
try {
|
||||
this.stack[this.top - 1].putOnce(string, Boolean.TRUE);
|
||||
if(this.comma) {
|
||||
this.writer.write(',');
|
||||
}
|
||||
this.writer.write(JSONObject.quote(string));
|
||||
this.writer.write(':');
|
||||
this.comma = false;
|
||||
this.mode = 'o';
|
||||
return this;
|
||||
}
|
||||
catch(IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
}
|
||||
throw new JSONException("Misplaced key.");
|
||||
}
|
||||
/**
|
||||
* Begin appending a new object. All keys and values until the balancing <code>endObject</code> will be appended to this object. The <code>endObject</code> method must be called to mark the object's end.
|
||||
* @return this
|
||||
* @throws JSONException If the nesting is too deep, or if the object is started in the wrong place (for example as a key or after the end of the outermost array or object).
|
||||
*/
|
||||
public JSONWriter object() throws JSONException {
|
||||
if(this.mode == 'i') {
|
||||
this.mode = 'o';
|
||||
}
|
||||
if(this.mode == 'o' || this.mode == 'a') {
|
||||
this.append("{");
|
||||
this.push(new JSONObject());
|
||||
this.comma = false;
|
||||
return this;
|
||||
}
|
||||
throw new JSONException("Misplaced object.");
|
||||
|
||||
}
|
||||
/**
|
||||
* Pop an array or object scope.
|
||||
* @param c The scope to close.
|
||||
* @throws JSONException If nesting is wrong.
|
||||
*/
|
||||
private void pop(char c) throws JSONException {
|
||||
if(this.top <= 0) {
|
||||
throw new JSONException("Nesting error.");
|
||||
}
|
||||
char m = this.stack[this.top - 1] == null ? 'a' : 'k';
|
||||
if(m != c) {
|
||||
throw new JSONException("Nesting error.");
|
||||
}
|
||||
this.top -= 1;
|
||||
this.mode = this.top == 0 ? 'd' : this.stack[this.top - 1] == null ? 'a' : 'k';
|
||||
}
|
||||
/**
|
||||
* Push an array or object scope.
|
||||
* @param c The scope to open.
|
||||
* @throws JSONException If nesting is too deep.
|
||||
*/
|
||||
private void push(JSONObject jo) throws JSONException {
|
||||
if(this.top >= maxdepth) {
|
||||
throw new JSONException("Nesting too deep.");
|
||||
}
|
||||
this.stack[this.top] = jo;
|
||||
this.mode = jo == null ? 'a' : 'k';
|
||||
this.top += 1;
|
||||
}
|
||||
/**
|
||||
* Append either the value <code>true</code> or the value <code>false</code>.
|
||||
* @param b A boolean.
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
*/
|
||||
public JSONWriter value(boolean b) throws JSONException {
|
||||
return this.append(b ? "true" : "false");
|
||||
}
|
||||
/**
|
||||
* Append a double value.
|
||||
* @param d A double.
|
||||
* @return this
|
||||
* @throws JSONException If the number is not finite.
|
||||
*/
|
||||
public JSONWriter value(double d) throws JSONException {
|
||||
return this.value(new Double(d));
|
||||
}
|
||||
/**
|
||||
* Append a long value.
|
||||
* @param l A long.
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
*/
|
||||
public JSONWriter value(long l) throws JSONException {
|
||||
return this.append(Long.toString(l));
|
||||
}
|
||||
/**
|
||||
* Append an object value.
|
||||
* @param object The object to append. It can be null, or a Boolean, Number, String, JSONObject, or JSONArray, or an object that implements JSONString.
|
||||
* @return this
|
||||
* @throws JSONException If the value is out of sequence.
|
||||
*/
|
||||
public JSONWriter value(Object object) throws JSONException {
|
||||
return this.append(JSONObject.valueToString(object));
|
||||
}
|
||||
}
|
||||
181
Foundation/src/com/foundation/util/json/JsonBuilder.java
Normal file
181
Foundation/src/com/foundation/util/json/JsonBuilder.java
Normal file
@@ -0,0 +1,181 @@
|
||||
package com.foundation.util.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.common.comparison.Comparator;
|
||||
import com.common.debug.Debug;
|
||||
import com.common.exception.InvalidArgumentException;
|
||||
import com.common.util.IIterator;
|
||||
import com.common.util.LiteHashMap;
|
||||
import com.common.util.LiteHashSet;
|
||||
import com.common.util.LiteList;
|
||||
import com.foundation.common.Entity;
|
||||
import com.foundation.common.MetadataContainer;
|
||||
|
||||
/**
|
||||
* Reads and writes JSON formatted data.
|
||||
* Uses hashmaps and lists for the java side data structure.
|
||||
*/
|
||||
public class JsonBuilder {
|
||||
private JsonBuilder() {
|
||||
}//JsonBuilder()//
|
||||
private static LiteHashMap readObject(JSONObject object) throws JSONException {
|
||||
String[] keys = JSONObject.getNames(object);
|
||||
LiteHashMap result = new LiteHashMap(keys.length > 10 ? keys.length : 10);
|
||||
|
||||
for(int index = 0; index < keys.length; index++) {
|
||||
Object value = object.get(keys[index]);
|
||||
|
||||
if(value instanceof JSONObject) {
|
||||
value = readObject((JSONObject) value);
|
||||
}//if//
|
||||
else if(value instanceof JSONArray) {
|
||||
value = readArray((JSONArray) value);
|
||||
}//else if//
|
||||
else if(value == JSONObject.NULL) {
|
||||
value = null;
|
||||
}//else if//
|
||||
|
||||
result.put(keys[index], value);
|
||||
}//for//
|
||||
|
||||
return result;
|
||||
}//readObject()//
|
||||
private static LiteList readArray(JSONArray array) throws JSONException {
|
||||
LiteList result = new LiteList(array.length() > 10 ? array.length() : 10);
|
||||
|
||||
for(int index = 0; index < array.length(); index++) {
|
||||
Object value = array.get(index);
|
||||
|
||||
if(value instanceof JSONObject) {
|
||||
value = readObject((JSONObject) value);
|
||||
}//if//
|
||||
else if(value instanceof JSONArray) {
|
||||
value = readArray((JSONArray) value);
|
||||
}//else if//
|
||||
else if(value == JSONObject.NULL) {
|
||||
value = null;
|
||||
}//else if//
|
||||
|
||||
result.add(value);
|
||||
}//for//
|
||||
|
||||
return result;
|
||||
}//readArray()//
|
||||
/**
|
||||
* Converts the JSON string into a collection of LiteHashMap and LiteList instances.
|
||||
* @param json
|
||||
* @return
|
||||
*/
|
||||
public static LiteHashMap readJson(String json) {
|
||||
try {
|
||||
JSONTokener tokener = new JSONTokener(json);
|
||||
//TODO: It may be an array starting the JSON, not an object.
|
||||
JSONObject object = new JSONObject(tokener);
|
||||
|
||||
return readObject(object);
|
||||
}//try//
|
||||
catch(JSONException e) {
|
||||
Debug.log(e);
|
||||
throw new InvalidArgumentException("Invalid JSON string.");
|
||||
}//catch//
|
||||
}//readJson()//
|
||||
private static JSONObject writeObject(LiteHashMap object) throws JSONException {
|
||||
JSONObject result = new JSONObject();
|
||||
|
||||
for(IIterator iterator = object.keyIterator(); iterator.hasNext(); ) {
|
||||
String key = (String) iterator.next();
|
||||
Object value = object.get(key);
|
||||
|
||||
if(value instanceof LiteHashMap) {
|
||||
value = writeObject((LiteHashMap) value);
|
||||
}//if//
|
||||
else if(value instanceof LiteList) {
|
||||
value = writeArray((LiteList) value);
|
||||
}//else if//
|
||||
else if(value == null) {
|
||||
value = JSONObject.NULL;
|
||||
}//else if//
|
||||
|
||||
result.put(key, value);
|
||||
}//for//
|
||||
|
||||
return result;
|
||||
}//writeObject()//
|
||||
private static JSONArray writeArray(LiteList array) throws JSONException {
|
||||
JSONArray result = new JSONArray();
|
||||
|
||||
for(int index = 0; index < array.getSize(); index++) {
|
||||
Object value = array.get(index);
|
||||
|
||||
if(value instanceof LiteHashMap) {
|
||||
value = writeObject((LiteHashMap) value);
|
||||
}//if//
|
||||
else if(value instanceof LiteList) {
|
||||
value = writeArray((LiteList) value);
|
||||
}//else if//
|
||||
else if(value == null) {
|
||||
value = JSONObject.NULL;
|
||||
}//else if//
|
||||
|
||||
result.put(value);
|
||||
}//for//
|
||||
|
||||
return result;
|
||||
}//writeArray()//
|
||||
/**
|
||||
* Converts the value into a compact JSON string.
|
||||
* Includes all attributes that are not cyclical.
|
||||
* @param value The value to be converted (it will delve into collections and examine Entity objects to build the JSON string).
|
||||
* @return The JSON formatted string for the tree of objects.
|
||||
*/
|
||||
public static String writeJson(Object value) {
|
||||
return writeJson(value, null, null);
|
||||
}//writeJson()//
|
||||
/**
|
||||
* Converts the value into a JSON string.
|
||||
* Includes all attributes that are not cyclical.
|
||||
* @param indent The indent string to be used, or null if spacing should be minimized.
|
||||
* @return The JSON formatted string for the tree of objects.
|
||||
*/
|
||||
public static String writeJson(Object value, String indent) {
|
||||
return writeJson(value, null, indent);
|
||||
}//toJson()//
|
||||
/**
|
||||
* Converts the value into a compact JSON string.
|
||||
* Includes all attributes that are not cyclical.
|
||||
* @param metadataContainer The container containing metadata on what to include in the JSON.
|
||||
* @return The JSON formatted string for the tree of objects.
|
||||
*/
|
||||
public static String writeJson(Object value, MetadataContainer metadataContainer) {
|
||||
return writeJson(value, metadataContainer, null);
|
||||
}//toJson()//
|
||||
/**
|
||||
* Converts the value into a JSON string.
|
||||
* Includes all attributes that are not cyclical.
|
||||
* @param metadataContainer The container containing metadata on what to include in the JSON.
|
||||
* @param indent The indent string to be used, or null if spacing should be minimized.
|
||||
* @return The JSON formatted string for the tree of objects.
|
||||
*/
|
||||
public static String writeJson(Object value, MetadataContainer metadataContainer, String indent) {
|
||||
StringWriter writer = new StringWriter(10000);
|
||||
|
||||
if(value != null) {
|
||||
try {
|
||||
Entity.jsonValue(value, metadataContainer, indent, 0, new LiteHashSet(100, Comparator.getIdentityComparator(), LiteHashSet.STYLE_NO_DUPLICATES), writer);
|
||||
}//try//
|
||||
catch(IOException e) {
|
||||
//Shouldn't ever occur.//
|
||||
Debug.log(e);
|
||||
}//catch//
|
||||
catch(Throwable e) {
|
||||
Debug.log(e);
|
||||
}//catch//
|
||||
}//if//
|
||||
|
||||
return writer.toString();
|
||||
}//toJson()//
|
||||
}//JsonBuilder//
|
||||
294
Foundation/src/com/foundation/util/xml/AbstractNode.java
Normal file
294
Foundation/src/com/foundation/util/xml/AbstractNode.java
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (c) 2008,2009 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
import com.common.comparison.Comparator;
|
||||
import com.common.util.ICollection;
|
||||
import com.common.util.IHashMap;
|
||||
import com.common.util.IIterator;
|
||||
import com.common.util.IList;
|
||||
import com.common.util.LiteList;
|
||||
import com.foundation.util.HashMap;
|
||||
import com.foundation.util.IManagedList;
|
||||
import com.foundation.util.ManagedList;
|
||||
|
||||
public abstract class AbstractNode extends Element implements IAbstractNode {
|
||||
/** Ordered child elements defined between the node start and end tags. */
|
||||
private ManagedList elements = null;
|
||||
/** Ordered attributes defined in the node. */
|
||||
private ManagedList attributes = null;
|
||||
/**
|
||||
* AbstractNode constructor.
|
||||
*/
|
||||
public AbstractNode() {
|
||||
}//AbstractNode()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#getElements()
|
||||
*/
|
||||
public IManagedList getElements() {
|
||||
if(elements == null) {
|
||||
elements = new ManagedList(new ElementListManager(this));
|
||||
}//if//
|
||||
|
||||
return elements;
|
||||
}//getElements()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#addAttribute(com.foundation.util.xml.IAttribute)
|
||||
*/
|
||||
public boolean addAttribute(IAttribute attribute) {
|
||||
return getAttributes().add(attribute) != -1;
|
||||
}//addAttribute()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#addAttribute(java.lang.String, java.lang.Object)
|
||||
*/
|
||||
public IAttribute addAttribute(String name, Object value) {
|
||||
IAttribute result = new Property(name, value == null ? "" : value.toString());
|
||||
|
||||
return addAttribute(result) ? result : null;
|
||||
}//addAttribute()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#getAttribute(java.lang.String)
|
||||
*/
|
||||
public IAttribute getAttribute(String attributeName) {
|
||||
IAttribute result = null;
|
||||
|
||||
if(attributes != null) {
|
||||
for(int index = 0, length = attributes.getSize(); result == null && index < length; index++) {
|
||||
IAttribute next = (IAttribute) attributes.get(index);
|
||||
|
||||
if(Comparator.equals(next.getName(), attributeName)) {
|
||||
result = next;
|
||||
}//if//
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//getAttribute()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#getAttributeNames()
|
||||
*/
|
||||
public IList getAttributeNames() {
|
||||
LiteList result = LiteList.EMPTY_LIST;
|
||||
|
||||
if(attributes != null) {
|
||||
result = new LiteList(attributes.getSize());
|
||||
|
||||
for(int index = 0, length = attributes.getSize(); index < length; index++) {
|
||||
IAttribute next = (IAttribute) attributes.get(index);
|
||||
|
||||
result.add(next.getName());
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//getAttributeNames()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#getAttributeValue(java.lang.String)
|
||||
*/
|
||||
public String getAttributeValue(String attributeName) {
|
||||
IAttribute attribute = getAttribute(attributeName);
|
||||
|
||||
return attribute != null ? attribute.getValue() : null;
|
||||
}//getAttributeValue()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#getAttributeValue(java.lang.String, boolean, boolean)
|
||||
*/
|
||||
public String getAttributeValue(String attributeName, boolean trim, boolean emptySameAsNull) {
|
||||
return getAttributeValue(attributeName, trim, emptySameAsNull, null);
|
||||
}//getAttributeValue()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#getAttributeValue(java.lang.String, boolean, boolean, java.lang.String)
|
||||
*/
|
||||
public String getAttributeValue(String attributeName, boolean trim, boolean emptySameAsNull, String defaultValue) {
|
||||
IAttribute attribute = getAttribute(attributeName);
|
||||
String value = attribute != null ? attribute.getValue() : null;
|
||||
|
||||
if(value != null) {
|
||||
if(trim) {
|
||||
value = value.trim();
|
||||
}//if//
|
||||
|
||||
if((emptySameAsNull) && (value.length() == 0)) {
|
||||
value = null;
|
||||
}//if//
|
||||
}//if//
|
||||
|
||||
return value == null ? defaultValue : value;
|
||||
}//getAttributeValue()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#getAttributeBooleanValue(java.lang.String)
|
||||
*/
|
||||
public Boolean getAttributeBooleanValue(String attributeName) {
|
||||
return getAttributeBooleanValue(attributeName, null);
|
||||
}//getAttributeBooleanValue()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#getAttributeBooleanValue(java.lang.String, java.lang.Boolean)
|
||||
*/
|
||||
public Boolean getAttributeBooleanValue(String attributeName, Boolean defaultValue) {
|
||||
String value = getAttributeValue(attributeName, true, true, null);
|
||||
|
||||
return value == null ? defaultValue : Boolean.valueOf(value);
|
||||
}//getAttributeBooleanValue()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#getAttributeIntegerValue(java.lang.String)
|
||||
*/
|
||||
public Integer getAttributeIntegerValue(String attributeName) {
|
||||
return getAttributeIntegerValue(attributeName, null);
|
||||
}//getAttributeIntegerValue()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#getAttributeIntegerValue(java.lang.String, java.lang.Integer)
|
||||
*/
|
||||
public Integer getAttributeIntegerValue(String attributeName, Integer defaultValue) {
|
||||
String value = getAttributeValue(attributeName, true, true, null);
|
||||
|
||||
return value == null ? defaultValue : Integer.valueOf(value);
|
||||
}//getAttributeIntegerValue()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#getAttributeLongValue(java.lang.String)
|
||||
*/
|
||||
public Long getAttributeLongValue(String attributeName) {
|
||||
return getAttributeLongValue(attributeName, null);
|
||||
}//getAttributeLongValue()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#getAttributeLongValue(java.lang.String, java.lang.Long)
|
||||
*/
|
||||
public Long getAttributeLongValue(String attributeName, Long defaultValue) {
|
||||
String value = getAttributeValue(attributeName, true, true, null);
|
||||
|
||||
return value == null ? defaultValue : Long.valueOf(value);
|
||||
}//getAttributeLongValue()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#getAttributes()
|
||||
*/
|
||||
public IManagedList getAttributes() {
|
||||
if(attributes == null) {
|
||||
attributes = new ManagedList(10, 20);
|
||||
}//if//
|
||||
|
||||
return attributes;
|
||||
}//getAttributes()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#hasAttribute(java.lang.String)
|
||||
*/
|
||||
public boolean hasAttribute(String attributeName) {
|
||||
//TODO: This is inefficient - callers should simply get the IAttribute object so that it doesn't have to be found twice.
|
||||
return getAttribute(attributeName) != null;
|
||||
}//hasAttribute()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#removeAttribute(java.lang.String)
|
||||
*/
|
||||
public boolean removeAttribute(String attributeName) {
|
||||
IAttribute result = null;
|
||||
|
||||
if(attributes != null) {
|
||||
for(int index = 0, length = attributes.getSize(); result == null && index < length; index++) {
|
||||
IAttribute next = (IAttribute) attributes.get(index);
|
||||
|
||||
if(Comparator.equals(next.getName(), attributeName)) {
|
||||
attributes.remove(index);
|
||||
result = next;
|
||||
}//if//
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
return result != null;
|
||||
}//removeAttribute()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#createNode(java.lang.String)
|
||||
*/
|
||||
public INode createNode(String name) {
|
||||
INode result = new Node(name);
|
||||
|
||||
getElements().add(result);
|
||||
|
||||
return result;
|
||||
}//createNode()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#createText()
|
||||
*/
|
||||
public IText createText() {
|
||||
IText result = new Text();
|
||||
|
||||
getElements().add(result);
|
||||
|
||||
return result;
|
||||
}//createText()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#createText(java.lang.String)
|
||||
*/
|
||||
public IText createText(String text) {
|
||||
IText result = new Text();
|
||||
|
||||
getElements().add(result);
|
||||
result.setText(text);
|
||||
|
||||
return result;
|
||||
}//createText()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#createComment()
|
||||
*/
|
||||
public IComment createComment() {
|
||||
IComment result = new Comment();
|
||||
|
||||
getElements().add(result);
|
||||
|
||||
return result;
|
||||
}//createComment()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#createComment(java.lang.String)
|
||||
*/
|
||||
public IComment createComment(String comment) {
|
||||
IComment result = new Comment();
|
||||
|
||||
getElements().add(result);
|
||||
result.setText(comment);
|
||||
|
||||
return result;
|
||||
}//createComment()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#findNodes(java.lang.String, com.common.util.ICollection)
|
||||
*/
|
||||
public void findNodes(String name, ICollection results) {
|
||||
findNodes(name, results, false);
|
||||
}//findNodes()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#findNodes(java.lang.String, com.common.util.ICollection)
|
||||
*/
|
||||
public void findNodes(String name, ICollection results, boolean recursive) {
|
||||
IIterator iterator = getElements().iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object next = iterator.next();
|
||||
|
||||
if((((IElement) next).isNode()) && (((INode) next).getName().equals(name))) {
|
||||
results.add(next);
|
||||
}//if//
|
||||
|
||||
if(next instanceof IAbstractNode && recursive) {
|
||||
((IAbstractNode) next).findNodes(name, results, recursive);
|
||||
}//if//
|
||||
}//while//
|
||||
}//findNodes()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAbstractNode#findNode(java.lang.String)
|
||||
*/
|
||||
public INode findNode(String name) {
|
||||
IIterator iterator = getElements().iterator();
|
||||
INode result = null;
|
||||
|
||||
while((result == null) && (iterator.hasNext())) {
|
||||
Object next = iterator.next();
|
||||
|
||||
if((((IElement) next).isNode()) && (((INode) next).getName().equals(name))) {
|
||||
result = (INode) next;
|
||||
}//if//
|
||||
}//while//
|
||||
|
||||
return result;
|
||||
}//findNode()//
|
||||
}//AbstractNode//
|
||||
62
Foundation/src/com/foundation/util/xml/Comment.java
Normal file
62
Foundation/src/com/foundation/util/xml/Comment.java
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
public class Comment extends Element implements IComment {
|
||||
private String text = null;
|
||||
/**
|
||||
* Comment constructor.
|
||||
*/
|
||||
public Comment() {
|
||||
super();
|
||||
}//Comment()//
|
||||
/**
|
||||
* Comment constructor.
|
||||
* @param comment The initial text of the comment.
|
||||
*/
|
||||
public Comment(String comment) {
|
||||
super();
|
||||
|
||||
setText(comment);
|
||||
}//Comment()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IComment#getText()
|
||||
*/
|
||||
public String getText() {
|
||||
return text;
|
||||
}//getText()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.Element#isComment()
|
||||
*/
|
||||
public boolean isComment() {
|
||||
return true;
|
||||
}//isComment()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IComment#setText(java.lang.String)
|
||||
*/
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}//setText()//
|
||||
/**
|
||||
* Writes the element to the buffer.
|
||||
* @param out The output stream that will be given the formatted element data.
|
||||
* @param builder The document builder that will provide guidance.
|
||||
* @param prepend The string that will be added before any other characters in a perticular line.
|
||||
* @param postpend The string that will be added after any other characters in a perticular line.
|
||||
* @param compact Whether the output should be kept compact, or should include formatting characters.
|
||||
*/
|
||||
public void write(XmlOutputStream out, DocumentBuilder builder, String prepend, String postpend, boolean compact) throws java.io.IOException {
|
||||
if(!builder.getIgnoreComments().booleanValue() && !compact) {
|
||||
out.write(prepend);
|
||||
out.write("<!--");
|
||||
out.write(builder.getIgnoreTextWhitespace().booleanValue() ? getText().trim() : getText());
|
||||
out.write("-->");
|
||||
out.write(postpend);
|
||||
}//if//
|
||||
}//write()//
|
||||
}//Comment//
|
||||
92
Foundation/src/com/foundation/util/xml/DocType.java
Normal file
92
Foundation/src/com/foundation/util/xml/DocType.java
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2006,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/*
|
||||
* Encapsulates the DOCTYPE information that exists at the very top of most XML documents.
|
||||
* <p>See http://en.wikipedia.org/wiki/Document_Type_Declaration for a good description and links to resources.</p>
|
||||
*/
|
||||
public class DocType extends Element implements IDocType {
|
||||
private String name = null;
|
||||
private String visibility = null;
|
||||
private String publicIdentifier = null;
|
||||
private String systemIdentifier = null;
|
||||
/**
|
||||
* DocType constructor.
|
||||
* @param name The document type name.
|
||||
* @param visibility The document type visibility.
|
||||
* @param publicIdentifier The document type's public identifier or null if not available.
|
||||
* @param systemIdentifier The document type's system identifier (path to the dtd).
|
||||
*/
|
||||
public DocType(String name, String visibility, String publicIdentifier, String systemIdentifier) {
|
||||
super();
|
||||
|
||||
this.name = name;
|
||||
this.visibility = visibility;
|
||||
this.publicIdentifier = publicIdentifier;
|
||||
this.systemIdentifier = systemIdentifier;
|
||||
}//DocType()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IDocType#getName()
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}//getName()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IDocType#getVisibility()
|
||||
*/
|
||||
public String getVisibility() {
|
||||
return visibility;
|
||||
}//getVisibility()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IDocType#getPublicIdentifier()
|
||||
*/
|
||||
public String getPublicIdentifier() {
|
||||
return publicIdentifier;
|
||||
}//getPublicIdentifier()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IDocType#getSystemIdentifier()
|
||||
*/
|
||||
public String getSystemIdentifier() {
|
||||
return systemIdentifier;
|
||||
}//getSystemIdentifier()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.Element#write(com.foundation.util.xml.XmlOutputStream, com.foundation.util.xml.DocumentBuilder, java.lang.String, java.lang.String, boolean)
|
||||
*/
|
||||
public void write(XmlOutputStream out, DocumentBuilder builder, String prepend, String postpend, boolean compact) throws IOException {
|
||||
out.write(prepend);
|
||||
out.write("<!DOCTYPE");
|
||||
|
||||
if(getName() != null) {
|
||||
out.write(' ');
|
||||
out.write(getName());
|
||||
}//if//
|
||||
|
||||
if(getVisibility() != null) {
|
||||
out.write(' ');
|
||||
out.write(getVisibility());
|
||||
}//if//
|
||||
|
||||
if(getPublicIdentifier() != null) {
|
||||
out.write(" \"");
|
||||
out.write(getPublicIdentifier());
|
||||
out.write("\"");
|
||||
}//if//
|
||||
|
||||
if(getSystemIdentifier() != null) {
|
||||
out.write(" \"");
|
||||
out.write(getSystemIdentifier());
|
||||
out.write("\"");
|
||||
}//if//
|
||||
|
||||
out.write(">");
|
||||
out.write(postpend);
|
||||
}//write()//
|
||||
}//DocType//
|
||||
159
Foundation/src/com/foundation/util/xml/Document.java
Normal file
159
Foundation/src/com/foundation/util/xml/Document.java
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
import com.common.util.*;
|
||||
import com.foundation.util.IManagedList;
|
||||
import com.foundation.util.ManagedList;
|
||||
|
||||
public class Document extends AbstractNode implements IDocument {
|
||||
private IDocType docType = null;
|
||||
private ManagedList metadataNodes = null;
|
||||
/**
|
||||
* Document constructor.
|
||||
*/
|
||||
public Document() {
|
||||
super();
|
||||
}//Document()//
|
||||
/**
|
||||
* Gets the name of the node.
|
||||
* @return The node's name which is how the node is identified.
|
||||
*/
|
||||
public String getName() {
|
||||
//This method is not supported.//
|
||||
return null;
|
||||
}//getName()//
|
||||
/**
|
||||
* Gets this node's parent node.
|
||||
* @return The parent node, or null if this node does not have a parent.
|
||||
*/
|
||||
public IAbstractNode getParent() {
|
||||
return null;
|
||||
}//getParent()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#getEndCharacter()
|
||||
*/
|
||||
public int getEndCharacter() {
|
||||
return 0;
|
||||
}//getEndCharacter()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#getEndLine()
|
||||
*/
|
||||
public int getEndLine() {
|
||||
return 0;
|
||||
}//getEndLine()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#getStartCharacter()
|
||||
*/
|
||||
public int getStartCharacter() {
|
||||
return 0;
|
||||
}//getStartCharacter()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#getStartLine()
|
||||
*/
|
||||
public int getStartLine() {
|
||||
return 0;
|
||||
}//getStartLine()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IDocument#getDocType()
|
||||
*/
|
||||
public IDocType getDocType() {
|
||||
return docType;
|
||||
}//getDocType()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IDocument#setDocType(com.foundation.util.xml.IDocType)
|
||||
*/
|
||||
public void setDocType(IDocType docType) {
|
||||
this.docType = docType;
|
||||
}//setDocType()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.Element#isDocument()
|
||||
*/
|
||||
public boolean isDocument() {
|
||||
return true;
|
||||
}//isDocument()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IDocument#getMetadataNodes()
|
||||
*/
|
||||
public IManagedList getMetadataElements() {
|
||||
if(metadataNodes == null) {
|
||||
metadataNodes = new ManagedList(new MetadataNodeListManager(this));
|
||||
}//if//
|
||||
|
||||
return metadataNodes;
|
||||
}//getMetadataNodes()//
|
||||
/**
|
||||
* Writes the element to the buffer.
|
||||
* @param out The output stream that will be given the formatted element data.
|
||||
* @param builder The document builder that will provide guidance.
|
||||
* @param prepend The string that will be added before any other characters in a perticular line.
|
||||
* @param postpend The string that will be added after any other characters in a perticular line.
|
||||
* @param compact Whether the output should be kept compact, or should include formatting characters.
|
||||
*/
|
||||
public void write(XmlOutputStream out, DocumentBuilder builder, String prepend, String postpend, boolean compact) throws java.io.IOException {
|
||||
IIterator iterator = null;
|
||||
|
||||
if(getMetadataElements().getSize() > 0) {
|
||||
iterator = getMetadataElements().iterator();
|
||||
|
||||
for(int index = 0; index < getMetadataElements().getSize(); index++) {
|
||||
IElement element = (IElement) getMetadataElements().get(index);
|
||||
|
||||
if(element instanceof MetadataNode) {
|
||||
element.write(out, builder, prepend, postpend, false);
|
||||
}//if//
|
||||
else if(element instanceof IComment) {
|
||||
//Always display the header comments so that we can include a legal header.//
|
||||
//Note: If the user wants all comments stripped then it should set the builder's ignore comments flag.//
|
||||
element.write(out, builder, prepend, postpend, false);
|
||||
}//else if//
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
if(docType != null) {
|
||||
docType.write(out, builder, prepend, postpend, compact);
|
||||
}//if//
|
||||
|
||||
iterator = getElements().iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Element element = (Element) iterator.next();
|
||||
|
||||
element.write(out, builder, prepend, postpend, compact);
|
||||
}//while//
|
||||
}//write()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
DocumentBuilder builder = new DocumentBuilder();
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream(20000);
|
||||
XmlOutputStream xout = new XmlOutputStream(bout, "UTF8");
|
||||
String result = null;
|
||||
|
||||
builder.allowEncodedCharacters(false);
|
||||
|
||||
try {
|
||||
write(xout, builder, null, null, false);
|
||||
}//try//
|
||||
catch(Throwable e) {
|
||||
//Ignored.//
|
||||
}//catch//
|
||||
|
||||
try {
|
||||
result = new String(bout.toByteArray(), "UTF8");
|
||||
}//try//
|
||||
catch(Throwable e) {
|
||||
//Ignored.//
|
||||
}//catch//
|
||||
|
||||
return result;
|
||||
}//toString()//
|
||||
}//Document//
|
||||
2366
Foundation/src/com/foundation/util/xml/DocumentBuilder.java
Normal file
2366
Foundation/src/com/foundation/util/xml/DocumentBuilder.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
/**
|
||||
* This exception is raised if an XML stream is improperly formatted. This does not get used if the document does not conform to the document spec.
|
||||
*/
|
||||
public class DocumentFormatException extends Exception {
|
||||
private int lineNumber = 0;
|
||||
private int characterOffset = 0;
|
||||
/**
|
||||
* DocumentFormatException constructor.
|
||||
*/
|
||||
public DocumentFormatException() {
|
||||
super();
|
||||
}//DocumentFormatException()//
|
||||
/**
|
||||
* DocumentFormatException constructor.
|
||||
*/
|
||||
public DocumentFormatException(XmlInputStream stream) {
|
||||
super();
|
||||
|
||||
this.lineNumber = stream.getNextLineIndex();
|
||||
this.characterOffset = stream.getNextLineCharacterOffset();
|
||||
}//DocumentFormatException()//
|
||||
/**
|
||||
* DocumentFormatException constructor.
|
||||
* @param message The exception message.
|
||||
*/
|
||||
public DocumentFormatException(String message) {
|
||||
super(message);
|
||||
}//DocumentFormatException()//
|
||||
/**
|
||||
* DocumentFormatException constructor.
|
||||
* @param message The exception message.
|
||||
*/
|
||||
public DocumentFormatException(String message, XmlInputStream stream) {
|
||||
super(message);
|
||||
|
||||
this.lineNumber = stream.getNextLineIndex();
|
||||
this.characterOffset = stream.getNextLineCharacterOffset();
|
||||
}//DocumentFormatException()//
|
||||
/**
|
||||
* Gets the character offset within the line where the exception occured.
|
||||
* @return The line relative offset of the character causing the exception.
|
||||
*/
|
||||
public int getCharacterOffset() {
|
||||
return characterOffset;
|
||||
}//getCharacterOffset()//
|
||||
/**
|
||||
* Gets the line number in the document where the exception occured.
|
||||
* @return The line number at which the exception occured.
|
||||
*/
|
||||
public int getLineNumber() {
|
||||
return lineNumber;
|
||||
}//getLineNumber()//
|
||||
}//DocumentFormatException//
|
||||
164
Foundation/src/com/foundation/util/xml/Element.java
Normal file
164
Foundation/src/com/foundation/util/xml/Element.java
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
public abstract class Element implements IElement {
|
||||
private IAbstractNode parent = null;
|
||||
private int startCharacter = -1;
|
||||
private int startLine = -1;
|
||||
private int startLineCharacter = -1;
|
||||
private int endCharacter = -1;
|
||||
private int endLine = -1;
|
||||
private int endLineCharacter = -1;
|
||||
private boolean hasErrors = false;
|
||||
/**
|
||||
* Element constructor.
|
||||
*/
|
||||
public Element() {
|
||||
super();
|
||||
}//Element()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IElement#hasErrors()
|
||||
*/
|
||||
public boolean hasErrors() {
|
||||
return hasErrors;
|
||||
}//hasErrors()//
|
||||
/**
|
||||
* Sets whether the element has errors in it but is still detectable.
|
||||
* @param hasErrors Whether the reader detected errors in this element of the document.
|
||||
*/
|
||||
public void hasErrors(boolean hasErrors) {
|
||||
this.hasErrors = hasErrors;
|
||||
}//hasErrors()//
|
||||
/**
|
||||
* Gets this node's parent node.
|
||||
* @return The parent node, or null if this node does not have a parent.
|
||||
*/
|
||||
public IAbstractNode getParent() {
|
||||
return parent;
|
||||
}//getParent()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IElement#isComment()
|
||||
*/
|
||||
public boolean isComment() {
|
||||
return false;
|
||||
}//isComment()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IElement#isNode()
|
||||
*/
|
||||
public boolean isNode() {
|
||||
return false;
|
||||
}//isNode()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IElement#isText()
|
||||
*/
|
||||
public boolean isText() {
|
||||
return false;
|
||||
}//isText()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IElement#isDocument()
|
||||
*/
|
||||
public boolean isDocument() {
|
||||
return false;
|
||||
}//isDocument()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IElement#isInvalid()
|
||||
*/
|
||||
public boolean isInvalid() {
|
||||
return false;
|
||||
}//isInvalid()//
|
||||
/**
|
||||
* Sets this node's parent node.
|
||||
* @param parent The parent node, or null if this node does not have a parent.
|
||||
*/
|
||||
protected void setParent(IAbstractNode parent) {
|
||||
this.parent = parent;
|
||||
}//setParent()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IElement#write(com.foundation.util.xml.XmlOutputStream, com.foundation.util.xml.DocumentBuilder, java.lang.String, java.lang.String, boolean)
|
||||
*/
|
||||
public abstract void write(XmlOutputStream out, DocumentBuilder builder, String prepend, String postpend, boolean compact) throws java.io.IOException;
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IElement#getStartLine()
|
||||
*/
|
||||
public int getStartLine() {
|
||||
return startLine;
|
||||
}//getStartLine()//
|
||||
/**
|
||||
* Sets the line number on which the node begins.
|
||||
* @param startLine The line number where the start of the node is.
|
||||
*/
|
||||
public void setStartLine(int startLine) {
|
||||
this.startLine = startLine;
|
||||
}//setStartLine()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IElement#getStartCharacter()
|
||||
*/
|
||||
public int getStartCharacter() {
|
||||
return startCharacter;
|
||||
}//getStartCharacter()//
|
||||
/**
|
||||
* Sets the character number within the file where the text begins (inclusive).
|
||||
* @param startCharacter The index of the character from the beginning of the file.
|
||||
*/
|
||||
public void setStartCharacter(int startCharacter) {
|
||||
this.startCharacter = startCharacter;
|
||||
}//setStartCharacter()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IElement#getStartLineCharacter()
|
||||
*/
|
||||
public int getStartLineCharacter() {
|
||||
return startLineCharacter;
|
||||
}//getStartLineCharacter()/
|
||||
/**
|
||||
* Sets the character number within the line where the text begins (inclusive).
|
||||
* @param startLineCharacter The index of the character from the beginning of the line.
|
||||
*/
|
||||
public void setStartLineCharacter(int startLineCharacter) {
|
||||
this.startLineCharacter = startLineCharacter;
|
||||
}//setStartLineCharacter()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IElement#getEndCharacter()
|
||||
*/
|
||||
public int getEndCharacter() {
|
||||
return endCharacter;
|
||||
}//getEndCharacter()//
|
||||
/**
|
||||
* Sets the character number within the file where the text ends (inclusive).
|
||||
* @param endCharacter The index of the character from the beginning of the file.
|
||||
*/
|
||||
public void setEndCharacter(int endCharacter) {
|
||||
this.endCharacter = endCharacter;
|
||||
}//setEndCharacter()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IElement#getEndLine()
|
||||
*/
|
||||
public int getEndLine() {
|
||||
return endLine;
|
||||
}//getEndLine()//
|
||||
/**
|
||||
* Sets the line number on which the node ends.
|
||||
* @param endLine The line number where the end of the node is.
|
||||
*/
|
||||
public void setEndLine(int endLine) {
|
||||
this.endLine = endLine;
|
||||
}//setEndLine()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IElement#getEndLineCharacter()
|
||||
*/
|
||||
public int getEndLineCharacter() {
|
||||
return endLineCharacter;
|
||||
}//getEndLineCharacter()//
|
||||
/**
|
||||
* Sets the character number within the line where the text ends (inclusive).
|
||||
* @param endLineCharacter The index of the character from the beginning of the line.
|
||||
*/
|
||||
public void setEndLineCharacter(int endLineCharacter) {
|
||||
this.endLineCharacter = endLineCharacter;
|
||||
}//setEndLineCharacter()//
|
||||
}//Element//
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
import com.common.util.*;
|
||||
import com.foundation.util.*;
|
||||
|
||||
/**
|
||||
* Defines how the node's elements collection will be managed.
|
||||
*/
|
||||
final class ElementListManager extends ListManager {
|
||||
private AbstractNode node = null;
|
||||
/**
|
||||
* ElementListManager constructor.
|
||||
* @param node The node that this manager is servicing. Every element added to the collection will be given this node as its' parent.
|
||||
*/
|
||||
public ElementListManager(AbstractNode node) {
|
||||
super();
|
||||
|
||||
if(node == null) {
|
||||
throw new NullPointerException("It is not allowed to pass the ElementListManager a null node reference.");
|
||||
}//if//
|
||||
|
||||
this.node = node;
|
||||
}//ElementListManager()//
|
||||
/**
|
||||
* Determines whether the value can be added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param value The value that may be added.
|
||||
* @return Whether the value can be added to the collection.
|
||||
*/
|
||||
public boolean canAdd(IManagedCollection managed, Object value, byte context) {
|
||||
return (super.canAdd(managed, value, context)) && (value instanceof Element) && (!(value instanceof IDocument));
|
||||
}//canAdd()//
|
||||
/**
|
||||
* Determines whether the user can make the collection immutable (unchangeable).
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @return Whether the collection immutable flag can be set.
|
||||
*/
|
||||
public boolean canMakeImmutable(IManagedCollection managed) {
|
||||
return false;
|
||||
}//canMakeImmutable()//
|
||||
/**
|
||||
* Determines whether the collection should ask the manager to allow an add operation.
|
||||
* @return Whether this manager will be asked for permission before an add operation.
|
||||
*/
|
||||
public boolean checkOnAdd() {
|
||||
return true;
|
||||
}//checkOnAdd()//
|
||||
/**
|
||||
* Determines whether the collection should notify the manager after an add operation occurs.
|
||||
* @return Whether this manager will be notified after an add operation.
|
||||
*/
|
||||
public boolean notifyOnPostAdd() {
|
||||
return true;
|
||||
}//notifyOnPostAdd()//
|
||||
/**
|
||||
* Determines whether the collection should notify the manager after a remove operation occurs.
|
||||
* @return Whether this manager will be notified after a remove operation.
|
||||
*/
|
||||
public boolean notifyOnPostRemove() {
|
||||
return true;
|
||||
}//notifyOnPostRemove()//
|
||||
/**
|
||||
* Allows the manager to provide functionality after a value has been added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param value The value that has be added.
|
||||
* @see #preAdd(Object)
|
||||
*/
|
||||
public void postAdd(IManagedCollection managed, Object value, byte context) {
|
||||
if(value instanceof Element) {
|
||||
((Element) value).setParent(node);
|
||||
}//if//
|
||||
|
||||
super.postAdd(managed, value, context);
|
||||
}//postAdd()//
|
||||
/**
|
||||
* Allows the manager to provide functionality after a value has been removed from the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param value The value that has be removed.
|
||||
* @see #preRemove(Object)
|
||||
*/
|
||||
public void postRemove(IManagedCollection managed, Object value, byte context) {
|
||||
if(value instanceof Element) {
|
||||
((Element) value).setParent(null);
|
||||
}//if//
|
||||
|
||||
super.postRemove(managed, value, context);
|
||||
}//postRemove()//
|
||||
}//ElementListManager//
|
||||
176
Foundation/src/com/foundation/util/xml/IAbstractNode.java
Normal file
176
Foundation/src/com/foundation/util/xml/IAbstractNode.java
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 2008,2009 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
import com.common.util.ICollection;
|
||||
import com.common.util.IList;
|
||||
import com.foundation.util.IManagedList;
|
||||
|
||||
public interface IAbstractNode extends IElement {
|
||||
/**
|
||||
* Gets the collection of ordered elements that are defined within this node.
|
||||
* @return An ordered collection of IElement objects.
|
||||
*/
|
||||
public IManagedList getElements();
|
||||
/**
|
||||
* Adds the attribute to the node.
|
||||
* @param attribute The attribute to add. This attribute's name should be unique in the node's collection of attributes.
|
||||
* @return Whether the attribute was added.
|
||||
*/
|
||||
public boolean addAttribute(IAttribute attribute);
|
||||
/**
|
||||
* Adds the attribute to the node.
|
||||
* @param name The attribute name.
|
||||
* @param value The value for the attribute. The toString() method will be called to get a string representation. A null value is converted to an empty string.
|
||||
* @return The added attribute, or null if the add failed.
|
||||
*/
|
||||
public IAttribute addAttribute(String name, Object value);
|
||||
/**
|
||||
* Gets the attribute that has the associated attribute name.
|
||||
* @param attributeName The name of the attribute to lookup.
|
||||
* @return The attribute that has the given attribute name.
|
||||
*/
|
||||
public IAttribute getAttribute(String attributeName);
|
||||
/**
|
||||
* Gets the collection of attribute names for this node.
|
||||
* @return A collection of all of the attribute names in this node.
|
||||
*/
|
||||
public IList getAttributeNames();
|
||||
/**
|
||||
* Gets the value of the attribute that has the associated attribute name.
|
||||
* @param attributeName The name of the attribute to lookup.
|
||||
* @return The attribute value that associated with the given attribute name. This will be <code>null</code> if the attribute name is not in the mapping.
|
||||
*/
|
||||
public String getAttributeValue(String attributeName);
|
||||
/**
|
||||
* Gets the value of the attribute that has the associated attribute name.
|
||||
* @param attributeName The name of the attribute to lookup.
|
||||
* @param trim Whether the value should be trimed of excees spacing before and after any values.
|
||||
* @param emptySameAsNull Whether the empty values (after optional trimming) should be replaced by null values.
|
||||
* @return The attribute value that associated with the given attribute name. This will be <code>null</code> if the attribute name is not in the mapping.
|
||||
*/
|
||||
public String getAttributeValue(String attributeName, boolean trim, boolean emptySameAsNull);
|
||||
/**
|
||||
* Gets the value of the attribute that has the associated attribute name.
|
||||
* @param attributeName The name of the attribute to lookup.
|
||||
* @param trim Whether the value should be trimed of excees spacing before and after any values.
|
||||
* @param emptySameAsNull Whether the empty values (after optional trimming) should be replaced by null values.
|
||||
* @param defaultValue The value to be returned if the result would have been null.
|
||||
* @return The attribute value that associated with the given attribute name. This will be the default value if the attribute name is not in the mapping.
|
||||
*/
|
||||
public String getAttributeValue(String attributeName, boolean trim, boolean emptySameAsNull, String defaultValue);
|
||||
/**
|
||||
* Gets the value of the attribute that has the associated attribute name.
|
||||
* <p>Conversion of text to Integer performed by Integer.valueOf(String).</p>
|
||||
* @param attributeName The name of the attribute to lookup.
|
||||
* @return The attribute value that associated with the given attribute name. This will be <code>null</code> if the attribute name is not in the mapping.
|
||||
*/
|
||||
public Integer getAttributeIntegerValue(String attributeName);
|
||||
/**
|
||||
* Gets the value of the attribute that has the associated attribute name.
|
||||
* <p>Conversion of text to Integer performed by Integer.valueOf(String).</p>
|
||||
* @param attributeName The name of the attribute to lookup.
|
||||
* @param defaultValue The value to be returned if the result would have been null.
|
||||
* @return The attribute value that associated with the given attribute name. This will be the default value if the attribute name is not in the mapping.
|
||||
*/
|
||||
public Integer getAttributeIntegerValue(String attributeName, Integer defaultValue);
|
||||
/**
|
||||
* Gets the value of the attribute that has the associated attribute name.
|
||||
* <p>Conversion of text to Long performed by Long.valueOf(String).</p>
|
||||
* @param attributeName The name of the attribute to lookup.
|
||||
* @return The attribute value that associated with the given attribute name. This will be <code>null</code> if the attribute name is not in the mapping.
|
||||
*/
|
||||
public Long getAttributeLongValue(String attributeName);
|
||||
/**
|
||||
* Gets the value of the attribute that has the associated attribute name.
|
||||
* <p>Conversion of text to Long performed by Long.valueOf(String).</p>
|
||||
* @param attributeName The name of the attribute to lookup.
|
||||
* @param defaultValue The value to be returned if the result would have been null.
|
||||
* @return The attribute value that associated with the given attribute name. This will be the default value if the attribute name is not in the mapping.
|
||||
*/
|
||||
public Long getAttributeLongValue(String attributeName, Long defaultValue);
|
||||
/**
|
||||
* Gets the value of the attribute that has the associated attribute name.
|
||||
* <p>Conversion of text to Boolean performed by Boolean.valueOf(String).</p>
|
||||
* @param attributeName The name of the attribute to lookup.
|
||||
* @return The attribute value that associated with the given attribute name. This will be <code>null</code> if the attribute name is not in the mapping.
|
||||
*/
|
||||
public Boolean getAttributeBooleanValue(String attributeName);
|
||||
/**
|
||||
* Gets the value of the attribute that has the associated attribute name.
|
||||
* <p>Conversion of text to Boolean performed by Boolean.valueOf(String).</p>
|
||||
* @param attributeName The name of the attribute to lookup.
|
||||
* @param defaultValue The value to be returned if the result would have been null.
|
||||
* @return The attribute value that associated with the given attribute name. This will be the default value if the attribute name is not in the mapping.
|
||||
*/
|
||||
public Boolean getAttributeBooleanValue(String attributeName, Boolean defaultValue);
|
||||
/**
|
||||
* Gets the collection of attributes defined within the node start tag.
|
||||
* @return The ordered collection of IAttribute objects.
|
||||
*/
|
||||
public IManagedList getAttributes();
|
||||
/**
|
||||
* Determines whether the attribute exists in this node.
|
||||
* @param attributeName The name of the attribute to look for.
|
||||
* @return Whether this node has this attribute.
|
||||
*/
|
||||
public boolean hasAttribute(String attributeName);
|
||||
/**
|
||||
* Removes the attribute from the node.
|
||||
* @param attributeName Identifies the attribute to remove by its' name.
|
||||
* @return Whether the attribute was removed.
|
||||
*/
|
||||
public boolean removeAttribute(String attributeName);
|
||||
/**
|
||||
* A convienence method that creates a new node and adds it to the end of the collection of elements.
|
||||
* @param name An optional name for the node. The node's name can also be set by calling the <code>INode.setName(String)</code> method.
|
||||
* @return A new empty node element that is pre-added to this node's collection of contained elements.
|
||||
*/
|
||||
public INode createNode(String name);
|
||||
/**
|
||||
* A convienence method that creates a new text node and adds it to the end of the collection of elements.
|
||||
* @return A new empty text element that is pre-added to this node's collection of contained elements.
|
||||
*/
|
||||
public IText createText();
|
||||
/**
|
||||
* A convienence method that creates a new text node and adds it to the end of the collection of elements.
|
||||
* @param text The text to place in the text element.
|
||||
* @return A new text element that is pre-added to this node's collection of contained elements.
|
||||
*/
|
||||
public IText createText(String text);
|
||||
/**
|
||||
* A convienence method that creates a new comment node and adds it to the end of the collection of elements.
|
||||
* @return A new empty comment element that is pre-added to this node's collection of contained elements.
|
||||
*/
|
||||
public IComment createComment();
|
||||
/**
|
||||
* A convienence method that creates a new comment node and adds it to the end of the collection of elements.
|
||||
* @param comment The text to place in the comment element.
|
||||
* @return A new comment element that is pre-added to this node's collection of contained elements.
|
||||
*/
|
||||
public IComment createComment(String comment);
|
||||
/**
|
||||
* Locate the first node with the given name.
|
||||
* @param name The name of the node to find.
|
||||
* @return The node found, or null.
|
||||
*/
|
||||
public INode findNode(String name);
|
||||
/**
|
||||
* Locates all nodes with the given name that are children of just this node.
|
||||
* @param name The name of the nodes to find.
|
||||
* @param results The collection to fill with results.
|
||||
*/
|
||||
public void findNodes(String name, ICollection results);
|
||||
/**
|
||||
* Locates all nodes with the given name.
|
||||
* @param name The name of the nodes to find.
|
||||
* @param results The collection to fill with results.
|
||||
* @param recursive Whether the nodes in the tree should be recursively navigated to find results.
|
||||
*/
|
||||
public void findNodes(String name, ICollection results, boolean recursive);
|
||||
}//IAbstractNode//
|
||||
77
Foundation/src/com/foundation/util/xml/IAttribute.java
Normal file
77
Foundation/src/com/foundation/util/xml/IAttribute.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
/**
|
||||
* Note that the hasErrors flag represents errors in the name of the attribute, while the hasValueErrors represents errors in the value.
|
||||
*/
|
||||
public interface IAttribute extends IElement {
|
||||
public static final int QUOTE_TYPE_DOUBLE = 0;
|
||||
public static final int QUOTE_TYPE_SINGLE = 1;
|
||||
public static final int QUOTE_TYPE_NONE = 2;
|
||||
/**
|
||||
* Gets whether the element has errors in the value.
|
||||
* <p>The hasErrors flag represents errors only in the attribute name.
|
||||
* @return Whether the reader detected errors in the value.
|
||||
*/
|
||||
public boolean hasValueErrors();
|
||||
/**
|
||||
* Gets the name of the attribute.
|
||||
* @return The attribute's name which is how the attribute is identified.
|
||||
*/
|
||||
public String getName();
|
||||
/**
|
||||
* Gets the attribute's value.
|
||||
* @return The value associated with this attribute.
|
||||
*/
|
||||
public String getValue();
|
||||
/**
|
||||
* Gets the type of quote used for the attribute in the xml.
|
||||
* @return One of the QUOTE_TYPE_xx identifiers.
|
||||
*/
|
||||
public int getQuoteType();
|
||||
/**
|
||||
* Sets the type of quote used for the attribute in the xml.
|
||||
* @param quoteType One of the QUOTE_TYPE_xx identifiers.
|
||||
*/
|
||||
public void setQuoteType(int quoteType);
|
||||
/**
|
||||
* Gets the number of quote characters that begin and end the attribute's value.
|
||||
* @return The count of characters at the beginning and end of the attribute value that are quoting the value.
|
||||
*/
|
||||
public int getQuoteCharacterCount();
|
||||
/**
|
||||
* Gets the attribute's value.
|
||||
* @param trim Whether the value should be trimed of excees spacing before and after any values.
|
||||
* @param emptySameAsNull Whether the empty values (after optional trimming) should be replaced by null values.
|
||||
* @return The value associated with this attribute.
|
||||
*/
|
||||
public String getValue(boolean trim, boolean emptySameAsNull);
|
||||
/**
|
||||
* Sets the attribute's value.
|
||||
* @param value The value associated with this attribute.
|
||||
*/
|
||||
public void setValue(String value);
|
||||
/**
|
||||
* Sets the name of the node.
|
||||
* @param name The node's name which is how the node is identified.
|
||||
*/
|
||||
public void setName(String name);
|
||||
/**
|
||||
* Gets the index of the last value character.
|
||||
* <p>This will be non-negative no matter what, though if there is no value then this will be the same as the endCharacter value.
|
||||
* @return The last character in the value.
|
||||
*/
|
||||
public int getNameEndCharacter();
|
||||
/**
|
||||
* Gets the index of the first value character (including the quotes).
|
||||
* <p>If this is not -1, then a value was specified and the endCharacter refers the the last character of the value (which would be the ending quote).
|
||||
* @return The first character in the value.
|
||||
*/
|
||||
public int getValueStartCharacter();
|
||||
}//IAttribute//
|
||||
21
Foundation/src/com/foundation/util/xml/IComment.java
Normal file
21
Foundation/src/com/foundation/util/xml/IComment.java
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
public interface IComment extends IElement {
|
||||
/**
|
||||
* Gets the text for this comment element.
|
||||
* @return The text associated with this comment element.
|
||||
*/
|
||||
public String getText();
|
||||
/**
|
||||
* Sets the text for this comment element.
|
||||
* @param text The text associated with this comment element.
|
||||
*/
|
||||
public void setText(String text);
|
||||
}//IComment//
|
||||
31
Foundation/src/com/foundation/util/xml/IDocType.java
Normal file
31
Foundation/src/com/foundation/util/xml/IDocType.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
public interface IDocType extends IElement {
|
||||
/**
|
||||
* Gets the document type name (ie: HTML).
|
||||
* @return The document type name.
|
||||
*/
|
||||
public String getName();
|
||||
/**
|
||||
* Gets the document type visibility (ie: PUBLIC).
|
||||
* @return The document type visibility.
|
||||
*/
|
||||
public String getVisibility();
|
||||
/**
|
||||
* Gets the document type's public identifier (ie: -//W3C//DTD XHTML Basic 1.0//EN).
|
||||
* @return The document type's public identifier or null if not available.
|
||||
*/
|
||||
public String getPublicIdentifier();
|
||||
/**
|
||||
* Gets the document type's system identifier (ie: http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd).
|
||||
* @return The document type's system identifier (path to the dtd).
|
||||
*/
|
||||
public String getSystemIdentifier();
|
||||
}//IDocType//
|
||||
32
Foundation/src/com/foundation/util/xml/IDocument.java
Normal file
32
Foundation/src/com/foundation/util/xml/IDocument.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
import com.foundation.util.IManagedList;
|
||||
|
||||
/**
|
||||
* Note: A document contains metadata elements, then a doctype, then elements, in that order.
|
||||
*/
|
||||
public interface IDocument extends IAbstractNode {
|
||||
/**
|
||||
* Gets the collection of ordered metadata nodes and comments defined at the very top of the document.
|
||||
* <p>Note that these node objects cannot contain child elements. We may at some point define a special class for this data instead of using the Node class.</p>
|
||||
* @return The ordered metadata nodes <?name attr="value" ... ?> defined at the top of the document.
|
||||
*/
|
||||
public IManagedList getMetadataElements();
|
||||
/**
|
||||
* Gets the DOCTYPE data for the document.
|
||||
* @return The document type metadata or null if none was provided.
|
||||
*/
|
||||
public IDocType getDocType();
|
||||
/**
|
||||
* Sets the DOCTYPE data for the document.
|
||||
* @param docType The document type metadata or null if none is provided.
|
||||
*/
|
||||
public void setDocType(IDocType docType);
|
||||
}//IDocument//
|
||||
85
Foundation/src/com/foundation/util/xml/IElement.java
Normal file
85
Foundation/src/com/foundation/util/xml/IElement.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
public interface IElement {
|
||||
/**
|
||||
* Gets whether the element has errors in it but is still detectable.
|
||||
* @return Whether the reader detected errors in this element of the document.
|
||||
*/
|
||||
public boolean hasErrors();
|
||||
/**
|
||||
* Gets this element's parent node.
|
||||
* @return The parent node, or null if this element does not have a parent (only the case for the document).
|
||||
*/
|
||||
public IAbstractNode getParent();
|
||||
/**
|
||||
* Determines whether this is an IComment instance.
|
||||
* @return Whether this instance implements IComment.
|
||||
*/
|
||||
public boolean isComment();
|
||||
/**
|
||||
* Determines whether this is an INode instance.
|
||||
* @return Whether this instance implements INode.
|
||||
*/
|
||||
public boolean isNode();
|
||||
/**
|
||||
* Determines whether this is an IText instance.
|
||||
* @return Whether this instance implements IText.
|
||||
*/
|
||||
public boolean isText();
|
||||
/**
|
||||
* Determines whether this is an IDocument instance.
|
||||
* @return Whether this instance implements IDocument.
|
||||
*/
|
||||
public boolean isDocument();
|
||||
/**
|
||||
* Determines whether this is an IInvalid instance.
|
||||
* @return Whether this instance implements IInvalid.
|
||||
*/
|
||||
public boolean isInvalid();
|
||||
/**
|
||||
* Writes the element to the buffer.
|
||||
* @param out The output stream that will be given the formatted element data.
|
||||
* @param builder The document builder that will provide guidance.
|
||||
* @param prepend The string that will be added before any other characters in a perticular line.
|
||||
* @param postpend The string that will be added after any other characters in a perticular line.
|
||||
* @param compact Whether the output should be kept compact, or should include formatting characters.
|
||||
*/
|
||||
public void write(XmlOutputStream out, DocumentBuilder builder, String prepend, String postpend, boolean compact) throws java.io.IOException;
|
||||
/**
|
||||
* Gets the line number on which the text begins.
|
||||
* @return The line number where the start of the text is.
|
||||
*/
|
||||
public int getStartLine();
|
||||
/**
|
||||
* Gets the line number on which the text ends.
|
||||
* @return The line number where the end of the text is.
|
||||
*/
|
||||
public int getEndLine();
|
||||
/**
|
||||
* Gets the character number within the line where the text begins (inclusive).
|
||||
* @return The index of the character from the beginning of the line.
|
||||
*/
|
||||
public int getStartLineCharacter();
|
||||
/**
|
||||
* Gets the character number within the line where the text ends (inclusive).
|
||||
* @return The index of the character from the beginning of the line.
|
||||
*/
|
||||
public int getEndLineCharacter();
|
||||
/**
|
||||
* Gets the character number within the file where the text begins (inclusive).
|
||||
* @return The index of the character from the beginning of the file.
|
||||
*/
|
||||
public int getStartCharacter();
|
||||
/**
|
||||
* Gets the character number within the file where the text ends (inclusive).
|
||||
* @return The index of the character from the beginning of the file.
|
||||
*/
|
||||
public int getEndCharacter();
|
||||
}//IElement//
|
||||
21
Foundation/src/com/foundation/util/xml/IInvalid.java
Normal file
21
Foundation/src/com/foundation/util/xml/IInvalid.java
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
public interface IInvalid extends IElement {
|
||||
/**
|
||||
* Gets the invalid text for this element.
|
||||
* @return The invalid text associated with this element.
|
||||
*/
|
||||
public String getInvalidText();
|
||||
/**
|
||||
* Sets the invalid text for this element.
|
||||
* @param invalidText The invalid text associated with this element.
|
||||
*/
|
||||
public void setInvalidText(String invalidText);
|
||||
}//IInvalid//
|
||||
11
Foundation/src/com/foundation/util/xml/IMetadataNode.java
Normal file
11
Foundation/src/com/foundation/util/xml/IMetadataNode.java
Normal file
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
public interface IMetadataNode extends INode {
|
||||
}//IMetadataNode//
|
||||
71
Foundation/src/com/foundation/util/xml/INode.java
Normal file
71
Foundation/src/com/foundation/util/xml/INode.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
/**
|
||||
* Possible use cases:<br>
|
||||
* <tagname attribute="abc"></tagname><br>
|
||||
* <tagname attribute="abc"/><br>
|
||||
* <tagname attribute="abc"> <-- some html tags such as <p> may not have an end tag.<br>
|
||||
* The StartCharacter and EndCharacter represent the very first and very last character indices in the node.
|
||||
* INode adds to that StartTagTailStartCharacter, StartTagTailEndCharacter, StartTagEndNameCharacter, and EndTagStartCharacter so that all of the beginning and ends of the formatting characters have known positions.
|
||||
* <p>
|
||||
* For an INode, the ordering would be thus:<br>
|
||||
* 1) StartCharacter<br>
|
||||
* Node Name<br>
|
||||
* 2) StartTagEndNameCharacter<br>
|
||||
* Node attributes, comments, etc...<br>
|
||||
* 3) StartTagTailStartCharacter<br>
|
||||
* 4) StartTagTailEndCharacter (may be the same as EndCharacter in some use cases)<br>
|
||||
* Child nodes, comments, etc..<br>
|
||||
* 5) EndTagStartCharacter (optional for some use cases - will be zero if not provided)<br>
|
||||
* 6) EndCharacter<br>
|
||||
*/
|
||||
public interface INode extends IAbstractNode {
|
||||
/**
|
||||
* Gets whether the node should always display an end tag.
|
||||
* @return Whether the node should display an end tag even if one is not required.
|
||||
*/
|
||||
public boolean useEndTag();
|
||||
/**
|
||||
* Gets whether the node has no ending tag and the starting tag does not end with a slash.
|
||||
* <br>For example: <mynode attr='abc'>.
|
||||
* @return Whether the node does not have a proper XML ending.
|
||||
*/
|
||||
public boolean isEndless();
|
||||
/**
|
||||
* Gets the global character offset of the last character of the start tag (inclusive).
|
||||
* @return The index of the character from the beginning of the file.
|
||||
*/
|
||||
public int getStartTagTailStartCharacter();
|
||||
/**
|
||||
* Gets the global character offset of the last character of the start tag (inclusive).
|
||||
* @return The index of the character from the beginning of the file.
|
||||
*/
|
||||
public int getStartTagTailEndCharacter();
|
||||
/**
|
||||
* Gets the global character offset of the last character of the start tag name (inclusive).
|
||||
* @return The index of the character from the beginning of the file.
|
||||
*/
|
||||
public int getStartTagEndNameCharacter();
|
||||
/**
|
||||
* Gets the global character offset of the first character of the ending tag (inclusive).
|
||||
* @return The index of the character from the beginning of the file.
|
||||
*/
|
||||
public int getEndTagStartCharacter();
|
||||
/**
|
||||
* Gets the name of the node.
|
||||
* @return The node's name which is how the node is identified.
|
||||
*/
|
||||
public String getName();
|
||||
/**
|
||||
* Sets the name of the node.
|
||||
* @param name The node's name which is how the node is identified.
|
||||
*/
|
||||
public void setName(String name);
|
||||
}//INode//
|
||||
21
Foundation/src/com/foundation/util/xml/IText.java
Normal file
21
Foundation/src/com/foundation/util/xml/IText.java
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
public interface IText extends IElement {
|
||||
/**
|
||||
* Gets the text for this text element.
|
||||
* @return The text associated with this text element.
|
||||
*/
|
||||
public String getText();
|
||||
/**
|
||||
* Sets the text for this text element.
|
||||
* @param text The text associated with this text element.
|
||||
*/
|
||||
public void setText(String text);
|
||||
}//IText//
|
||||
64
Foundation/src/com/foundation/util/xml/Invalid.java
Normal file
64
Foundation/src/com/foundation/util/xml/Invalid.java
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class Invalid extends Element implements IInvalid {
|
||||
private String invalidText = null;
|
||||
/**
|
||||
* Invalid constructor.
|
||||
*/
|
||||
public Invalid() {
|
||||
}//Invalid()//
|
||||
/**
|
||||
* Invalid constructor.
|
||||
* @param invalidText The invalid text.
|
||||
*/
|
||||
public Invalid(String invalidText) {
|
||||
setInvalidText(invalidText);
|
||||
}//Invalid()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IInvalid#getInvalidText()
|
||||
*/
|
||||
public String getInvalidText() {
|
||||
return invalidText;
|
||||
}//getInvalidText()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IInvalid#setInvalidText(java.lang.String)
|
||||
*/
|
||||
public void setInvalidText(String invalidText) {
|
||||
this.invalidText = invalidText;
|
||||
}//setInvalidText()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IElement#isInvalid()
|
||||
*/
|
||||
public boolean isInvalid() {
|
||||
return true;
|
||||
}//isInvalid()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.Element#write(com.foundation.util.xml.XmlOutputStream, com.foundation.util.xml.DocumentBuilder, java.lang.String, java.lang.String, boolean)
|
||||
*/
|
||||
public void write(XmlOutputStream out, DocumentBuilder builder, String prepend, String postpend, boolean compact) throws IOException {
|
||||
out.write(prepend);
|
||||
out.write(getInvalidText());
|
||||
out.write(postpend);
|
||||
}//write()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.Element#hasErrors()
|
||||
*/
|
||||
public boolean hasErrors() {
|
||||
return true;
|
||||
}//hasErrors()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.Element#hasErrors(boolean)
|
||||
*/
|
||||
public void hasErrors(boolean hasErrors) {
|
||||
//Does nothing.. invalid tags obviously have errors.//
|
||||
}//hasErrors()//
|
||||
}//Invalid//
|
||||
141
Foundation/src/com/foundation/util/xml/MetadataNode.java
Normal file
141
Foundation/src/com/foundation/util/xml/MetadataNode.java
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
import com.foundation.util.*;
|
||||
|
||||
/*
|
||||
* The node that occurs at the top of a document only and provides some metadata on the document.
|
||||
*/
|
||||
public class MetadataNode extends Node implements IMetadataNode {
|
||||
/**
|
||||
* MetadataNode constructor.
|
||||
*/
|
||||
public MetadataNode() {
|
||||
super();
|
||||
}//MetadataNode()//
|
||||
/**
|
||||
* MetadataNode constructor.
|
||||
* @param name The initial name for the node.
|
||||
*/
|
||||
public MetadataNode(String name) {
|
||||
super(name);
|
||||
}//MetadataNode()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#getStartTagTailEndCharacter()
|
||||
*/
|
||||
public int getStartTagTailEndCharacter() {
|
||||
return getEndCharacter();
|
||||
}//getStartTagTailEndCharacter()//
|
||||
/**
|
||||
* Sets the global character offset of the last character of the start tag (inclusive).
|
||||
* @param startTagTailEndCharacter The index of the character from the beginning of the file.
|
||||
*/
|
||||
public void setStartTagTailEndCharacter(int startTagTailEndCharacter) {
|
||||
setEndCharacter(startTagTailEndCharacter);
|
||||
}//setStartTagTailEndCharacter()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#getStartTagTailEndLine()
|
||||
*/
|
||||
public int getStartTagTailEndLine() {
|
||||
return getEndLine();
|
||||
}//getStartTagTailEndLine()//
|
||||
/**
|
||||
* Sets the line offset of the last character of the start tag.
|
||||
* @param startTagTailEndLine The line number where the end of the node is.
|
||||
*/
|
||||
public void setStartTagTailEndLine(int startTagTailEndLine) {
|
||||
setEndLine(startTagTailEndLine);
|
||||
}//setStartTagTailEndLine()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#getStartTagTailEndLineCharacter()
|
||||
*/
|
||||
public int getStartTagTailEndLineCharacter() {
|
||||
return getEndLineCharacter();
|
||||
}//getStartTagTailEndLineCharacter()//
|
||||
/**
|
||||
* Sets the line character offset of the last character of the start tag (inclusive).
|
||||
* @param startTagTailEndLineCharacter The index of the character from the beginning of the line.
|
||||
*/
|
||||
public void setStartTagTailEndLineCharacter(int startTagTailEndLineCharacter) {
|
||||
setEndLineCharacter(startTagTailEndLineCharacter);
|
||||
}//setStartTagTailEndLineCharacter()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#getEndTagStartCharacter()
|
||||
*/
|
||||
public int getEndTagStartCharacter() {
|
||||
return 0;
|
||||
}//getEndTagStartCharacter()//
|
||||
/**
|
||||
* Sets the global character offset of the first character of the ending tag (inclusive).
|
||||
* @param endTagStartCharacter The index of the character from the beginning of the file.
|
||||
*/
|
||||
public void setEndTagStartCharacter(int endTagStartCharacter) {
|
||||
}//setEndTagStartCharacter()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#getEndTagStartLine()
|
||||
*/
|
||||
public int getEndTagStartLine() {
|
||||
return 0;
|
||||
}//getEndTagStartLine()//
|
||||
/**
|
||||
* Sets the line offset of the first character of the ending tag.
|
||||
* @param endTagStartLine The line number where the end of the node is.
|
||||
*/
|
||||
public void setEndTagStartLine(int endTagStartLine) {
|
||||
}//setEndTagStartLine()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#getEndTagStartLineCharacter()
|
||||
*/
|
||||
public int getEndTagStartLineCharacter() {
|
||||
return 0;
|
||||
}//getEndTagStartLineCharacter()//
|
||||
/**
|
||||
* Sets the line character offset of the first character of the ending tag (inclusive).
|
||||
* @param endTagStartLineCharacter The index of the character from the beginning of the line.
|
||||
*/
|
||||
public void setEndTagStartLineCharacter(int endTagStartLineCharacter) {
|
||||
}//setEndTagStartLineCharacter()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#createNode(java.lang.String)
|
||||
*/
|
||||
public INode createNode(String name) {
|
||||
return null;
|
||||
}//createNode()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#getElements()
|
||||
*/
|
||||
public IManagedList getElements() {
|
||||
return ManagedList.EMPTY_LIST;
|
||||
}//getElements()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IElement#write(com.foundation.util.xml.XmlOutputStream, com.foundation.util.xml.DocumentBuilder, java.lang.String, java.lang.String, boolean)
|
||||
*/
|
||||
public void write(XmlOutputStream out, DocumentBuilder builder, String prepend, String postpend, boolean compact) throws java.io.IOException {
|
||||
out.write(prepend);
|
||||
out.write("<?");
|
||||
out.write(getName());
|
||||
|
||||
//Write the attributes.//
|
||||
for(int index = 0; index < getAttributes().getSize(); index++) {
|
||||
IAttribute attribute = (IAttribute) getAttributes().get(index);
|
||||
|
||||
out.write(' ');
|
||||
attribute.write(out, builder, null, null, compact);
|
||||
}//for//
|
||||
|
||||
out.write("?>");
|
||||
out.write(postpend);
|
||||
}//write()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
return "Metadata Node: " + getName();
|
||||
}//toString()//
|
||||
}//MetadataNode//
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
import com.common.util.*;
|
||||
import com.foundation.util.*;
|
||||
|
||||
/**
|
||||
* Defines how the node's elements collection will be managed.
|
||||
*/
|
||||
final class MetadataNodeListManager extends ListManager {
|
||||
private Document document = null;
|
||||
/**
|
||||
* ElementListManager constructor.
|
||||
* @param node The node that this manager is servicing. Every element added to the collection will be given this node as its' parent.
|
||||
*/
|
||||
public MetadataNodeListManager(Document document) {
|
||||
super();
|
||||
|
||||
if(document == null) {
|
||||
throw new NullPointerException("It is not allowed to pass the MetadataNodeListManager a null document reference.");
|
||||
}//if//
|
||||
|
||||
this.document = document;
|
||||
}//ElementListManager()//
|
||||
/**
|
||||
* Determines whether the value can be added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param value The value that may be added.
|
||||
* @return Whether the value can be added to the collection.
|
||||
*/
|
||||
public boolean canAdd(IManagedCollection managed, Object value, byte context) {
|
||||
return (super.canAdd(managed, value, context)) && (value instanceof MetadataNode || value instanceof Property);
|
||||
}//canAdd()//
|
||||
/**
|
||||
* Determines whether the user can make the collection immutable (unchangeable).
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @return Whether the collection immutable flag can be set.
|
||||
*/
|
||||
public boolean canMakeImmutable(IManagedCollection managed) {
|
||||
return false;
|
||||
}//canMakeImmutable()//
|
||||
/**
|
||||
* Determines whether the collection should ask the manager to allow an add operation.
|
||||
* @return Whether this manager will be asked for permission before an add operation.
|
||||
*/
|
||||
public boolean checkOnAdd() {
|
||||
return true;
|
||||
}//checkOnAdd()//
|
||||
/**
|
||||
* Determines whether the collection should notify the manager after an add operation occurs.
|
||||
* @return Whether this manager will be notified after an add operation.
|
||||
*/
|
||||
public boolean notifyOnPostAdd() {
|
||||
return true;
|
||||
}//notifyOnPostAdd()//
|
||||
/**
|
||||
* Determines whether the collection should notify the manager after a remove operation occurs.
|
||||
* @return Whether this manager will be notified after a remove operation.
|
||||
*/
|
||||
public boolean notifyOnPostRemove() {
|
||||
return true;
|
||||
}//notifyOnPostRemove()//
|
||||
/**
|
||||
* Allows the manager to provide functionality after a value has been added to the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param value The value that has be added.
|
||||
* @see #preAdd(Object)
|
||||
*/
|
||||
public void postAdd(IManagedCollection managed, Object value, byte context) {
|
||||
if(value instanceof Node) {
|
||||
((Node) value).setParent(document);
|
||||
}//if//
|
||||
|
||||
super.postAdd(managed, value, context);
|
||||
}//postAdd()//
|
||||
/**
|
||||
* Allows the manager to provide functionality after a value has been removed from the collection.
|
||||
* @param managed The collection that is being managed by this ICollectionManager.
|
||||
* @param value The value that has be removed.
|
||||
* @see #preRemove(Object)
|
||||
*/
|
||||
public void postRemove(IManagedCollection managed, Object value, byte context) {
|
||||
if(value instanceof Node) {
|
||||
((Node) value).setParent(null);
|
||||
}//if//
|
||||
|
||||
super.postRemove(managed, value, context);
|
||||
}//postRemove()//
|
||||
}//ElementListManager//
|
||||
218
Foundation/src/com/foundation/util/xml/Node.java
Normal file
218
Foundation/src/com/foundation/util/xml/Node.java
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
import com.common.util.*;
|
||||
|
||||
public class Node extends AbstractNode implements INode {
|
||||
/** The name of the node. */
|
||||
private String name = null;
|
||||
/** The global character offset of the first character of the start tag. */
|
||||
private int startTagTailStartCharacter = -1;
|
||||
/** The global character offset of the last character of the start tag. */
|
||||
private int startTagTailEndCharacter = -1;
|
||||
/** The global character offset of the last character of the start tag name. */
|
||||
private int startTagEndNameCharacter = -1;
|
||||
/** The global character offset of the first character of the ending tag. */
|
||||
private int endTagStartCharacter = -1;
|
||||
/** Whether the node has no end tag and was not properly (by XML standards) ended in the start tag. Example of a node where isEndless is true: <mynode attr='abc'>. */
|
||||
private boolean isEndless = false;
|
||||
/** Whether to display an end tag even if one is not necessary (set to true if reading and an end tag existed). */
|
||||
private boolean useEndTag = false;
|
||||
/**
|
||||
* Node constructor.
|
||||
*/
|
||||
public Node() {
|
||||
super();
|
||||
}//Node()//
|
||||
/**
|
||||
* Node constructor.
|
||||
* @param name The initial name for the node.
|
||||
*/
|
||||
public Node(String name) {
|
||||
super();
|
||||
|
||||
setName(name);
|
||||
}//Node()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#useEndTag()
|
||||
*/
|
||||
public boolean useEndTag() {
|
||||
return useEndTag;
|
||||
}//useEndTag()//
|
||||
/**
|
||||
* Sets whether the node should always display an end tag.
|
||||
* @param useEndTag Whether the node should display an end tag even if one is not required.
|
||||
*/
|
||||
public void useEndTag(boolean useEndTag) {
|
||||
this.useEndTag = useEndTag;
|
||||
}//useEndTag()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#isEndless()
|
||||
*/
|
||||
public boolean isEndless() {
|
||||
return isEndless;
|
||||
}//isEndless()//
|
||||
/**
|
||||
* Sets whether the node has no ending tag and the starting tag does not end with a slash.
|
||||
* <br>For example: <mynode attr='abc'>.
|
||||
* @param isEndless Whether the node does not have a proper XML ending.
|
||||
*/
|
||||
public void isEndless(boolean isEndless) {
|
||||
this.isEndless = isEndless;
|
||||
}//isEndless()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#getStartTagTailStartCharacter()
|
||||
*/
|
||||
public int getStartTagTailStartCharacter() {
|
||||
return startTagTailStartCharacter;
|
||||
}//getStartTagTailStartCharacter()//
|
||||
/**
|
||||
* Sets the global character offset of the first character of the start tag (inclusive).
|
||||
* @param startTagTailStartCharacter The index of the character from the beginning of the file.
|
||||
*/
|
||||
public void setStartTagTailStartCharacter(int startTagTailStartCharacter) {
|
||||
this.startTagTailStartCharacter = startTagTailStartCharacter;
|
||||
}//setStartTagTailStartCharacter()//
|
||||
/* (non-Javadoc)
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#getStartTagTailEndCharacter()
|
||||
*/
|
||||
public int getStartTagTailEndCharacter() {
|
||||
return startTagTailEndCharacter;
|
||||
}//getStartTagTailEndCharacter()//
|
||||
/**
|
||||
* Sets the global character offset of the last character of the start tag (inclusive).
|
||||
* @param startTagTailEndCharacter The index of the character from the beginning of the file.
|
||||
*/
|
||||
public void setStartTagTailEndCharacter(int startTagTailEndCharacter) {
|
||||
this.startTagTailEndCharacter = startTagTailEndCharacter;
|
||||
}//setStartTagTailEndCharacter()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#getStartTagEndNameCharacter()
|
||||
*/
|
||||
public int getStartTagEndNameCharacter() {
|
||||
return startTagEndNameCharacter;
|
||||
}//getStartTagEndNameCharacter()//
|
||||
/**
|
||||
* Sets the global character offset of the last character of the start tag name (inclusive).
|
||||
* @param startTagEndNameCharacter The index of the character from the beginning of the file.
|
||||
*/
|
||||
public void setStartTagEndNameCharacter(int startTagEndNameCharacter) {
|
||||
this.startTagEndNameCharacter = startTagEndNameCharacter;
|
||||
}//setStartTagEndNameCharacter()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.INode#getEndTagStartCharacter()
|
||||
*/
|
||||
public int getEndTagStartCharacter() {
|
||||
return endTagStartCharacter;
|
||||
}//getEndTagStartCharacter()//
|
||||
/**
|
||||
* Sets the global character offset of the first character of the ending tag (inclusive).
|
||||
* @param endTagStartCharacter The index of the character from the beginning of the file.
|
||||
*/
|
||||
public void setEndTagStartCharacter(int endTagStartCharacter) {
|
||||
this.endTagStartCharacter = endTagStartCharacter;
|
||||
}//setEndTagStartCharacter()//
|
||||
/**
|
||||
* Gets the name of the node.
|
||||
* @return The node's name which is how the node is identified.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}//getName()//
|
||||
/**
|
||||
* Determines whether this is an IComment instance.
|
||||
* @return Whether this instance implements IComment.
|
||||
*/
|
||||
public boolean isComment() {
|
||||
return false;
|
||||
}//isComment()//
|
||||
/**
|
||||
* Determines whether this is an INode instance.
|
||||
* @return Whether this instance implements INode.
|
||||
*/
|
||||
public boolean isNode() {
|
||||
return true;
|
||||
}//isNode()//
|
||||
/**
|
||||
* Determines whether this is an IText instance.
|
||||
* @return Whether this instance implements IText.
|
||||
*/
|
||||
public boolean isText() {
|
||||
return false;
|
||||
}//isText()//
|
||||
/**
|
||||
* Sets the name of the node.
|
||||
* @param name The node's name which is how the node is identified.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}//setName()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IElement#write(com.foundation.util.xml.XmlOutputStream, com.foundation.util.xml.DocumentBuilder, java.lang.String, java.lang.String, boolean)
|
||||
*/
|
||||
public void write(XmlOutputStream out, DocumentBuilder builder, String prepend, String postpend, boolean compact) throws java.io.IOException {
|
||||
IIterator iterator = null;
|
||||
|
||||
out.write(prepend);
|
||||
out.write('<');
|
||||
out.write(getName());
|
||||
iterator = getAttributes().iterator();
|
||||
|
||||
//Write the attributes.//
|
||||
while(iterator.hasNext()) {
|
||||
if(iterator.hasNext()) {
|
||||
out.write(' ');
|
||||
}//if//
|
||||
|
||||
((IAttribute) iterator.next()).write(out, builder, null, null, compact);
|
||||
}//while//
|
||||
|
||||
//Write the child elements.//
|
||||
if(getElements().getSize() == 1 && getElements().getFirst() instanceof IText) {
|
||||
out.write('>');
|
||||
((IText) getElements().getFirst()).write(out, builder, "", "", compact);
|
||||
out.write("</");
|
||||
out.write(getName());
|
||||
out.write('>');
|
||||
}//if//
|
||||
else if(getElements().getSize() > 0 || useEndTag()) {
|
||||
out.write('>');
|
||||
out.write(postpend);
|
||||
iterator = getElements().iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
IElement element = (IElement) iterator.next();
|
||||
|
||||
element.write(out, builder, compact ? prepend : "\t" + prepend, postpend, compact);
|
||||
}//while//
|
||||
|
||||
out.write(prepend);
|
||||
out.write("</");
|
||||
out.write(getName());
|
||||
out.write('>');
|
||||
}//else if//
|
||||
else {
|
||||
if(isEndless()) {
|
||||
out.write(">");
|
||||
}//if//
|
||||
else {
|
||||
out.write("/>");
|
||||
}//else//
|
||||
}//else//
|
||||
|
||||
out.write(postpend);
|
||||
}//write()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
return "Node: " + getName() + " Indicies: " + getStartCharacter() + ", " + getStartTagEndNameCharacter() + ", " + getStartTagTailStartCharacter() + ", " + getStartTagTailEndCharacter() + ", " + getEndTagStartCharacter() + ", " + getEndCharacter();
|
||||
}//toString()//
|
||||
}//Node//
|
||||
287
Foundation/src/com/foundation/util/xml/Property.java
Normal file
287
Foundation/src/com/foundation/util/xml/Property.java
Normal file
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2009 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.common.util.optimized.CharHashSet;
|
||||
|
||||
/*
|
||||
* Implements a simple XML property which is a member of a node.
|
||||
*/
|
||||
public class Property extends Element implements IAttribute {
|
||||
public static final CharHashSet ENCODED_CHARS_DOUBLE_QUOTES;
|
||||
public static final CharHashSet ENCODED_CHARS_SINGLE_QUOTES;
|
||||
public static final CharHashSet ENCODED_CHARS_NO_QUOTES;
|
||||
public static final CharHashSet ENCODED_CHARS_DOUBLE_QUOTES_PLUS_SLASH;
|
||||
public static final CharHashSet ENCODED_CHARS_SINGLE_QUOTES_PLUS_SLASH;
|
||||
public static final CharHashSet ENCODED_CHARS_NO_QUOTES_PLUS_SLASH;
|
||||
|
||||
static {
|
||||
ENCODED_CHARS_DOUBLE_QUOTES = new CharHashSet(DocumentBuilder.defaultEncodedCharacters, DocumentBuilder.defaultEncodedCharacters.getSize() + 10, CharHashSet.DEFAULT_LOAD_FACTOR, CharHashSet.STYLE_NO_DUPLICATES);
|
||||
ENCODED_CHARS_DOUBLE_QUOTES.addAll(new char[] {'"', '\n', '\r', '&', '<', '>'});
|
||||
ENCODED_CHARS_DOUBLE_QUOTES.isChangeable(false);
|
||||
ENCODED_CHARS_SINGLE_QUOTES = new CharHashSet(DocumentBuilder.defaultEncodedCharacters, DocumentBuilder.defaultEncodedCharacters.getSize() + 10, CharHashSet.DEFAULT_LOAD_FACTOR, CharHashSet.STYLE_NO_DUPLICATES);
|
||||
ENCODED_CHARS_SINGLE_QUOTES.addAll(new char[] {'\'', '\n', '\r', '&', '<', '>'});
|
||||
ENCODED_CHARS_SINGLE_QUOTES.isChangeable(false);
|
||||
ENCODED_CHARS_NO_QUOTES = new CharHashSet(DocumentBuilder.defaultEncodedCharacters, DocumentBuilder.defaultEncodedCharacters.getSize() + 10, CharHashSet.DEFAULT_LOAD_FACTOR, CharHashSet.STYLE_NO_DUPLICATES);
|
||||
ENCODED_CHARS_NO_QUOTES.addAll(new char[] {' ', '\n', '\r', '&', '<', '>'});
|
||||
ENCODED_CHARS_NO_QUOTES.isChangeable(false);
|
||||
|
||||
ENCODED_CHARS_DOUBLE_QUOTES_PLUS_SLASH = new CharHashSet(DocumentBuilder.defaultEncodedCharacters, DocumentBuilder.defaultEncodedCharacters.getSize() + 10, CharHashSet.DEFAULT_LOAD_FACTOR, CharHashSet.STYLE_NO_DUPLICATES);
|
||||
ENCODED_CHARS_DOUBLE_QUOTES_PLUS_SLASH.addAll(new char[] {'"', '\n', '\r', '&', '<', '>', '\\'});
|
||||
ENCODED_CHARS_DOUBLE_QUOTES_PLUS_SLASH.isChangeable(false);
|
||||
ENCODED_CHARS_SINGLE_QUOTES_PLUS_SLASH = new CharHashSet(DocumentBuilder.defaultEncodedCharacters, DocumentBuilder.defaultEncodedCharacters.getSize() + 10, CharHashSet.DEFAULT_LOAD_FACTOR, CharHashSet.STYLE_NO_DUPLICATES);
|
||||
ENCODED_CHARS_SINGLE_QUOTES_PLUS_SLASH.addAll(new char[] {'\'', '\n', '\r', '&', '<', '>', '\\'});
|
||||
ENCODED_CHARS_SINGLE_QUOTES_PLUS_SLASH.isChangeable(false);
|
||||
ENCODED_CHARS_NO_QUOTES_PLUS_SLASH = new CharHashSet(DocumentBuilder.defaultEncodedCharacters, DocumentBuilder.defaultEncodedCharacters.getSize() + 10, CharHashSet.DEFAULT_LOAD_FACTOR, CharHashSet.STYLE_NO_DUPLICATES);
|
||||
ENCODED_CHARS_NO_QUOTES_PLUS_SLASH.addAll(new char[] {' ', '\n', '\r', '&', '<', '>', '\\'});
|
||||
ENCODED_CHARS_NO_QUOTES_PLUS_SLASH.isChangeable(false);
|
||||
}//static//
|
||||
|
||||
/** The type of quotes to wrapper the value in. Note that none requires that the value have no spacing in it. */
|
||||
private int quoteType = QUOTE_TYPE_DOUBLE;
|
||||
/** The name of the attribute. */
|
||||
private String name = null;
|
||||
/** The attribute value, or null if there isn't one (ie an attribute in the xml followed by no equals sign). */
|
||||
private String value = null;
|
||||
/** Whether the element has errors in the value. */
|
||||
private boolean hasValueErrors = false;
|
||||
/** This will be non-negative no matter what, though if there is no value then this will be the same as the endCharacter value. */
|
||||
private int valueStartCharacter = -1;
|
||||
/** If this is not -1, then a value was specified and the endCharacter refers the the last character of the value (which would be the ending quote). */
|
||||
private int nameEndCharacter = -1;
|
||||
/**
|
||||
* Property constructor.
|
||||
* @param name The name of the attibute which cannot later be changed because that is what uniquely identifies this attribute.
|
||||
*/
|
||||
public Property(String name) {
|
||||
super();
|
||||
|
||||
setName(name);
|
||||
}//Property()//
|
||||
/**
|
||||
* Property constructor.
|
||||
* @param name The name of the attibute which cannot later be changed because that is what uniquely identifies this attribute.
|
||||
* @param value The initial attribute value.
|
||||
*/
|
||||
public Property(String name, String value) {
|
||||
super();
|
||||
|
||||
setName(name);
|
||||
setValue(value);
|
||||
}//Property()//
|
||||
/**
|
||||
* Property constructor.
|
||||
* @param name The name of the attibute which cannot later be changed because that is what uniquely identifies this attribute.
|
||||
* @param value The initial attribute value.
|
||||
* @param quoteType One of the QUOTE_TYPE_xx identifiers.
|
||||
*/
|
||||
public Property(String name, String value, int quoteType) {
|
||||
super();
|
||||
|
||||
setName(name);
|
||||
setValue(value);
|
||||
setQuoteType(quoteType);
|
||||
}//Property()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAttribute#getQuoteType()
|
||||
*/
|
||||
public int getQuoteType() {
|
||||
return quoteType;
|
||||
}//getQuoteType()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAttribute#setQuoteType(int)
|
||||
*/
|
||||
public void setQuoteType(int quoteType) {
|
||||
this.quoteType = quoteType;
|
||||
}//setQuoteType()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAttribute#getQuoteCharacterCount()
|
||||
*/
|
||||
public int getQuoteCharacterCount() {
|
||||
return quoteType == QUOTE_TYPE_NONE ? 0 : 1;
|
||||
}//getQuoteCharacterCount()//
|
||||
/**
|
||||
* Gets the name of the attribute.
|
||||
* @return The attribute's name which is how the attribute is identified.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}//getName()//
|
||||
/**
|
||||
* Sets the name of the attribute.
|
||||
* @param name The attribute's name which is how the attribute is identified.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}//setName()//
|
||||
/**
|
||||
* Gets the attribute's value.
|
||||
* @return The value associated with this attribute.
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}//getValue()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAttribute#getValue(boolean, boolean)
|
||||
*/
|
||||
public String getValue(boolean trim, boolean emptySameAsNull) {
|
||||
String value = this.value;
|
||||
|
||||
if(value != null) {
|
||||
if(trim) {
|
||||
value = value.trim();
|
||||
}//if//
|
||||
|
||||
if((emptySameAsNull) && (value.length() == 0)) {
|
||||
value = null;
|
||||
}//if//
|
||||
}//if//
|
||||
|
||||
return value;
|
||||
}//getValue()//
|
||||
/**
|
||||
* Sets the attribute's value.
|
||||
* @param value The value associated with this attribute.
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}//setValue()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.Element#isComment()
|
||||
*/
|
||||
public boolean isComment() {
|
||||
return false;
|
||||
}//isComment()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.Element#isNode()
|
||||
*/
|
||||
public boolean isNode() {
|
||||
return false;
|
||||
}//isNode()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.Element#isText()
|
||||
*/
|
||||
public boolean isText() {
|
||||
return false;
|
||||
}//isText()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.Element#write(com.foundation.util.xml.XmlOutputStream, com.foundation.util.xml.DocumentBuilder, java.lang.String, java.lang.String, boolean)
|
||||
*/
|
||||
public void write(XmlOutputStream out, DocumentBuilder builder, String prepend, String postpend, boolean compact) throws IOException {
|
||||
out.write(name);
|
||||
|
||||
if(value != null) {
|
||||
CharHashSet encodedCharacters = null;
|
||||
|
||||
out.write('=');
|
||||
|
||||
switch(quoteType) {
|
||||
case QUOTE_TYPE_DOUBLE: {
|
||||
out.write('"');
|
||||
|
||||
//When allowing encoded characters, the XML reader will read the \ character inside quotes and interperate it as a control character, otherwise it is just a slash.//
|
||||
if(builder.allowEncodedCharacters()) {
|
||||
encodedCharacters = ENCODED_CHARS_DOUBLE_QUOTES_PLUS_SLASH;
|
||||
}//if//
|
||||
else {
|
||||
encodedCharacters = ENCODED_CHARS_DOUBLE_QUOTES;
|
||||
}//else//
|
||||
break;
|
||||
}//case//
|
||||
case QUOTE_TYPE_SINGLE: {
|
||||
out.write('\'');
|
||||
|
||||
//When allowing encoded characters, the XML reader will read the \ character inside quotes and interperate it as a control character, otherwise it is just a slash.//
|
||||
if(builder.allowEncodedCharacters()) {
|
||||
encodedCharacters = ENCODED_CHARS_SINGLE_QUOTES_PLUS_SLASH;
|
||||
}//if//
|
||||
else {
|
||||
encodedCharacters = ENCODED_CHARS_SINGLE_QUOTES;
|
||||
}//else//
|
||||
break;
|
||||
}//case//
|
||||
default: {
|
||||
//When allowing encoded characters, the XML reader will read the \ character inside quotes and interperate it as a control character, otherwise it is just a slash.//
|
||||
if(builder.allowEncodedCharacters()) {
|
||||
encodedCharacters = ENCODED_CHARS_NO_QUOTES_PLUS_SLASH;
|
||||
}//if//
|
||||
else {
|
||||
encodedCharacters = ENCODED_CHARS_NO_QUOTES;
|
||||
}//else//
|
||||
break;
|
||||
}//default//
|
||||
}//switch//
|
||||
|
||||
out.write(builder.preProcess(value, encodedCharacters));
|
||||
|
||||
switch(quoteType) {
|
||||
case QUOTE_TYPE_DOUBLE: {
|
||||
out.write('"');
|
||||
break;
|
||||
}//case//
|
||||
case QUOTE_TYPE_SINGLE: {
|
||||
out.write('\'');
|
||||
break;
|
||||
}//case//
|
||||
default: {
|
||||
break;
|
||||
}//default//
|
||||
}//switch//
|
||||
}//if//
|
||||
}//write()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAttribute#getNameEndCharacter()
|
||||
*/
|
||||
public int getNameEndCharacter() {
|
||||
return nameEndCharacter;
|
||||
}//getNameEndCharacter()//
|
||||
/**
|
||||
* Sets the index of the last value character.
|
||||
* <p>This will be non-negative no matter what, though if there is no value then this will be the same as the endCharacter value.
|
||||
* @param nameEndCharacter The last character in the value.
|
||||
*/
|
||||
public void setNameEndCharacter(int nameEndCharacter) {
|
||||
this.nameEndCharacter = nameEndCharacter;
|
||||
}//setNameEndCharacter()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAttribute#getValueStartCharacter()
|
||||
*/
|
||||
public int getValueStartCharacter() {
|
||||
return valueStartCharacter;
|
||||
}//getValueStartCharacter()//
|
||||
/**
|
||||
* Sets the index of the first value character (including the quotes).
|
||||
* <p>If this is not -1, then a value was specified and the endCharacter refers the the last character of the value (which would be the ending quote).
|
||||
* @param valueStartCharacter The first character in the value.
|
||||
*/
|
||||
public void setValueStartCharacter(int valueStartCharacter) {
|
||||
this.valueStartCharacter = valueStartCharacter;
|
||||
}//setValueStartCharacter()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.xml.IAttribute#hasValueErrors()
|
||||
*/
|
||||
public boolean hasValueErrors() {
|
||||
return hasValueErrors;
|
||||
}//hasValueErrors()//
|
||||
/**
|
||||
* Determines whether the element has errors in the value.
|
||||
* <p>The hasErrors flag represents errors only in the attribute name.
|
||||
* @param hasValueErrors Whether the reader detected errors in the value.
|
||||
*/
|
||||
public void hasValueErrors(boolean hasValueErrors) {
|
||||
this.hasValueErrors = hasValueErrors;
|
||||
}//hasValueErrors()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
return "Attribute: " + getName() + " Indicies: " + getStartCharacter() + ", " + getNameEndCharacter() + ", " + getValueStartCharacter() + ", " + getEndCharacter();
|
||||
}//toString()//
|
||||
}//Property//
|
||||
84
Foundation/src/com/foundation/util/xml/Text.java
Normal file
84
Foundation/src/com/foundation/util/xml/Text.java
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
import com.common.util.optimized.CharHashSet;
|
||||
|
||||
public class Text extends Element implements IText {
|
||||
public static final CharHashSet ENCODED_CHARS;
|
||||
|
||||
static {
|
||||
ENCODED_CHARS = new CharHashSet(DocumentBuilder.defaultEncodedCharacters, DocumentBuilder.defaultEncodedCharacters.getSize() + 10, CharHashSet.DEFAULT_LOAD_FACTOR, CharHashSet.STYLE_NO_DUPLICATES);
|
||||
ENCODED_CHARS.addAll(new char[] {'&', '<', '>'});
|
||||
}//static//
|
||||
|
||||
private String text = null;
|
||||
/**
|
||||
* Text constructor.
|
||||
*/
|
||||
public Text() {
|
||||
super();
|
||||
}//Text()//
|
||||
/**
|
||||
* Text constructor.
|
||||
* @param text The initial textual string associated with this text object.
|
||||
*/
|
||||
public Text(String text) {
|
||||
super();
|
||||
|
||||
setText(text);
|
||||
}//Text()//
|
||||
/**
|
||||
* Gets the text for this text element.
|
||||
* @return The text associated with this text element.
|
||||
*/
|
||||
public String getText() {
|
||||
return text;
|
||||
}//getText()//
|
||||
/**
|
||||
* Determines whether this is an IComment instance.
|
||||
* @return Whether this instance implements IComment.
|
||||
*/
|
||||
public boolean isComment() {
|
||||
return false;
|
||||
}//isComment()//
|
||||
/**
|
||||
* Determines whether this is an INode instance.
|
||||
* @return Whether this instance implements INode.
|
||||
*/
|
||||
public boolean isNode() {
|
||||
return false;
|
||||
}//isNode()//
|
||||
/**
|
||||
* Determines whether this is an IText instance.
|
||||
* @return Whether this instance implements IText.
|
||||
*/
|
||||
public boolean isText() {
|
||||
return true;
|
||||
}//isText()//
|
||||
/**
|
||||
* Sets the text for this text element.
|
||||
* @param text The text associated with this text element.
|
||||
*/
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}//setText()//
|
||||
/**
|
||||
* Writes the element to the buffer.
|
||||
* @param out The output stream that will be given the formatted element data.
|
||||
* @param builder The document builder that will provide guidance.
|
||||
* @param prepend The string that will be added before any other characters in a perticular line.
|
||||
* @param postpend The string that will be added after any other characters in a perticular line.
|
||||
* @param compact Whether the output should be kept compact, or should include formatting characters.
|
||||
*/
|
||||
public void write(XmlOutputStream out, DocumentBuilder builder, String prepend, String postpend, boolean compact) throws java.io.IOException {
|
||||
out.write(prepend);
|
||||
out.write(builder.preProcess(getText(), ENCODED_CHARS));
|
||||
out.write(postpend);
|
||||
}//write()//
|
||||
}//Text//
|
||||
220
Foundation/src/com/foundation/util/xml/XmlInputStream.java
Normal file
220
Foundation/src/com/foundation/util/xml/XmlInputStream.java
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2008 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import com.common.io.StreamSupport;
|
||||
|
||||
/**
|
||||
* <p>TODO: Read the encoding from the xml metadata if available.</p>
|
||||
*/
|
||||
class XmlInputStream {
|
||||
private static final char lineSeparator;
|
||||
private String input = null;
|
||||
/** The index of the next character in the stream (the one retrieved by calling <code>next()</code>). */
|
||||
private int nextCharacterIndex = 0;
|
||||
private int nextLineIndex = 0;
|
||||
private int nextLineCharacterOffset = 0;
|
||||
private int currentCharacterIndex = 0;
|
||||
private int currentLineIndex = 0;
|
||||
private int currentLineCharacterOffset = 0;
|
||||
/** The sections of the input to ignore. The internal indices must still be maintained relative to the entire text, but the ignored section characters will not be reported to the user of the stream. */
|
||||
private int[] ignoredSections = null;
|
||||
/** The total number of characters to be skipped due to ignored sections. */
|
||||
private int totalSkippedCharacters = 0;
|
||||
/** The current number of characters that have been skipped due to ignored sections. */
|
||||
private int currentSkippedCharacters = 0;
|
||||
/** The next ignored section in the ignoredSections array. */
|
||||
private int nextIgnoredSectionIndex = 0;
|
||||
|
||||
static {
|
||||
String separator = System.getProperty("line.separator");
|
||||
|
||||
lineSeparator = separator.charAt(separator.length() - 1);
|
||||
}//static//
|
||||
/**
|
||||
* XmlInputStream constructor.
|
||||
* <p>Note: Currently we read the entire text imediately.</p>
|
||||
* @param in The stream containing the XML text.
|
||||
* @param encoding The encoding of the XML text.
|
||||
*/
|
||||
XmlInputStream(InputStream in, String encoding) throws IOException {
|
||||
this(in, encoding, null);
|
||||
}//XmlInputStream()//
|
||||
/**
|
||||
* XmlInputStream constructor.
|
||||
* @param input The XML text.
|
||||
*/
|
||||
XmlInputStream(String input) throws IOException {
|
||||
this(input, null);
|
||||
}//XmlInputStream()//
|
||||
/**
|
||||
* XmlInputStream constructor.
|
||||
* <p>Note: Currently we read the entire text imediately.</p>
|
||||
* @param in The stream containing the XML text.
|
||||
* @param encoding The encoding of the XML text.
|
||||
* @param ignoredSections The sections of the input to ignore. The internal indices must still be maintained relative to the entire text, but the ignored section characters will not be reported to the user of the stream.
|
||||
*/
|
||||
XmlInputStream(InputStream in, String encoding, int[] ignoredSections) throws IOException {
|
||||
this(StreamSupport.readText(in, encoding), ignoredSections);
|
||||
}//XmlInputStream()//
|
||||
/**
|
||||
* XmlInputStream constructor.
|
||||
* @param input The XML text.
|
||||
* @param ignoredSections The sections of the input to ignore. The internal indices must still be maintained relative to the entire text, but the ignored section characters will not be reported to the user of the stream. The ignored sections must be an even array of ascending start/stop index pairs where the start & stop may be equal, but the next start must be at least one greater than the previous stop index.
|
||||
*/
|
||||
XmlInputStream(String input, int[] ignoredSections) throws IOException {
|
||||
super();
|
||||
this.input = input;
|
||||
this.ignoredSections = ignoredSections;
|
||||
|
||||
if(ignoredSections != null) {
|
||||
for(int index = 0; index < ignoredSections.length; index += 2) {
|
||||
totalSkippedCharacters += ignoredSections[index + 1] - ignoredSections[index] + 1;
|
||||
}//for//
|
||||
}//if//
|
||||
}//XmlInputStream()//
|
||||
/**
|
||||
* Determines whether there are enough characters in the stream to peek at the character at the desired offset.
|
||||
* @param offset The offset of the character the user wants to view. A value of zero will peek at the next character.
|
||||
* @return Will be true if such a character exists.
|
||||
*/
|
||||
public boolean canPeek(int offset) throws IOException {
|
||||
return input.length() - (totalSkippedCharacters - currentSkippedCharacters) > nextCharacterIndex + offset;
|
||||
}//canPeek()//
|
||||
/**
|
||||
* The offset of the next character in the context of the current line.
|
||||
* @return The offset of the next character in the current line. This offset starts at zero (the beginning of the line) an increments until the line ends.
|
||||
*/
|
||||
public int getNextLineCharacterOffset() {
|
||||
return nextLineCharacterOffset;
|
||||
}//getNextLineCharacterOffset()//
|
||||
/**
|
||||
* Gets the current line index (for the next character to be retrieved).
|
||||
* @return The index of the line that the next character resides on where lines begin with index zero.
|
||||
*/
|
||||
public int getNextLineIndex() {
|
||||
return nextLineIndex;
|
||||
}//getNextLineIndex()//
|
||||
/**
|
||||
* Gets the index of the next character within the entire stream.
|
||||
* @return The stream character index of the next character where the first stream character is index zero.
|
||||
*/
|
||||
public int getNextCharacterIndex() {
|
||||
return nextCharacterIndex;
|
||||
}//getNextCharacterIndex()//
|
||||
/**
|
||||
* The offset of the current character in the context of the current line.
|
||||
* @return The offset of the current character in the current line. This offset starts at zero (the beginning of the line) an increments until the line ends.
|
||||
*/
|
||||
public int getCurrentLineCharacterOffset() {
|
||||
return currentLineCharacterOffset;
|
||||
}//getCurrentLineCharacterOffset()//
|
||||
/**
|
||||
* Gets the current line index (for the current character to be retrieved).
|
||||
* @return The index of the line that the current character resides on where lines begin with index zero.
|
||||
*/
|
||||
public int getCurrentLineIndex() {
|
||||
return currentLineIndex;
|
||||
}//getCurrentLineIndex()//
|
||||
/**
|
||||
* Gets the index of the current character within the entire stream.
|
||||
* @return The stream character index of the current character where the first stream character is index zero.
|
||||
*/
|
||||
public int getCurrentCharacterIndex() {
|
||||
return currentCharacterIndex;
|
||||
}//getCurrentCharacterIndex()//
|
||||
/**
|
||||
* Determines whether there is a next character in the stream.
|
||||
* @return Will be true if there is at least one more character in the stream.
|
||||
*/
|
||||
public boolean hasNext() throws IOException {
|
||||
return canPeek(0);
|
||||
}//hasNext()//
|
||||
/**
|
||||
* Gets the next character in the stream.
|
||||
* @return The next character in the stream. This character will not be retrievable again from this stream.
|
||||
*/
|
||||
public char next() throws IOException {
|
||||
char result = input.charAt(nextCharacterIndex);
|
||||
|
||||
currentCharacterIndex = nextCharacterIndex;
|
||||
currentLineCharacterOffset = nextLineCharacterOffset;
|
||||
currentLineIndex = nextLineIndex;
|
||||
|
||||
//Track the character index in the stream.//
|
||||
nextCharacterIndex++;
|
||||
nextLineCharacterOffset++;
|
||||
|
||||
//Track the line and line offset indexes in the stream.//
|
||||
if(result == lineSeparator) {
|
||||
nextLineCharacterOffset = 0;
|
||||
nextLineIndex++;
|
||||
}//if//
|
||||
|
||||
//If we have ignored sections then skip them now if the next index falls within one such section.//
|
||||
if(ignoredSections != null && nextIgnoredSectionIndex < ignoredSections.length && nextCharacterIndex == ignoredSections[nextIgnoredSectionIndex]) {
|
||||
int ignoredLength = 0;
|
||||
char ch = result;
|
||||
|
||||
//Iteratively identify the ignored length since it is possible that two or more ignored sections are consecutive.//
|
||||
while(nextIgnoredSectionIndex < ignoredSections.length && nextCharacterIndex + ignoredLength == ignoredSections[nextIgnoredSectionIndex]) {
|
||||
ignoredLength += ignoredSections[nextIgnoredSectionIndex + 1] - ignoredSections[nextIgnoredSectionIndex] + 1;
|
||||
nextIgnoredSectionIndex += 2;
|
||||
}//while//
|
||||
|
||||
currentSkippedCharacters += ignoredLength;
|
||||
nextCharacterIndex += ignoredLength;
|
||||
|
||||
//Skip over the ignored characters, but also track the next indices.//
|
||||
while(ignoredLength-- > 0) {
|
||||
nextLineCharacterOffset++;
|
||||
|
||||
if(ch == lineSeparator) {
|
||||
nextLineCharacterOffset = 0;
|
||||
nextLineIndex++;
|
||||
}//if//
|
||||
|
||||
ch = input.charAt(nextCharacterIndex);
|
||||
}//while//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//next()//
|
||||
/**
|
||||
* Peeks at one of the next characters in the stream.
|
||||
* @param offset The positive offset of the character to peek at. If this is zero, then the next character returned by the next() method will be returned.
|
||||
* @return The character at the given offset in the stream.
|
||||
*/
|
||||
public char peek(int offset) throws IOException {
|
||||
int index = nextCharacterIndex + offset;
|
||||
|
||||
if(ignoredSections != null && nextIgnoredSectionIndex < ignoredSections.length && ignoredSections[nextIgnoredSectionIndex] <= index) {
|
||||
int ignoredSectionIndex = nextIgnoredSectionIndex;
|
||||
|
||||
while(ignoredSectionIndex < ignoredSections.length && ignoredSections[ignoredSectionIndex] <= index) {
|
||||
int ignoredLength = ignoredSections[nextIgnoredSectionIndex + 1] - ignoredSections[nextIgnoredSectionIndex] + 1;
|
||||
|
||||
index += ignoredLength;
|
||||
ignoredSectionIndex += 2;
|
||||
}//while//
|
||||
}//if//
|
||||
|
||||
return input.charAt(index);
|
||||
}//peek()//
|
||||
/**
|
||||
* Skips the next <code>count</code> characters in the stream. This is the same as calling the <code>next()<code> method <code>count</code> times without saving the results.
|
||||
* @param count The number of characters to be skipped.
|
||||
*/
|
||||
public void skip(int count) throws IOException {
|
||||
while(count-- > 0) {
|
||||
next();
|
||||
}//while//
|
||||
}//next()//
|
||||
}//XmlInputStream//
|
||||
75
Foundation/src/com/foundation/util/xml/XmlOutputStream.java
Normal file
75
Foundation/src/com/foundation/util/xml/XmlOutputStream.java
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2007 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.foundation.util.xml;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
/*
|
||||
* Wrappers any output stream to provide streaming for an XML document.
|
||||
* <p>TODO: Read the encoding from the xml metadata if available.</p>
|
||||
*/
|
||||
class XmlOutputStream extends java.io.OutputStream {
|
||||
private static final int CHARACTER_BUFFER_SIZE = 1000;
|
||||
private java.io.OutputStream out = null;
|
||||
//private CharsetEncoder encoder = null;
|
||||
//private CharBuffer charBuffer = CharBuffer.allocate(CHARACTER_BUFFER_SIZE);
|
||||
//private ByteBuffer byteBuffer = null;
|
||||
/**
|
||||
* XmlOutputStream constructor.
|
||||
* @param out The output stream to wrapper.
|
||||
* @param encoding The character set encoding to use.
|
||||
*/
|
||||
XmlOutputStream(java.io.OutputStream out, String encoding) {
|
||||
super();
|
||||
|
||||
//this.encoder = Charset.forName(encoding).newEncoder();
|
||||
this.out = out;
|
||||
//this.byteBuffer = ByteBuffer.allocate(((int) Math.ceil(encoder.maxBytesPerChar())) * CHARACTER_BUFFER_SIZE);
|
||||
}//XmlOutputStream()//
|
||||
/**
|
||||
* Writes a string to the stream.
|
||||
* @param string The string to append to this stream.
|
||||
*/
|
||||
public void write(char ch) throws java.io.IOException {
|
||||
//TODO: For some reason using the character buffer and byte buffer doesn't work. The encoder screws up the byte buffer. This should be debugged at some point since the alternative is inefficient and possibly buggy.
|
||||
//byteBuffer.rewind();
|
||||
//charBuffer.rewind();
|
||||
//charBuffer.append(ch);
|
||||
//encoder.encode(charBuffer, byteBuffer, false);
|
||||
//out.write(byteBuffer.array(), 0, byteBuffer.position());
|
||||
write("" + ch);
|
||||
}//write()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.io.OutputStream#write(int)
|
||||
*/
|
||||
public void write(int b) throws java.io.IOException {
|
||||
out.write(b);
|
||||
}//write()//
|
||||
/**
|
||||
* Writes a string to the stream.
|
||||
* @param string The string to append to this stream.
|
||||
*/
|
||||
public void write(String string) throws java.io.IOException {
|
||||
/*
|
||||
int offset = 0;
|
||||
|
||||
while(offset < string.length()) {
|
||||
byteBuffer.rewind();
|
||||
charBuffer.rewind();
|
||||
charBuffer.append(string.length() - offset > CHARACTER_BUFFER_SIZE ? string.substring(offset, offset + CHARACTER_BUFFER_SIZE) : offset == 0 ? string : string.substring(offset));
|
||||
encoder.encode(charBuffer, byteBuffer, false);
|
||||
out.write(byteBuffer.array(), 0, byteBuffer.position());
|
||||
offset += CHARACTER_BUFFER_SIZE;
|
||||
}//while//
|
||||
*/
|
||||
out.write(string.getBytes("UTF8"));
|
||||
}//write()//
|
||||
}//XmlOutputStream//
|
||||
Reference in New Issue
Block a user