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.Set;
29
30 import com.enspire.collections.decorator.SetDecorator;
31 import com.enspire.gemini.BidirectionalProperty;
32 import com.enspire.gemini.RelationshipUpdater;
33 import com.enspire.gemini.commands.BidirectionalCollectionAdd;
34 import com.enspire.gemini.commands.BidirectionalCollectionRemove;
35 import com.enspire.gemini.commands.Command;
36 import com.enspire.gemini.commands.CommandExecutor;
37 import com.enspire.gemini.commands.CommandExecutorImpl;
38
39 /***
40 * <p><a href="http://www.e-nspire.com">e-nspire site</a></p>
41 * This <code>Set</code> updates the corresponding opposite property of
42 * its elements, both simple and container properties. It is intended
43 * to represent one end of a bidirectional association. It must be supplied
44 * with <code>RelationshipUpdater</code> to know which property of the
45 * containing objects represents the opposite end. It decorates another
46 * <code>Set</code>.
47 *
48 * @author Dragan Djuric <dragand@dev.java.net>
49 * @since 1.0
50 */
51 public class BidirectionalSet extends SetDecorator
52 implements BidirectionalProperty{
53
54 private Set decoratedSet;
55 private RelationshipUpdater relationshipUpdater;
56 private Object owner;
57 private String oppositeName;
58
59 /***
60 * @see com.enspire.gemini.BidirectionalProperty#getRelationshipUpdater()
61 */
62 public RelationshipUpdater getRelationshipUpdater() {
63 return this.relationshipUpdater;
64 }
65
66 /***
67 * @see com.enspire.gemini.BidirectionalProperty#setRelationshipUpdater(com.enspire.gemini.RelationshipUpdater)
68 */
69 public void setRelationshipUpdater(RelationshipUpdater relationshipUpdater) {
70 this.relationshipUpdater = relationshipUpdater;
71 }
72
73 /***
74 * @see com.enspire.gemini.BidirectionalProperty#getOppositeName()
75 */
76 public String getOppositeName() {
77 return oppositeName;
78 }
79
80 /***
81 * @see com.enspire.gemini.BidirectionalProperty#setOppositeName(java.lang.String)
82 */
83 public void setOppositeName(
84 String oppositeName) {
85 this.oppositeName = oppositeName;
86 }
87
88 /***
89 * @see com.enspire.gemini.BidirectionalProperty#getOwner()
90 */
91 public Object getOwner() {
92 return owner;
93 }
94
95 /***
96 * @see com.enspire.gemini.BidirectionalProperty#setOwner(java.lang.Object)
97 */
98 public void setOwner(Object owner) {
99 this.owner = owner;
100 }
101
102 /***
103 * @see com.enspire.gemini.BidirectionalProperty#getPropertyValue()
104 */
105 public Object getPropertyValue() {
106 return this.getDecoratedSet();
107 }
108
109 /***
110 * @see com.enspire.gemini.BidirectionalProperty#setPropertyValue(java.lang.String)
111 */
112 public void setPropertyValue(Object propertyValue) {
113 this.decoratedSet = (Set)propertyValue;
114 }
115
116 /***
117 * @see com.enspire.collections.decorator.SetDecorator#getDecoratedSet()
118 */
119 protected Set getDecoratedSet() {
120 return this.decoratedSet;
121 }
122
123 /***
124 * Adds the object to the set and updates the opposite property
125 * of the added object.
126 *
127 * @see java.util.Set#add(java.lang.Object)
128 */
129 public boolean add(Object object) {
130 if (super.add(object)) {
131 try {
132 getRelationshipUpdater().set(
133 object, getOppositeName(), getOwner());
134 return true;
135 } catch(RuntimeException e) {
136 super.remove(object);
137 throw e;
138 }
139 }
140 return false;
141 }
142
143 /***
144 * Removes the object from the set and updates the opposite property
145 * of the removed object.
146 *
147 * @see java.util.Set#remove(java.lang.Object)
148 */
149 public boolean remove(Object object) {
150 if (super.remove(object)) {
151 try {
152 getRelationshipUpdater().unset(
153 object, getOppositeName(), getOwner());
154 return true;
155 }catch(RuntimeException e) {
156 super.add(object);
157 throw e;
158 }
159 }
160 return false;
161 }
162
163 /***
164 * @see java.util.Set#addAll(java.util.Collection)
165 */
166 public boolean addAll(Collection coll) {
167 int sizeBefore = size();
168 CommandExecutor executor = new CommandExecutorImpl();
169 try {
170 for (final Iterator it = coll.iterator(); it.hasNext();) {
171 Object object = it.next();
172 Command addCommand = new BidirectionalCollectionAdd(
173 this, this.getDecoratedSet(), object);
174 executor.execute(addCommand);
175 }
176 return sizeBefore != size();
177 }catch(RuntimeException e) {
178 executor.undo();
179 throw e;
180 }
181 }
182
183 /***
184 * @see java.util.Set#removeAll(java.util.Collection)
185 */
186 public boolean removeAll(Collection coll) {
187 int sizeBefore = size();
188 CommandExecutor executor = new CommandExecutorImpl();
189 try {
190 for (final Iterator it = coll.iterator(); it.hasNext();) {
191 Object object = it.next();
192 Command removeCommand = new BidirectionalCollectionRemove(
193 this, this.getDecoratedSet(), object);
194 executor.execute(removeCommand);
195 }
196 return sizeBefore != size();
197 }catch(RuntimeException e) {
198 executor.undo();
199 throw e;
200 }
201 }
202
203 /***
204 * Unsupported operation.
205 *
206 * @see java.util.Set#retainAll(java.util.Collection)
207 */
208 public boolean retainAll(Collection coll) {
209 throw new UnsupportedOperationException();
210 }
211
212 /***
213 * Unsupported operation.
214 *
215 * @see java.util.Set#clear()
216 */
217 public void clear() {
218 throw new UnsupportedOperationException("clear() is not allowed.");
219 }
220
221 /***
222 * @see com.enspire.collections.decorator.SetDecorator#iterator()
223 */
224
225 public Iterator iterator() {
226 return new BidirectionalIterator(this, super.iterator());
227 }
228 }