View Javadoc

1   /*
2   * E-nspire Gemini.
3   * A Java and AspectJ based framework that enables transparent 
4   * bidirectional relationships between Plain Old Java Objects.
5   * 
6   * Copyright (C) 2005 Dragan Djuric
7   * 
8   * This program is free software; you can redistribute it and/or
9   * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  * 
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21  * 
22  * Contact the author at dragand@dev.java.net
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 }