KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > j2ee > persistence > wizard > fromdb > TableClosure


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.j2ee.persistence.wizard.fromdb;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.Collections JavaDoc;
24 import java.util.HashSet JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Set JavaDoc;
28 import javax.swing.event.ChangeListener JavaDoc;
29
30 /**
31  *
32  * @author Andrei Badea
33  */

34 public class TableClosure {
35
36     // XXX Javadoc
37

38     private final Set JavaDoc<Table> tables;
39
40     private final Set JavaDoc<Table> availableTables = new HashSet JavaDoc<Table>();
41     private final Set JavaDoc<Table> wantedTables = new HashSet JavaDoc<Table>();
42     private final Set JavaDoc<Table> selectedTables = new HashSet JavaDoc<Table>();
43     private final Set JavaDoc<Table> referencedTables = new HashSet JavaDoc<Table>();
44
45     // just for performance reasons
46
private final Set JavaDoc<Table> unmodifAvailableTables = Collections.unmodifiableSet(availableTables);
47     private final Set JavaDoc<Table> unmodifWantedTables = Collections.unmodifiableSet(wantedTables);
48     private final Set JavaDoc<Table> unmodifSelectedTables = Collections.unmodifiableSet(selectedTables);
49     private final Set JavaDoc<Table> unmodifReferencedTables = Collections.unmodifiableSet(referencedTables);
50
51     private boolean closureEnabled = true;
52
53     private final ChangeSupport changeSupport = new ChangeSupport(this);
54
55     public TableClosure(TableProvider tableProvider) {
56         tables = tableProvider.getTables();
57         availableTables.addAll(tables);
58     }
59
60     public void addChangeListener(ChangeListener JavaDoc listener) {
61         changeSupport.addChangeListener(listener);
62     }
63
64     public void removeChangeListener(ChangeListener JavaDoc listener) {
65         changeSupport.removeChangeListener(listener);
66     }
67
68     public Set JavaDoc<Table> getAvailableTables() {
69         return unmodifAvailableTables;
70     }
71
72     public Set JavaDoc<Table> getSelectedTables() {
73         return unmodifSelectedTables;
74     }
75
76     public Set JavaDoc<Table> getReferencedTables() {
77         return unmodifReferencedTables;
78     }
79
80     /**
81      * Static because of the tests.
82      */

83     Set JavaDoc<Table> getWantedTables() {
84         return unmodifWantedTables;
85     }
86
87     public void addTables(Set JavaDoc<Table> tables) {
88         if (!canAddAllTables(tables)) {
89             return;
90         }
91         if (closureEnabled) {
92             if (wantedTables.addAll(tables)) {
93                 Set JavaDoc<Table> refTables = removeDisabledTables(getReferencedTablesTransitively(tables));
94                 Set JavaDoc<Table> addedTables = new HashSet JavaDoc<Table>(tables);
95                 addedTables.addAll(refTables);
96
97                 selectedTables.addAll(addedTables);
98                 referencedTables.addAll(refTables);
99                 availableTables.removeAll(addedTables);
100
101                 Set JavaDoc<Table> joinTables = removeDisabledTables(getJoinTablesTransitively(addedTables));
102                 // if some of the join tables are already selected, we don't want
103
// to add them once more and especially we want to avoid adding
104
// already selected tables as referenced tables -- that would be incorrect
105
joinTables.removeAll(selectedTables);
106                 selectedTables.addAll(joinTables);
107
108                 referencedTables.addAll(joinTables);
109                 availableTables.removeAll(joinTables);
110
111                 changeSupport.fireChange();
112             }
113         } else {
114             wantedTables.addAll(tables);
115             selectedTables.addAll(tables);
116             availableTables.removeAll(tables);
117
118             changeSupport.fireChange();
119         }
120     }
121
122     public void removeTables(Set JavaDoc<Table> tables) {
123         if (!canRemoveAllTables(tables)) {
124             return;
125         }
126
127         if (closureEnabled) {
128             if (wantedTables.removeAll(tables)) {
129                 redoClosure();
130
131                 changeSupport.fireChange();
132             }
133         } else {
134             wantedTables.removeAll(tables);
135             selectedTables.removeAll(tables);
136             availableTables.addAll(tables);
137
138             changeSupport.fireChange();
139         }
140     }
141
142     public void addAllTables() {
143         wantedTables.clear();
144         for (Table table : tables) {
145             if (!table.isDisabled()) {
146                 wantedTables.add(table);
147             }
148         }
149
150         if (closureEnabled) {
151             redoClosure();
152
153             changeSupport.fireChange();
154         } else {
155             selectedTables.addAll(wantedTables);
156             availableTables.addAll(tables);
157             availableTables.removeAll(wantedTables);
158
159             changeSupport.fireChange();
160         }
161     }
162
163     public void removeAllTables() {
164         wantedTables.clear();
165         selectedTables.clear();
166         referencedTables.clear();
167         availableTables.addAll(tables);
168
169         changeSupport.fireChange();
170     }
171
172     public boolean getClosureEnabled() {
173         return closureEnabled;
174     }
175
176     public void setClosureEnabled(boolean closureEnabled) {
177         if (this.closureEnabled == closureEnabled) {
178             return;
179         }
180
181         this.closureEnabled = closureEnabled;
182
183         if (closureEnabled) {
184             redoClosure();
185         } else {
186             selectedTables.clear();
187             selectedTables.addAll(wantedTables);
188
189             referencedTables.clear();
190
191             availableTables.addAll(tables);
192             availableTables.removeAll(wantedTables);
193         }
194
195         changeSupport.fireChange();
196     }
197
198     public boolean canAddAllTables(Set JavaDoc<Table> tables) {
199         if (tables.size() <= 0) {
200             return false;
201         }
202         // can't add disabled tables
203
for (Table table : tables) {
204             if (table.isDisabled()) {
205                 return false;
206             }
207         }
208         return true;
209     }
210
211     public boolean canAddSomeTables(Set JavaDoc<Table> tables) {
212         if (tables.size() <= 0) {
213             return false;
214         }
215         for (Table table : tables) {
216             if (!table.isDisabled()) {
217                 return true;
218             }
219         }
220         return false;
221     }
222
223     public boolean canRemoveAllTables(Set JavaDoc<Table> tables) {
224         if (tables.size() <= 0) {
225             return false;
226         }
227
228         // no need to check for disabled tables, as there can not be
229
// disabled tables in selectedTables
230

231         if (!closureEnabled) {
232             return true;
233         }
234         // can't remove referenced tables
235
// PENDING but we could support removing a table which is
236
// only referenced by another removed table
237
for (Table table : tables) {
238             if (referencedTables.contains(table)) {
239                 return false;
240             }
241         }
242         return true;
243     }
244
245     private void redoClosure() {
246         referencedTables.clear();
247         referencedTables.addAll(removeDisabledTables(getReferencedTablesTransitively(wantedTables)));
248
249         selectedTables.clear();
250         selectedTables.addAll(wantedTables);
251         selectedTables.addAll(referencedTables);
252
253         Set JavaDoc<Table> joinTables = removeDisabledTables(getJoinTablesTransitively(selectedTables));
254         // avoid adding already selected tables as join tables
255
joinTables.removeAll(selectedTables);
256
257         selectedTables.addAll(joinTables);
258         referencedTables.addAll(joinTables);
259
260         availableTables.clear();
261         availableTables.addAll(tables);
262         availableTables.removeAll(selectedTables);
263     }
264
265     /**
266      * Returns the tables transitively referenced by the contents of the tables parameter
267      * (not including tables passed in this parameter). If a table references itself,
268      * it is not added to the result.
269      */

270     private Set JavaDoc<Table> getReferencedTablesTransitively(Set JavaDoc<Table> tables) {
271         Queue<Table> tableQueue = new Queue<Table>(tables);
272         Set JavaDoc<Table> referencedTables = new HashSet JavaDoc<Table>();
273
274         while (!tableQueue.isEmpty()) {
275             Table table = tableQueue.poll();
276
277             for (Table referencedTable : table.getReferencedTables()) {
278                 if (!referencedTable.equals(table)) {
279                     referencedTables.add(referencedTable);
280                 }
281                 tableQueue.offer(referencedTable);
282             }
283         }
284
285         return referencedTables;
286     }
287
288     private Set JavaDoc<Table> getJoinTablesTransitively(Set JavaDoc<Table> tables) {
289         Queue<Table> tableQueue = new Queue<Table>(tables);
290         Set JavaDoc<Table> joinTables = new HashSet JavaDoc<Table>();
291
292         while (!tableQueue.isEmpty()) {
293             Table table = tableQueue.poll();
294
295             for (Table joinTable : table.getJoinTables()) {
296                 if (areReferencedTablesSelected(joinTable, joinTables)) {
297                     joinTables.add(joinTable);
298                     tableQueue.offer(joinTable);
299                 }
300             }
301         }
302
303         return joinTables;
304     }
305
306     /**
307      * Returns true if all tables referenced by tableName are in {@link selectedTables} or
308      * the additionalTables parameter. The additionalTables parameter is necessary
309      * because it contains the already added join tables, which are not yet in selectedTables,
310      * but will eventually become part of it.
311      */

312     private boolean areReferencedTablesSelected(Table table, Set JavaDoc<Table> additionalTables) {
313         for (Table referencedTable : table.getReferencedTables()) {
314             if (!selectedTables.contains(referencedTable) && !additionalTables.contains(referencedTable)) {
315                 return false;
316             }
317         }
318         return true;
319     }
320
321     private static Set JavaDoc<Table> removeDisabledTables(Set JavaDoc<Table> tables) {
322         for (Iterator JavaDoc<Table> i = tables.iterator(); i.hasNext();) {
323             if (i.next().isDisabled()) {
324                 i.remove();
325             }
326         }
327         return tables;
328     }
329
330     /**
331      * A simple queue. An object can only be added once, even
332      * if it has already been removed from the queue. This class could implement
333      * the {@link java.util.Queue} interface, but it doesn't because that
334      * interface has too many unneeded methods. Not private because of the tests.
335      */

336     static final class Queue<T> {
337
338         /**
339          * The queue. Implemented as ArrayList since will be iterated using get().
340          */

341         private final List JavaDoc<T> queue;
342
343         /**
344          * The contents of the queue, needed in order to quickly (ideally
345          * in a constant time) tell if a table has been already added.
346          */

347         private final Set JavaDoc<T> contents;
348
349         /**
350          * The position in the queue.
351          */

352         private int currentIndex;
353
354         /**
355          * Creates a queue with an initial contents.
356          */

357         public Queue(Set JavaDoc<T> initialContents) {
358             assert !initialContents.contains(null);
359
360             queue = new ArrayList JavaDoc(initialContents);
361             contents = new HashSet JavaDoc(initialContents);
362         }
363
364         /**
365          * Adds an elements to the queue if it hasn't been already added.
366          */

367         public void offer(T element) {
368             assert element != null;
369
370             if (!contents.contains(element)) {
371                 contents.add(element);
372                 queue.add(element);
373             }
374         }
375
376         /**
377          * Returns true if the queue is empty.
378          */

379         public boolean isEmpty() {
380             return currentIndex >= queue.size();
381         }
382
383         /**
384          * Returns and removes the elements at the top of the queue or null if
385          * the queue is empty.
386          */

387         public T poll() {
388             T result = null;
389             if (!isEmpty()) {
390                 result = queue.get(currentIndex);
391                 currentIndex++;
392             }
393             return result;
394         }
395     }
396 }
397
Popular Tags