276 lines
8.5 KiB
Java
276 lines
8.5 KiB
Java
|
|
/*
|
||
|
|
* Copyright (c) 2006,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.view;
|
||
|
|
|
||
|
|
import com.common.debug.Debug;
|
||
|
|
import com.common.util.IIterator;
|
||
|
|
import com.foundation.event.EventSupport;
|
||
|
|
|
||
|
|
public class SingleAssociationContainer extends AssociationContainer implements IValueHolderListener {
|
||
|
|
/** A simple flag that turns thread verification on and off. */
|
||
|
|
private static final boolean VERIFY_THREAD = true;
|
||
|
|
|
||
|
|
private SingleAssociation[] associations = null;
|
||
|
|
private SingleAssociation firstNode = null;
|
||
|
|
private SingleAssociation lastNode = null;
|
||
|
|
private Object row = null;
|
||
|
|
private String valueHolderName = null;
|
||
|
|
private EventSupport eventSupport = null;
|
||
|
|
private IValueHolder valueHolder = null;
|
||
|
|
/**
|
||
|
|
* AssociationContainer constructor.
|
||
|
|
* @param valueHolderName The name of the value holder whose value will be the input for the associations.
|
||
|
|
* @param associations The associations that are the roots for the single resource association that will be using them.
|
||
|
|
*/
|
||
|
|
public SingleAssociationContainer(String valueHolderName, SingleAssociation[] associations) {
|
||
|
|
this.valueHolderName = valueHolderName;
|
||
|
|
this.associations = associations;
|
||
|
|
}//AssociationContainer()//
|
||
|
|
/**
|
||
|
|
* Locates the value holder by looking in the component's parents (and the component its self if it is a container) until a value holder with the given name is found.
|
||
|
|
* <p>Note: The name is not case sensitive.
|
||
|
|
* @return The found value holder, or null if one could not be found.
|
||
|
|
*/
|
||
|
|
protected IValueHolder locateValueHolder(IAbstractComponent component) {
|
||
|
|
IAbstractContainer container = null;
|
||
|
|
IValueHolder result = null;
|
||
|
|
|
||
|
|
if(component instanceof IAbstractContainer) {
|
||
|
|
container = (IAbstractContainer) component;
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
container = component.getContainer();
|
||
|
|
}//else//
|
||
|
|
|
||
|
|
while((result == null) && (container != null)) {
|
||
|
|
IIterator iterator = container.getComponents().iterator();
|
||
|
|
|
||
|
|
while((result == null) && (iterator.hasNext())) {
|
||
|
|
Object next = iterator.next();
|
||
|
|
|
||
|
|
if((next instanceof IValueHolder) && (((IValueHolder) next).getName().equalsIgnoreCase(valueHolderName))) {
|
||
|
|
result = (IValueHolder) next;
|
||
|
|
}//if//
|
||
|
|
}//while//
|
||
|
|
|
||
|
|
container = container.getContainer();
|
||
|
|
}//while//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}//locateValueHolder()//
|
||
|
|
/**
|
||
|
|
* Initializes the container of associations.
|
||
|
|
*/
|
||
|
|
public void initialize() {
|
||
|
|
if(associations != null) {
|
||
|
|
for(int index = 0; index < associations.length; index++) {
|
||
|
|
associations[index].initialize(this);
|
||
|
|
}//for//
|
||
|
|
}//if//
|
||
|
|
}//initialize()//
|
||
|
|
/**
|
||
|
|
* Releases the container of associations.
|
||
|
|
*/
|
||
|
|
public void release() {
|
||
|
|
if(associations != null) {
|
||
|
|
for(int index = 0; index < associations.length; index++) {
|
||
|
|
associations[index].release();
|
||
|
|
}//for//
|
||
|
|
}//if//
|
||
|
|
}//release()//
|
||
|
|
/**
|
||
|
|
* Registers the associations.
|
||
|
|
*/
|
||
|
|
public void register() {
|
||
|
|
SingleAssociation association = null;
|
||
|
|
|
||
|
|
if(valueHolderName != null) {
|
||
|
|
if(valueHolder == null) {
|
||
|
|
valueHolder = locateValueHolder(getResourceAssociation().getComponent());
|
||
|
|
valueHolder.registerListener(this);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
row = valueHolder.getValue();
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Find the first applicable association.//
|
||
|
|
for(int index = 0; association == null && index < associations.length; index++) {
|
||
|
|
if(associations[index].isApplicable(row)) {
|
||
|
|
association = associations[index];
|
||
|
|
}//if//
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
//If an applicable association was found then register the row with it.//
|
||
|
|
if(association != null) {
|
||
|
|
firstNode = association;
|
||
|
|
association.register(row);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Register with the child associations until we find a target association.//
|
||
|
|
while((association != null) && (!association.isTargetAssociation())) {
|
||
|
|
SingleAssociation next = null;
|
||
|
|
Object result = association.getResult();
|
||
|
|
|
||
|
|
for(int index = 0; next == null && index < associations.length; index++) {
|
||
|
|
if(associations[index].isApplicable(result)) {
|
||
|
|
next = associations[index];
|
||
|
|
}//if//
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
if(next != null) {
|
||
|
|
association.setNext(next);
|
||
|
|
next.register(result);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
association = next;
|
||
|
|
}//while//
|
||
|
|
|
||
|
|
if((association != null) && (association.isTargetAssociation())) {
|
||
|
|
lastNode = association;
|
||
|
|
}//if//
|
||
|
|
}//register()//
|
||
|
|
/**
|
||
|
|
* Unregisters the associations.
|
||
|
|
*/
|
||
|
|
public void unregister() {
|
||
|
|
if(firstNode != null) {
|
||
|
|
unregister(firstNode, row);
|
||
|
|
firstNode = null;
|
||
|
|
lastNode = null;
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
row = null;
|
||
|
|
|
||
|
|
if(eventSupport != null) {
|
||
|
|
eventSupport.unregisterAll();
|
||
|
|
}//if//
|
||
|
|
}//unregister()//
|
||
|
|
/**
|
||
|
|
* Recursively unregisters associations.
|
||
|
|
* @param association The association to unregister with.
|
||
|
|
* @param value The previous association's value which is the given association's input.
|
||
|
|
*/
|
||
|
|
protected void unregister(SingleAssociation association, Object value) {
|
||
|
|
if(association.getNext() != null) {
|
||
|
|
unregister(association.getNext(), association.getResult());
|
||
|
|
association.setNext(null);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
association.unregister(value);
|
||
|
|
}//unregister()//
|
||
|
|
/**
|
||
|
|
* Gets the value in the model.
|
||
|
|
* @return The value the row resolves to. This will be NO_VALUE if the row does not resolve to a target association.
|
||
|
|
*/
|
||
|
|
public Object getValue() {
|
||
|
|
Object result = NO_VALUE;
|
||
|
|
SingleAssociation association = firstNode;
|
||
|
|
|
||
|
|
if(association != null) {
|
||
|
|
while(association.getNext() != null) {
|
||
|
|
association = association.getNext();
|
||
|
|
}//while//
|
||
|
|
|
||
|
|
if(association.isTargetAssociation()) {
|
||
|
|
result = association.getResult();
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}//getValue()//
|
||
|
|
/**
|
||
|
|
* Gets the last association node in the chain to the result.
|
||
|
|
* @return The last association which produces the result. This will be null if there is no input, or no path to a target association.
|
||
|
|
*/
|
||
|
|
public SingleAssociation getEndAssociation() {
|
||
|
|
return lastNode;
|
||
|
|
}//getEndAssociation()//
|
||
|
|
/**
|
||
|
|
* Sets the value in the model.
|
||
|
|
* @param value The value to be set in the model.
|
||
|
|
*/
|
||
|
|
public void setValue(Object value) {
|
||
|
|
SingleAssociation association = firstNode;
|
||
|
|
|
||
|
|
if(VERIFY_THREAD) {
|
||
|
|
verifyThread();
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
if(firstNode == null) {
|
||
|
|
Debug.log("Error");
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
while(association.getNext() != null) {
|
||
|
|
association = association.getNext();
|
||
|
|
}//while//
|
||
|
|
|
||
|
|
if(association.isTargetAssociation()) {
|
||
|
|
association.setResult(value);
|
||
|
|
}//if//
|
||
|
|
}//setValue()//
|
||
|
|
/**
|
||
|
|
* Updates the associations after one of the associations alters its value.
|
||
|
|
* @param association The association that altered its value.
|
||
|
|
* @param oldValue The previous value for the given association.
|
||
|
|
* @param eventFlags The event flags that for the event that triggered the update. This will only be non-zero if an event triggered the call and the event was either an original value changed or cleared event.
|
||
|
|
*/
|
||
|
|
public void updateAssociations(SingleAssociation association, Object oldValue, int eventFlags) {
|
||
|
|
if(!EventSupport.isOriginalValueChanged(eventFlags) && !EventSupport.isOriginalValueCleared(eventFlags)) {
|
||
|
|
if(association.getNext() != null) {
|
||
|
|
unregister(association.getNext(), oldValue);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Register with the child associations until we find a target association.//
|
||
|
|
while((association != null) && (!association.isTargetAssociation())) {
|
||
|
|
SingleAssociation next = null;
|
||
|
|
Object result = association.getResult();
|
||
|
|
|
||
|
|
for(int index = 0; next == null && index < associations.length; index++) {
|
||
|
|
if(associations[index].isApplicable(result)) {
|
||
|
|
next = associations[index];
|
||
|
|
}//if//
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
if(next != null) {
|
||
|
|
association.setNext(next);
|
||
|
|
next.register(result);
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
association = next;
|
||
|
|
}//while//
|
||
|
|
|
||
|
|
//Update the last node reference.//
|
||
|
|
if((association != null) && (association.isTargetAssociation())) {
|
||
|
|
lastNode = association;
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Notify the SingleResourceAssociation.//
|
||
|
|
((SingleResourceAssociation) getResourceAssociation()).modelChanged(eventFlags, false);
|
||
|
|
}//updateAssociations()//
|
||
|
|
/**
|
||
|
|
* Gets the event support for the association.
|
||
|
|
* @return The event support used by the association to manage event registrations.
|
||
|
|
*/
|
||
|
|
public EventSupport getEventSupport() {
|
||
|
|
return eventSupport == null ? (eventSupport = new EventSupport(null)) : eventSupport;
|
||
|
|
}//getEventSupport()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.foundation.view.IValueHolderListener#heldValueChanged()
|
||
|
|
*/
|
||
|
|
public void heldValueChanged() {
|
||
|
|
if(VERIFY_THREAD) {
|
||
|
|
verifyThread();
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Called when the value holder related to this container has changed its held value.//
|
||
|
|
unregister();
|
||
|
|
register();
|
||
|
|
((SingleResourceAssociation) getResourceAssociation()).modelChanged(0, true);
|
||
|
|
}//heldValueChanged()//
|
||
|
|
}//AssociationContainer//
|