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.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 }