1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package com.enspire.gemini.bidirectional;
25
26 import java.util.Collection;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.ListIterator;
30
31 import org.apache.commons.collections.list.SetUniqueList;
32
33 import com.enspire.collections.decorator.ListDecorator;
34 import com.enspire.gemini.BidirectionalProperty;
35 import com.enspire.gemini.RelationshipUpdater;
36 import com.enspire.gemini.commands.BidirectionalCollectionRemove;
37 import com.enspire.gemini.commands.BidirectionalListAddByIndex;
38 import com.enspire.gemini.commands.Command;
39 import com.enspire.gemini.commands.CommandExecutor;
40 import com.enspire.gemini.commands.CommandExecutorImpl;
41
42 /***
43 * <p><a href="http://www.e-nspire.com">e-nspire site</a></p>
44 * This <code>List</code> updates the corresponding opposite property of
45 * its elements, both simple and container properties. It is intended
46 * to represent one end of a bidirectional association. It must be supplied
47 * with <code>RelationshipUpdater</code> to know which property of the
48 * containing objects represents the opposite end. It decorates another
49 * <code>List</code>.
50 *
51 * @author Dragan Djuric <dragand@dev.java.net>
52 * @since 1.0
53 **/
54 public class BidirectionalList extends ListDecorator
55 implements BidirectionalProperty {
56
57 private List decoratedList;
58 private RelationshipUpdater relationshipUpdater;
59 private Object owner;
60 private String oppositeName;
61
62 /***
63 * @see com.enspire.gemini.BidirectionalProperty#getRelationshipUpdater()
64 */
65 public RelationshipUpdater getRelationshipUpdater() {
66 return this.relationshipUpdater;
67 }
68
69 /***
70 * @see com.enspire.gemini.BidirectionalProperty#setRelationshipUpdater(com.enspire.gemini.RelationshipUpdater)
71 */
72 public void setRelationshipUpdater(RelationshipUpdater relationshipUpdater) {
73 this.relationshipUpdater = relationshipUpdater;
74 }
75
76 /***
77 * @see com.enspire.gemini.BidirectionalProperty#getOppositeName()
78 */
79 public String getOppositeName() {
80 return this.oppositeName;
81 }
82
83 /***
84 * @see com.enspire.gemini.BidirectionalProperty#setOppositeName(java.lang.String)
85 */
86 public void setOppositeName(String oppositeName) {
87 this.oppositeName = oppositeName;
88 }
89
90 /***
91 * @see com.enspire.gemini.BidirectionalProperty#getOwner()
92 */
93 public Object getOwner() {
94 return this.owner;
95 }
96
97 /***
98 * @see com.enspire.gemini.BidirectionalProperty#setOwner(java.lang.Object)
99 */
100 public void setOwner(Object owner) {
101 this.owner = owner;
102 }
103
104 /***
105 * @see com.enspire.gemini.BidirectionalProperty#getPropertyValue()
106 */
107 public Object getPropertyValue() {
108 return this.getDecoratedList();
109 }
110
111 /***
112 * @see com.enspire.gemini.BidirectionalProperty#setPropertyValue(java.lang.String)
113 */
114 public void setPropertyValue(Object propertyValue) {
115 this.decoratedList =
116 SetUniqueList.decorate((List)propertyValue);
117 }
118
119 /***
120 * @see com.enspire.collections.decorator.ListDecorator#getDecoratedList()
121 */
122
123 protected List getDecoratedList() {
124 return this.decoratedList;
125 }
126
127 /***
128 * Adds the object to the list and updates the opposite property
129 * of the added object.
130 *
131 * @see java.util.Collection#add(java.lang.Object)
132 */
133
134 public boolean add(Object object) {
135 final int sizeBefore = size();
136 add(sizeBefore, object);
137 return (sizeBefore != size());
138 }
139
140 /***
141 * @see com.enspire.collections.decorator.ListDecorator#add(int, java.lang.Object)
142 */
143
144 public void add(int index, Object object) {
145 final int sizeBefore = size();
146 super.add(index, object);
147 if (sizeBefore != size()) {
148 try {
149 getRelationshipUpdater().set(
150 object, getOppositeName(), getOwner());
151 } catch(RuntimeException e) {
152 super.remove(index);
153 throw e;
154 }
155 }
156 }
157
158 /***
159 * Removes the object from the list and updates the opposite property
160 * of the removed object.
161 *
162 * @see java.util.Collection#remove(java.lang.Object)
163 */
164 public boolean remove(Object object) {
165 int index = indexOf(object);
166 if (index == -1) {
167 return false;
168 }
169 return (remove(index) != null);
170 }
171
172 /***
173 * @see java.util.List#remove(int)
174 */
175 public Object remove(int index) {
176 Object removed = super.remove(index);
177 if (removed != null) {
178 try {
179 getRelationshipUpdater().unset(
180 removed, getOppositeName(), getOwner());
181 }catch(RuntimeException e) {
182 super.add(index, removed);
183 throw e;
184 }
185 }
186 return removed;
187 }
188
189 /***
190 * @see com.enspire.collections.decorator.CollectionDecorator#addAll(java.util.Collection)
191 */
192 public boolean addAll(Collection coll) {
193 final int sizeBefore = size();
194 addAll(size(), coll);
195 return (sizeBefore != size());
196 }
197
198 /***
199 * @see java.util.Collection#addAll(java.util.Collection)
200 */
201 public boolean addAll(int index, Collection coll) {
202 int sizeBefore = size();
203 CommandExecutor executor = new CommandExecutorImpl();
204 try {
205 for (final Iterator it = coll.iterator(); it.hasNext(); index++) {
206 Object object = it.next();
207 Command addCommand = new BidirectionalListAddByIndex(
208 this, this.getDecoratedList(), index, object);
209 executor.execute(addCommand);
210 }
211 return sizeBefore != size();
212 }catch(RuntimeException e) {
213 executor.undo();
214 throw e;
215 }
216 }
217
218 /***
219 * @see java.util.Collection#removeAll(java.util.Collection)
220 */
221 public boolean removeAll(Collection coll) {
222 int sizeBefore = size();
223 CommandExecutor executor = new CommandExecutorImpl();
224 try {
225 for (final Iterator it = coll.iterator(); it.hasNext();) {
226 Object object = it.next();
227 Command removeCommand = new BidirectionalCollectionRemove(
228 this, this.getDecoratedCollection(), object);
229 executor.execute(removeCommand);
230 }
231 return sizeBefore != size();
232 }catch(RuntimeException e) {
233 executor.undo();
234 throw e;
235 }
236 }
237
238 /***
239 * @see java.util.List#set(int, java.lang.Object)
240 */
241 public Object set(int index, Object object) {
242 Object oldValue = this.remove(index);
243 try {
244 this.add(index, object);
245 return oldValue;
246 }catch(RuntimeException e) {
247 if (oldValue != null) {
248 this.add(index, oldValue);
249 }
250 throw e;
251 }
252 }
253
254 /***
255 * @see java.util.List#subList(int, int)
256 */
257 public List subList(int fromIndex, int toIndex) {
258 BidirectionalList subList = new BidirectionalList();
259 subList.setOppositeName(this.getOppositeName());
260 subList.setOwner(this.getOwner());
261 subList.setRelationshipUpdater(this.getRelationshipUpdater());
262 subList.setPropertyValue(super.subList(fromIndex, toIndex));
263 return subList;
264 }
265
266 /***
267 * Unsupported operation.
268 *
269 * @see java.util.Collection#retainAll(java.util.Collection)
270 */
271 public boolean retainAll(Collection coll) {
272 throw new UnsupportedOperationException();
273 }
274
275 /***
276 * Unsupported operation.
277 *
278 * @see java.util.Collection#clear()
279 */
280 public void clear() {
281 throw new UnsupportedOperationException("clear() is not allowed.");
282 }
283
284 /***
285 * @see com.enspire.collections.decorator.ListDecorator#listIterator()
286 */
287
288 public ListIterator listIterator() {
289 return new BidirectionalListIterator(super.listIterator(), this);
290 }
291
292 /***
293 * @see com.enspire.collections.decorator.ListDecorator#listIterator(int)
294 */
295
296 public ListIterator listIterator(int index) {
297 return new BidirectionalListIterator(super.listIterator(index), this);
298 }
299
300 /***
301 * @see com.enspire.collections.decorator.ListDecorator#iterator()
302 */
303
304 public Iterator iterator() {
305 return this.listIterator();
306 }
307
308
309
310 }