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  
29  import com.enspire.collections.decorator.CollectionDecorator;
30  import com.enspire.collections.decorator.SetUniqueCollection;
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>Collection</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>Collection</code>.
47   *
48   * @author Dragan Djuric <dragand@dev.java.net>
49   * @since 1.0
50   **/
51  public class BidirectionalCollection extends CollectionDecorator
52          implements BidirectionalProperty {
53  
54      private Collection decoratedCollection;
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 this.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 this.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.getDecoratedCollection();
107     }
108 
109     /***
110      * @see com.enspire.gemini.BidirectionalProperty#setPropertyValue(java.lang.String)
111      */
112     public void setPropertyValue(Object propertyValue) { 
113         this.decoratedCollection = 
114                SetUniqueCollection.decorate((Collection)propertyValue);
115     }
116 
117     /***
118      * @see com.enspire.collections.decorator.ListDecorator#getDecoratedCollection()
119      */
120     
121     protected Collection getDecoratedCollection() {
122         return this.decoratedCollection;
123     }
124     
125     /***
126      * Adds the object to the collection and updates the opposite property
127      * of the added object.
128      * 
129      * @see java.util.Collection#add(java.lang.Object)
130      */
131     
132     public boolean add(Object object) {
133         if (super.add(object)) {
134             try {
135                 getRelationshipUpdater().set(
136                         object, getOppositeName(), getOwner());
137                 return true;
138             } catch(RuntimeException e) {
139                 super.remove(object);
140                 throw e;
141             }
142         }
143         return false;
144     }
145     
146     /***
147      * Removes the object from the collection and updates the opposite property
148      * of the removed object.
149      * 
150      * @see java.util.Collection#remove(java.lang.Object)
151      */
152     
153     public boolean remove(Object object) {
154         if (super.remove(object)) {
155             try {
156                 getRelationshipUpdater().unset(
157                         object, getOppositeName(), getOwner());
158                 return true;
159             }catch(RuntimeException e) {
160                 super.add(object);
161                 throw e;
162             }
163         }
164         return false;
165     }
166     
167     /***
168      * @see java.util.Collection#addAll(java.util.Collection)
169      */
170     
171     public boolean addAll(Collection coll) {
172         int sizeBefore = size();
173         CommandExecutor executor = new CommandExecutorImpl();
174         try {
175             for (final Iterator it = coll.iterator(); it.hasNext();) {
176                 Object object = it.next();
177                 Command addCommand = new BidirectionalCollectionAdd(
178                         this, this.getDecoratedCollection(), object);
179                 executor.execute(addCommand);
180             }
181             return sizeBefore != size();
182         }catch(RuntimeException e) {
183             executor.undo();
184             throw e;
185         }
186     }
187 
188     /***
189      * @see java.util.Collection#removeAll(java.util.Collection)
190      */
191     
192     public boolean removeAll(Collection coll) {
193         int sizeBefore = size();
194         CommandExecutor executor = new CommandExecutorImpl();
195         try {
196             for (final Iterator it = coll.iterator(); it.hasNext();) {
197                 Object object = it.next();
198                 Command removeCommand = new BidirectionalCollectionRemove(
199                         this, this.getDecoratedCollection(), object);
200                 executor.execute(removeCommand);
201             }
202             return sizeBefore != size();
203         }catch(RuntimeException e) {
204             executor.undo();
205             throw e;
206         }
207     }
208 
209     /***
210      * Unsupported operation.
211      * 
212      * @see java.util.Collection#retainAll(java.util.Collection)
213      */
214     
215     public boolean retainAll(Collection coll) {
216         throw new UnsupportedOperationException();
217     }
218 
219     /***
220      * Unsupported operation.
221      * 
222      * @see java.util.Collection#clear()
223      */
224     public void clear() {
225         throw new UnsupportedOperationException("clear() is not allowed.");
226     }
227 
228     /***
229      * @see com.enspire.collections.decorator.CollectionDecorator#iterator()
230      */
231     
232     public Iterator iterator() {
233         return new BidirectionalIterator(this, super.iterator());
234     }
235 
236 }