// Copyright 2012 Georg-August-Universität Göttingen, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package de.ugoe.cs.autoquest.eventcore; import java.util.LinkedList; import java.util.List; /** *

* Skeletal implementation for hierarchical event targets. *

* * @version 1.0 * @author Patrick Harms */ public abstract class AbstractDefaultHierarchicalEventTarget implements IHierarchicalEventTarget { /** *

* Id for object serialization. *

*/ public static final long serialVersionUID = 1L; /** *

* Specification of the event target *

*/ private final IEventTargetSpec specification; /** *

* Reference to the parent event target *

*/ private IHierarchicalEventTarget parent; /** *

* List of other event targets being equal to this *

*/ private List equalEventTargets = null; /** *

* the reference to the event target model to which this event target belongs. *

*/ private HierarchicalEventTargetModel eventTargetModel; /** *

* the hash code of this object *

*/ private int hashCode; /** *

* Constructor. Creates a new AbstractDefaultEventTarget. *

* * @param specification * specification of the created event target * @param parent * parent of the created event target; null means the target is at top-level */ public AbstractDefaultHierarchicalEventTarget(IEventTargetSpec specification, IHierarchicalEventTarget parent) { this.specification = specification; setParent(parent); if (specification != null) { this.hashCode = specification.hashCode(); } else { this.hashCode = 0; } } /* (non-Javadoc) * @see de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget#getSpecification() */ @Override public IEventTargetSpec getSpecification() { return specification; } /* (non-Javadoc) * @see de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget#getParent() */ @Override public IHierarchicalEventTarget getParent() { return parent; } /* (non-Javadoc) * @see de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget#getEventTargetModel() */ @Override public HierarchicalEventTargetModel getEventTargetModel() { return eventTargetModel; } /* (non-Javadoc) * @see de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget#addEqualEventTarget(IHierarchicalEventTarget) */ @Override public void addEqualEventTarget(IHierarchicalEventTarget equalElement) { if (!(equalElement instanceof AbstractDefaultHierarchicalEventTarget)) { throw new IllegalArgumentException ("this implementation can only handle other AbstractDefaultHierarchicalEventTargets"); } AbstractDefaultHierarchicalEventTarget other = (AbstractDefaultHierarchicalEventTarget) equalElement; synchronized (AbstractDefaultHierarchicalEventTarget.class) { if (this.equalEventTargets == null) { if (other.equalEventTargets == null) { this.equalEventTargets = new LinkedList(); this.equalEventTargets.add(this); this.equalEventTargets.add(other); other.equalEventTargets = this.equalEventTargets; other.hashCode = this.hashCode; } else { addIfNotContained(other.equalEventTargets, this); this.equalEventTargets = other.equalEventTargets; this.hashCode = other.hashCode; } } else { if (other.equalEventTargets == null) { addIfNotContained(this.equalEventTargets, other); other.equalEventTargets = this.equalEventTargets; other.hashCode = this.hashCode; } else if (this.equalEventTargets != other.equalEventTargets) { this.equalEventTargets.addAll(other.equalEventTargets); // we also have to set this new list for all other elements for which so // far list2 was registered for (AbstractDefaultHierarchicalEventTarget candidate : other.equalEventTargets) { candidate.equalEventTargets = this.equalEventTargets; candidate.hashCode = this.hashCode; } other.equalEventTargets = this.equalEventTargets; other.hashCode = this.hashCode; } // else // in this case, both GUI elements should already be registered with the same // lists. } } } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ public final boolean equals(Object other) { // implement final, as hierarchical event targets are all singletons and they equal only // if they are the same object or if they are in the list of equal event targets if (super.equals(other)) { return true; } else if (other instanceof AbstractDefaultHierarchicalEventTarget) { synchronized (AbstractDefaultHierarchicalEventTarget.class) { if (equalEventTargets != null) { for (AbstractDefaultHierarchicalEventTarget candidate : equalEventTargets) { if (candidate == other) { return true; } } } } } return false; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public final int hashCode() { // implement final, as event targets are all singletons and they equal only if they are the // same object. If there are several event target objects that represent the same event target // then they are stored in the list of equal event target. But at least their type is expected // to be equal, so return the hash code of the type. return hashCode; } /** *

* updates the parent node of this node if required due to model restructuring *

*/ void setParent(IHierarchicalEventTarget newParent) { synchronized (AbstractDefaultHierarchicalEventTarget.class) { // all equal event targets must have the same parent. Otherwise, they are not equal // anymore and we would have discrepancies on the return value of getParent() on // equal event targets. this.parent = newParent; if (equalEventTargets != null) { for (AbstractDefaultHierarchicalEventTarget candidate : equalEventTargets) { candidate.parent = newParent; } } } } /** *

* used to set the event target model to which this event target belongs. Will be set * automatically, if used in combination with {@link HierarchicalEventTargetModel}; *

* * @param eventTargetModel * */ void setEventTargetModel(HierarchicalEventTargetModel eventTargetModel) { this.eventTargetModel = eventTargetModel; } /** *

* Adds an {@link AbstractDefaultHierarchicalEventTarget} as equal to a list of * {@link AbstractDefaultHierarchicalEventTarget}s if and only if it is not already contained. *

* * @param equalTargetsList * list of {@link AbstractDefaultHierarchicalEventTarget} to which the event target * is added * @param eventTarget * event target to be added */ private void addIfNotContained(List equalTargetsList, AbstractDefaultHierarchicalEventTarget eventTarget) { for (AbstractDefaultHierarchicalEventTarget candidate : equalTargetsList) { if (candidate == eventTarget) { return; } } equalTargetsList.add(eventTarget); } }