source: trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/AbstractDefaultHierarchicalEventTarget.java @ 2252

Last change on this file since 2252 was 2146, checked in by pharms, 7 years ago
  • refactored GUI model so that hierarchical event target structures can also be used and created by plugins not being strictly for GUIs
  • Property svn:executable set to *
  • Property svn:mime-type set to text/plain
File size: 9.3 KB
Line 
1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
14
15package de.ugoe.cs.autoquest.eventcore;
16
17import java.util.LinkedList;
18import java.util.List;
19
20/**
21 * <p>
22 * Skeletal implementation for hierarchical event targets.
23 * </p>
24 *
25 * @version 1.0
26 * @author Patrick Harms
27 */
28public abstract class AbstractDefaultHierarchicalEventTarget
29    implements IHierarchicalEventTarget
30{
31
32    /**
33     * <p>
34     * Id for object serialization.
35     * </p>
36     */
37    public static final long serialVersionUID = 1L;
38
39    /**
40     * <p>
41     * Specification of the event target
42     * </p>
43     */
44    private final IEventTargetSpec specification;
45
46    /**
47     * <p>
48     * Reference to the parent event target
49     * </p>
50     */
51    private IHierarchicalEventTarget parent;
52   
53    /**
54     * <p>
55     * List of other event targets being equal to this
56     * </p>
57     */
58    private List<AbstractDefaultHierarchicalEventTarget> equalEventTargets = null;
59
60    /**
61     * <p>
62     * the reference to the event target model to which this event target belongs.
63     * </p>
64     */
65    private HierarchicalEventTargetModel<?> eventTargetModel;
66   
67    /**
68     * <p>
69     * the hash code of this object
70     * </p>
71     */
72    private int hashCode;
73
74    /**
75     * <p>
76     * Constructor. Creates a new AbstractDefaultEventTarget.
77     * </p>
78     *
79     * @param specification
80     *            specification of the created event target
81     * @param parent
82     *            parent of the created event target; null means the target is at top-level
83     */
84    public AbstractDefaultHierarchicalEventTarget(IEventTargetSpec         specification,
85                                                  IHierarchicalEventTarget parent)
86    {
87        this.specification = specification;
88        setParent(parent);
89       
90        if (specification != null) {
91            this.hashCode = specification.hashCode();
92        }
93        else {
94            this.hashCode = 0;
95        }
96    }
97
98    /* (non-Javadoc)
99     * @see de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget#getSpecification()
100     */
101    @Override
102    public IEventTargetSpec getSpecification() {
103        return specification;
104    }
105
106    /* (non-Javadoc)
107     * @see de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget#getParent()
108     */
109    @Override
110    public IHierarchicalEventTarget getParent() {
111        return parent;
112    }
113
114    /* (non-Javadoc)
115     * @see de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget#getEventTargetModel()
116     */
117    @Override
118    public HierarchicalEventTargetModel<?> getEventTargetModel()
119    {
120       return eventTargetModel;
121    }
122
123    /* (non-Javadoc)
124     * @see de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget#addEqualEventTarget(IHierarchicalEventTarget)
125     */
126    @Override
127    public void addEqualEventTarget(IHierarchicalEventTarget equalElement) {
128        if (!(equalElement instanceof AbstractDefaultHierarchicalEventTarget)) {
129            throw new IllegalArgumentException
130                ("this implementation can only handle other AbstractDefaultHierarchicalEventTargets");
131        }
132       
133        AbstractDefaultHierarchicalEventTarget other =
134            (AbstractDefaultHierarchicalEventTarget) equalElement;
135       
136        synchronized (AbstractDefaultHierarchicalEventTarget.class) {
137            if (this.equalEventTargets == null) {
138                if (other.equalEventTargets == null) {
139                    this.equalEventTargets = new LinkedList<AbstractDefaultHierarchicalEventTarget>();
140                    this.equalEventTargets.add(this);
141                    this.equalEventTargets.add(other);
142                    other.equalEventTargets = this.equalEventTargets;
143                    other.hashCode = this.hashCode;
144                }
145                else {
146                    addIfNotContained(other.equalEventTargets, this);
147                    this.equalEventTargets = other.equalEventTargets;
148                    this.hashCode = other.hashCode;
149                }
150            }
151            else {
152                if (other.equalEventTargets == null) {
153                    addIfNotContained(this.equalEventTargets, other);
154                    other.equalEventTargets = this.equalEventTargets;
155                    other.hashCode = this.hashCode;
156                }
157                else if (this.equalEventTargets != other.equalEventTargets) {
158                    this.equalEventTargets.addAll(other.equalEventTargets);
159
160                    // we also have to set this new list for all other elements for which so
161                    // far list2 was registered
162                    for (AbstractDefaultHierarchicalEventTarget candidate : other.equalEventTargets) {
163                        candidate.equalEventTargets = this.equalEventTargets;
164                        candidate.hashCode = this.hashCode;
165                    }
166
167                    other.equalEventTargets = this.equalEventTargets;
168                    other.hashCode = this.hashCode;
169                }
170                // else
171                // in this case, both GUI elements should already be registered with the same
172                // lists.
173            }
174        }
175    }
176
177    /* (non-Javadoc)
178     * @see java.lang.Object#equals(java.lang.Object)
179     */
180    public final boolean equals(Object other) {
181        // implement final, as hierarchical event targets are all singletons and they equal only
182        // if they are the same object or if they are in the list of equal event targets
183        if (super.equals(other)) {
184            return true;
185        }
186        else if (other instanceof AbstractDefaultHierarchicalEventTarget) {
187            synchronized (AbstractDefaultHierarchicalEventTarget.class) {
188                if (equalEventTargets != null) {
189                    for (AbstractDefaultHierarchicalEventTarget candidate : equalEventTargets) {
190                        if (candidate == other) {
191                            return true;
192                        }
193                    }
194                }
195            }
196        }
197
198        return false;
199    }
200
201    /* (non-Javadoc)
202     * @see java.lang.Object#hashCode()
203     */
204    @Override
205    public final int hashCode() {
206        // implement final, as event targets are all singletons and they equal only if they are the
207        // same object. If there are several event target objects that represent the same event target
208        // then they are stored in the list of equal event target. But at least their type is expected
209        // to be equal, so return the hash code of the type.
210        return hashCode;
211    }
212   
213    /**
214     * <p>
215     * updates the parent node of this node if required due to model restructuring
216     * </p>
217     */
218    void setParent(IHierarchicalEventTarget newParent)
219    {
220        synchronized (AbstractDefaultHierarchicalEventTarget.class) {
221            // all equal event targets must have the same parent. Otherwise, they are not equal
222            // anymore and we would have discrepancies on the return value of getParent() on
223            // equal event targets.
224            this.parent = newParent;
225            if (equalEventTargets != null) {
226                for (AbstractDefaultHierarchicalEventTarget candidate : equalEventTargets) {
227                    candidate.parent = newParent;
228                }
229            }
230        }
231    }
232
233    /**
234     * <p>
235     * used to set the event target model to which this event target belongs. Will be set
236     * automatically, if used in combination with {@link HierarchicalEventTargetModel};
237     * </p>
238     *
239     * @param eventTargetModel
240     *
241     */
242    void setEventTargetModel(HierarchicalEventTargetModel<?> eventTargetModel) {
243        this.eventTargetModel = eventTargetModel;
244    }
245
246    /**
247     * <p>
248     * Adds an {@link AbstractDefaultHierarchicalEventTarget} as equal to a list of
249     * {@link AbstractDefaultHierarchicalEventTarget}s if and only if it is not already contained.
250     * </p>
251     *
252     * @param equalTargetsList
253     *            list of {@link AbstractDefaultHierarchicalEventTarget} to which the event target
254     *            is added
255     * @param eventTarget
256     *            event target to be added
257     */
258    private void addIfNotContained(List<AbstractDefaultHierarchicalEventTarget> equalTargetsList,
259                                   AbstractDefaultHierarchicalEventTarget       eventTarget)
260    {
261        for (AbstractDefaultHierarchicalEventTarget candidate : equalTargetsList) {
262            if (candidate == eventTarget) {
263                return;
264            }
265        }
266
267        equalTargetsList.add(eventTarget);
268    }
269
270}
Note: See TracBrowser for help on using the repository browser.