KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > loaders > FolderOrder


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.openide.loaders;
21
22 import java.lang.ref.Reference JavaDoc;
23 import java.lang.ref.SoftReference JavaDoc;
24
25 import java.io.IOException JavaDoc;
26 import java.util.*;
27
28 import org.openide.filesystems.*;
29 import org.openide.loaders.DataFolder.SortMode;
30
31
32 /** A support for keeping order of children for folder list.
33  *
34  * @author Jaroslav Tulach
35  */

36 final class FolderOrder extends Object JavaDoc implements Comparator<DataObject> {
37     /** Separator of names of two files. The first file should be before
38      * the second one in partial ordering
39      */

40     private static final char SEP = '/';
41     
42     /** a static map with (FileObject, Reference (Folder))
43      */

44     private static final WeakHashMap<FileObject, Reference JavaDoc<FolderOrder>> map =
45             new WeakHashMap<FileObject, Reference JavaDoc<FolderOrder>> (101);
46     /** A static of known folder orders. Though we hold the
47      * FolderOrder with a soft reference which can be collected, even
48      * if this happens we would like the new FolderOrder to have any
49      * previously determined order attribute. Otherwise under obscure
50      * circumstances (#15381) it is possible for the IDE to go into an
51      * endless loop recalculating folder orders, since they keep
52      * getting collected.
53      */

54     private static final Map<FileObject, Object JavaDoc> knownOrders =
55             Collections.synchronizedMap(new WeakHashMap<FileObject, Object JavaDoc>(50));
56     
57
58     /** map of names of primary files of objects to their index or null */
59     private Map<String JavaDoc,Integer JavaDoc> order;
60     /** file to store data in */
61     private FileObject folder;
62     /** if true, partial orderings on disk should be ignored for files in the order */
63     private boolean ignorePartials;
64     /** a reference to sort mode of this folder order */
65     private SortMode sortMode;
66     /** previous value of the order */
67     private Object JavaDoc previous;
68
69     /** Constructor.
70     * @param folder the folder to create order for
71     */

72     private FolderOrder (FileObject folder) {
73         this.folder = folder;
74     }
75     
76     
77     /** Changes a sort order for this order
78      * @param mode sort mode.
79      */

80     public void setSortMode (SortMode mode) throws IOException JavaDoc {
81         // store the mode to properties
82
sortMode = mode;
83         mode.write (folder); // writes attribute EA_SORT_MODE -> updates FolderList
84

85         // FolderList.changedFolderOrder (folder);
86
}
87     
88     /** Getter for the sort order.
89      */

90     public SortMode getSortMode () {
91         if (sortMode == null) {
92             sortMode = SortMode.read (folder);
93         }
94         return sortMode;
95     }
96     
97     /** Changes the order of data objects.
98      */

99     public synchronized void setOrder (DataObject[] arr) throws IOException JavaDoc {
100         if (arr != null) {
101             order = new HashMap<String JavaDoc, Integer JavaDoc> (arr.length * 4 / 3 + 1);
102
103             // each object only once
104
Enumeration en = org.openide.util.Enumerations.removeDuplicates (
105                 org.openide.util.Enumerations.array (arr)
106             );
107
108             int i = 0;
109             while (en.hasMoreElements ()) {
110                 DataObject obj = (DataObject)en.nextElement ();
111                 FileObject fo = obj.getPrimaryFile ();
112                 if (folder.equals (fo.getParent ())) {
113                     // object for my folder
114
order.put (fo.getNameExt (), Integer.valueOf (i++));
115                 }
116             }
117             // Explicit order has been set, if written please clear affected
118
// order markings.
119
ignorePartials = true;
120         } else {
121             order = null;
122         }
123         
124         write (); // writes attribute EA_ORDER -> updates FolderList
125

126         
127         // FolderList.changedFolderOrder (folder);
128
}
129
130     /**
131      * Get ordering constraints for this folder.
132      * Returns a map from data objects to lists of data objects they should precede.
133      * @param objects a collection of data objects known to be in the folder
134      * @return a constraint map, or null if there are no constraints
135      */

136     public synchronized Map<DataObject, List<DataObject>> getOrderingConstraints(Collection<DataObject> objects) {
137         final Set<String JavaDoc> partials = readPartials ();
138         if (partials.isEmpty ()) {
139             return null;
140         } else {
141             Map<String JavaDoc, DataObject> objectsByName = new HashMap<String JavaDoc, DataObject>();
142             for (DataObject d: objects) {
143                 objectsByName.put(d.getPrimaryFile().getNameExt(), d);
144             }
145             Map<DataObject, List<DataObject>> m = new HashMap<DataObject, List<DataObject>>();
146             for (String JavaDoc constraint: partials) {
147                 int idx = constraint.indexOf(SEP);
148                 String JavaDoc a = constraint.substring(0, idx);
149                 String JavaDoc b = constraint.substring(idx + 1);
150                 if (ignorePartials && (order.containsKey(a) || order.containsKey(b))) {
151                     continue;
152                 }
153                 DataObject ad = objectsByName.get(a);
154                 if (ad == null) {
155                     continue;
156                 }
157                 DataObject bd = objectsByName.get(b);
158                 if (bd == null) {
159                     continue;
160                 }
161                 List<DataObject> l = m.get(ad);
162                 if (l == null) {
163                     m.put(ad, l = new LinkedList<DataObject>());
164                 }
165                 l.add(bd);
166             }
167             return m;
168         }
169     }
170
171     /** Read the list of intended partial orders from disk.
172      * Each element is a string of the form "a<b" for a, b filenames
173      * with extension, where a should come before b.
174      */

175     private Set<String JavaDoc> readPartials () {
176         Enumeration<String JavaDoc> e = folder.getAttributes ();
177         Set<String JavaDoc> s = new HashSet<String JavaDoc> ();
178         while (e.hasMoreElements ()) {
179             String JavaDoc name = e.nextElement ();
180             if (name.indexOf (SEP) != -1) {
181                 Object JavaDoc value = folder.getAttribute (name);
182                 if ((value instanceof Boolean JavaDoc) && ((Boolean JavaDoc) value).booleanValue ())
183                     s.add (name);
184             }
185         }
186         return s;
187     }
188
189     /** Compares two data object or two nodes.
190     */

191     public int compare (DataObject obj1, DataObject obj2) {
192         Integer JavaDoc i1 = (order == null) ? null : order.get (obj1.getPrimaryFile ().getNameExt ());
193         Integer JavaDoc i2 = (order == null) ? null : order.get (obj2.getPrimaryFile ().getNameExt ());
194
195         if (i1 == null) {
196             if (i2 != null) return 1;
197
198             // compare by the provided comparator
199
return getSortMode ().compare (obj1, obj2);
200         } else {
201             if (i2 == null) return -1;
202             // compare integers
203
if (i1.intValue () == i2.intValue ()) return 0;
204             if (i1.intValue () < i2.intValue ()) return -1;
205             return 1;
206         }
207     }
208
209     /** Stores the order to files.
210     */

211     public void write () throws IOException JavaDoc {
212         // Let it throw the IOException:
213
//if (folder.getFileSystem ().isReadOnly ()) return; // cannot write to read-only FS
214
if (order == null) {
215             // if we should clear the order
216
folder.setAttribute (DataFolder.EA_ORDER, null);
217         } else {
218             // Stores list of file names separated by /
219
java.util.Iterator JavaDoc<Map.Entry<String JavaDoc, Integer JavaDoc>> it = order.entrySet ().iterator ();
220             String JavaDoc[] filenames = new String JavaDoc[order.size ()];
221             while (it.hasNext ()) {
222                 Map.Entry<String JavaDoc, Integer JavaDoc> en = it.next ();
223                 String JavaDoc fo = en.getKey ();
224                 int indx = en.getValue ().intValue ();
225                 filenames[indx] = fo;
226             }
227             StringBuffer JavaDoc buf = new StringBuffer JavaDoc (255);
228             for (int i = 0; i < filenames.length; i++) {
229                 if (i > 0) {
230                     buf.append ('/');
231                 }
232                 buf.append (filenames[i]);
233             }
234
235             // Read *before* setting EA_ORDER, since org.netbeans.modules.apisupport.project.layers.WritableXMLFileSystem
236
// will kill off the partials when it gets that:
237
Set<String JavaDoc> p = ignorePartials ? readPartials() : null;
238             
239             folder.setAttribute (DataFolder.EA_ORDER, buf.toString ());
240
241             if (ignorePartials) {
242                 // Reverse any existing partial orders among files explicitly
243
// mentioned in the order.
244
if (! p.isEmpty ()) {
245                     Set<String JavaDoc> f = new HashSet<String JavaDoc> ();
246                     for (String JavaDoc fo: order.keySet()) {
247                         f.add (fo);
248                     }
249                     for (String JavaDoc s: p) {
250                         int idx = s.indexOf (SEP);
251                         if (f.contains (s.substring (0, idx)) &&
252                             f.contains (s.substring (idx + 1))) {
253                             folder.setAttribute (s, null);
254                         }
255                     }
256                 }
257                 // Need not do this again for this order:
258
ignorePartials = false;
259             }
260         }
261     }
262     
263     /** Reads the order from disk.
264      */

265     private void read () {
266         Object JavaDoc o = folder.getAttribute (DataFolder.EA_ORDER);
267         
268         if ((previous == null && o == null) ||
269             (previous != null && previous.equals (o))) {
270             // no change in order
271
return;
272         }
273         
274         if ((o instanceof Object JavaDoc[]) && (previous instanceof Object JavaDoc[])) {
275             if (compare((Object JavaDoc[]) o, (Object JavaDoc[]) previous)) {
276                 return;
277             }
278         }
279         
280         doRead (o);
281         
282         previous = o;
283         if (previous != null) {
284             knownOrders.put(folder, previous);
285         }
286         
287         FolderList.changedFolderOrder (folder);
288     }
289
290     /** Compares two arrays */
291     private static boolean compare(Object JavaDoc[] a, Object JavaDoc[] b) {
292         if (a == b) {
293             return true;
294         }
295         
296         int len = Math.min(a.length, b.length);
297         for (int i = 0; i < len; i++) {
298             if (a[i] != b[i]) {
299                 if (a[i] == null) {
300                     return false;
301                 }
302                 
303                 if (a[i].equals(b[i])) {
304                     continue;
305                 }
306                 
307                 if ((a[i] instanceof Object JavaDoc[]) && (b[i] instanceof Object JavaDoc[])) {
308                     if (compare((Object JavaDoc[]) a[i], (Object JavaDoc[]) b[i])) {
309                         continue;
310                     } else {
311                         return false;
312                     }
313                 } else {
314                     return false;
315                 }
316             }
317         }
318         
319         Object JavaDoc[] arr = (a.length > b.length) ? a : b;
320         if (checkNonNull(arr, len)) {
321             return false;
322         }
323         
324         return true;
325     }
326     
327     private static boolean checkNonNull(Object JavaDoc[] a, int from) {
328         for (int i = from; i < a.length; i++) {
329             if (a[i] != null) {
330                 return true;
331             }
332         }
333         
334         return false;
335     }
336     
337     /** Reads the values from the object o
338      * @param o value of attribute EA_ORDER
339      */

340     private void doRead (Object JavaDoc o) {
341         if (o == null) {
342             order = null;
343             return;
344         } else if (o instanceof String JavaDoc[][]) {
345             // Compatibility:
346
String JavaDoc[][] namesExts = (String JavaDoc[][]) o;
347
348             if (namesExts.length != 2) {
349                 order = null;
350                 return;
351             }
352             String JavaDoc[] names = namesExts[0];
353             String JavaDoc[] exts = namesExts[1];
354
355             if (names == null || exts == null || names.length != exts.length) {
356                 // empty order
357
order = null;
358                 return;
359             }
360
361
362             Map<String JavaDoc, Integer JavaDoc> set = new HashMap<String JavaDoc, Integer JavaDoc> (names.length);
363
364             for (int i = 0; i < names.length; i++) {
365                 set.put (names[i], Integer.valueOf (i));
366             }
367             order = set;
368             return;
369             
370         } else if (o instanceof String JavaDoc) {
371             // Current format:
372
String JavaDoc sepnames = (String JavaDoc) o;
373             Map<String JavaDoc, Integer JavaDoc> set = new HashMap<String JavaDoc, Integer JavaDoc> ();
374             StringTokenizer tok = new StringTokenizer (sepnames, "/"); // NOI18N
375
int i = 0;
376             while (tok.hasMoreTokens ()) {
377                 String JavaDoc file = tok.nextToken ();
378                 set.put (file, Integer.valueOf (i));
379                 i++;
380             }
381             
382             order = set;
383             return;
384         } else {
385             // Unknown format:
386
order = null;
387             return;
388         }
389     }
390     
391
392     /** Creates order for given folder object.
393     * @param f the folder
394     * @return the order
395     */

396     public static FolderOrder findFor (FileObject folder) {
397         FolderOrder order = null;
398         synchronized (map) {
399             Reference JavaDoc<FolderOrder> ref = map.get (folder);
400             order = ref == null ? null : ref.get ();
401             if (order == null) {
402                 order = new FolderOrder (folder);
403                 order.previous = knownOrders.get(folder);
404                 order.doRead(order.previous);
405                 
406                 map.put (folder, new SoftReference JavaDoc<FolderOrder> (order));
407             }
408         }
409         // always reread the order from disk, so it is uptodate
410
synchronized (order) {
411             order.read ();
412             return order;
413         }
414     }
415         
416      
417     
418 }
419
Popular Tags