KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > spi > project > support > ant > GlobFileBuiltQuery


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.spi.project.support.ant;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.io.File JavaDoc;
25 import java.lang.ref.Reference JavaDoc;
26 import java.lang.ref.WeakReference JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Arrays JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31 import java.util.WeakHashMap JavaDoc;
32 import java.util.logging.Level JavaDoc;
33 import java.util.logging.Logger JavaDoc;
34 import javax.swing.event.ChangeEvent JavaDoc;
35 import javax.swing.event.ChangeListener JavaDoc;
36 import org.netbeans.api.queries.FileBuiltQuery;
37 import org.netbeans.modules.project.ant.FileChangeSupport;
38 import org.netbeans.modules.project.ant.FileChangeSupportEvent;
39 import org.netbeans.modules.project.ant.FileChangeSupportListener;
40 import org.netbeans.spi.queries.FileBuiltQueryImplementation;
41 import org.openide.ErrorManager;
42 import org.openide.filesystems.FileAttributeEvent;
43 import org.openide.filesystems.FileChangeListener;
44 import org.openide.filesystems.FileEvent;
45 import org.openide.filesystems.FileObject;
46 import org.openide.filesystems.FileRenameEvent;
47 import org.openide.filesystems.FileUtil;
48 import org.openide.loaders.DataObject;
49 import org.openide.loaders.DataObjectNotFoundException;
50 import org.openide.util.Exceptions;
51 import org.openide.util.RequestProcessor;
52 import org.openide.util.Utilities;
53 import org.openide.util.WeakListeners;
54
55 /**
56  * Simple file built query based on glob patterns.
57  * @see AntProjectHelper#createGlobFileBuiltQuery
58  * @author Jesse Glick
59  */

60 final class GlobFileBuiltQuery implements FileBuiltQueryImplementation {
61     
62     private static final ErrorManager err = ErrorManager.getDefault().getInstance("org.netbeans.spi.project.support.ant.GlobFileBuiltQuery"); // NOI18N
63

64     private final AntProjectHelper helper;
65     private final PropertyEvaluator eval;
66     private final String JavaDoc[] fromPrefixes;
67     private final String JavaDoc[] fromSuffixes;
68     private final String JavaDoc[] toPrefixes;
69     private final String JavaDoc[] toSuffixes;
70     private static final Reference JavaDoc<StatusImpl> NONE = new WeakReference JavaDoc<StatusImpl>(null);
71     private final Map JavaDoc<FileObject,Reference JavaDoc<StatusImpl>> statuses = new WeakHashMap JavaDoc<FileObject,Reference JavaDoc<StatusImpl>>();
72
73     /**
74      * Create a new query implementation based on an Ant-based project.
75      * @see AntProjectHelper#createGlobFileBuiltQuery
76      */

77     public GlobFileBuiltQuery(AntProjectHelper helper, PropertyEvaluator eval, String JavaDoc[] from, String JavaDoc[] to) throws IllegalArgumentException JavaDoc {
78         this.helper = helper;
79         this.eval = eval;
80         int l = from.length;
81         if (to.length != l) {
82             throw new IllegalArgumentException JavaDoc("Non-matching lengths"); // NOI18N
83
}
84         fromPrefixes = new String JavaDoc[l];
85         fromSuffixes = new String JavaDoc[l];
86         toPrefixes = new String JavaDoc[l];
87         toSuffixes = new String JavaDoc[l];
88         for (int i = 0; i < l; i++) {
89             int idx = from[i].indexOf('*');
90             if (idx == -1 || idx != from[i].lastIndexOf('*')) {
91                 throw new IllegalArgumentException JavaDoc("Zero or multiple asterisks in " + from[i]); // NOI18N
92
}
93             fromPrefixes[i] = from[i].substring(0, idx);
94             fromSuffixes[i] = from[i].substring(idx + 1);
95             idx = to[i].indexOf('*');
96             if (idx == -1 || idx != to[i].lastIndexOf('*')) {
97                 throw new IllegalArgumentException JavaDoc("Zero or multiple asterisks in " + to[i]); // NOI18N
98
}
99             toPrefixes[i] = to[i].substring(0, idx);
100             toSuffixes[i] = to[i].substring(idx + 1);
101             // XXX check that none of the pieces contain two slashes in a row, and
102
// the path does not start with or end with a slash, etc.
103
}
104         // XXX add properties listener to evaluator... if anything changes, refresh all
105
// status objects and clear the status cache; can then also keep a cache of
106
// evaluated path prefixes & suffixes
107
}
108     
109     public synchronized FileBuiltQuery.Status getStatus(FileObject file) {
110         Reference JavaDoc<StatusImpl> r = statuses.get(file);
111         if (r == NONE) {
112             return null;
113         }
114         StatusImpl status = (r != null) ? r.get() : null;
115         if (status == null) {
116             status = createStatus(file);
117             if (status != null) {
118                 statuses.put(file, new WeakReference JavaDoc<StatusImpl>(status));
119             } else {
120                 statuses.put(file, NONE);
121             }
122         }
123         return status;
124     }
125     
126     private File JavaDoc findTarget(FileObject file) {
127         File JavaDoc sourceF = FileUtil.toFile(file);
128         if (sourceF == null) {
129             if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
130                 err.log("Not a disk file: " + file);
131             }
132             return null;
133         }
134         String JavaDoc source = sourceF.getAbsolutePath();
135         for (int i = 0; i < fromPrefixes.length; i++) {
136             String JavaDoc prefixEval = eval.evaluate(fromPrefixes[i]);
137             if (prefixEval == null) {
138                 if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
139                     err.log(fromPrefixes[i] + " evaluates to null");
140                 }
141                 continue;
142             }
143             String JavaDoc suffixEval = eval.evaluate(fromSuffixes[i]);
144             if (suffixEval == null) {
145                 if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
146                     err.log(fromSuffixes[i] + " evaluates to null");
147                 }
148                 continue;
149             }
150             boolean endsWithSlash = prefixEval.endsWith("/"); // NOI18N
151
String JavaDoc prefixF = helper.resolveFile(prefixEval).getAbsolutePath();
152             if (endsWithSlash && !prefixF.endsWith(File.separator)) {
153                 prefixF += File.separatorChar;
154             }
155             if (!source.startsWith(prefixF)) {
156                 continue;
157             }
158             String JavaDoc remainder = source.substring(prefixF.length());
159             if (!remainder.endsWith(suffixEval.replace('/', File.separatorChar))) {
160                 continue;
161             }
162             String JavaDoc particular = remainder.substring(0, remainder.length() - suffixEval.length());
163             String JavaDoc toPrefixEval = eval.evaluate(toPrefixes[i]);
164             if (toPrefixEval == null) {
165                 if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
166                     err.log(toPrefixes[i] + " evaluates to null");
167                 }
168                 continue;
169             }
170             String JavaDoc toSuffixEval = eval.evaluate(toSuffixes[i]);
171             if (toSuffixEval == null) {
172                 if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
173                     err.log(toSuffixes[i] + " evaluates to null");
174                 }
175                 continue;
176             }
177             File JavaDoc target = helper.resolveFile(toPrefixEval + particular + toSuffixEval);
178             if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
179                 err.log("Found target for " + source + ": " + target);
180             }
181             return target;
182         }
183         if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
184             err.log("No match for path " + source + " among " + Arrays.asList(fromPrefixes) + " " + Arrays.asList(fromSuffixes));
185         }
186         return null;
187     }
188     
189     private StatusImpl createStatus(FileObject file) {
190         File JavaDoc target = findTarget(file);
191         if (target != null) {
192             try {
193                 DataObject source = DataObject.find(file);
194                 
195                 return new StatusImpl(source, file, target);
196             } catch (DataObjectNotFoundException e) {
197                 Logger.getLogger(GlobFileBuiltQuery.class.getName()).log(Level.FINE, null, e);
198                 return null;
199             }
200         } else {
201             return null;
202         }
203     }
204     
205     private final class StatusImpl implements FileBuiltQuery.Status, PropertyChangeListener JavaDoc/*<DataObject>*/, FileChangeListener, FileChangeSupportListener, Runnable JavaDoc {
206         
207         private final List JavaDoc<ChangeListener JavaDoc> listeners = new ArrayList JavaDoc<ChangeListener JavaDoc>();
208         private Boolean JavaDoc built = null;
209         private final DataObject source;
210         private File JavaDoc target;
211         
212         StatusImpl(DataObject source, FileObject sourceFO, File JavaDoc target) {
213             this.source = source;
214             this.source.addPropertyChangeListener(WeakListeners.propertyChange(this, this.source));
215             sourceFO.addFileChangeListener(FileUtil.weakFileChangeListener(this, sourceFO));
216             this.target = target;
217             FileChangeSupport.DEFAULT.addListener(this, target);
218         }
219         
220         // Side effect is to update its cache and maybe fire changes.
221
public boolean isBuilt() {
222             boolean doFire = false;
223             boolean b;
224             synchronized (GlobFileBuiltQuery.this) {
225                 b = isReallyBuilt();
226                 if (built != null && built.booleanValue() != b) {
227                     doFire = true;
228                 }
229                 built = Boolean.valueOf(b);
230                 if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
231                     err.log("isBuilt: " + b + " from " + this);
232                 }
233             }
234             if (doFire) {
235                 fireChange();
236             }
237             return b;
238         }
239         
240         private boolean isReallyBuilt() {
241             if (!source.isValid()) {
242                 if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
243                     err.log("invalid: " + this);
244                 }
245                 return false; // whatever
246
}
247             if (source.isModified()) {
248                 if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
249                     err.log("modified: " + this);
250                 }
251                 return false;
252             }
253             if (target == null) {
254                 if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
255                     err.log("no target matching " + this);
256                 }
257                 return false;
258             }
259             long targetTime = target.lastModified();
260             long sourceTime = source.getPrimaryFile().lastModified().getTime();
261             if (targetTime >= sourceTime) {
262                 return true;
263             } else {
264                 if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
265                     err.log("out of date (target: " + targetTime + " vs. source: " + sourceTime + "): " + this);
266                 }
267                 return false;
268             }
269         }
270         
271         public void addChangeListener(ChangeListener JavaDoc l) {
272             synchronized (listeners) {
273                 listeners.add(l);
274             }
275         }
276         
277         public void removeChangeListener(ChangeListener JavaDoc l) {
278             synchronized (listeners) {
279                 listeners.remove(l);
280             }
281         }
282         
283         private void fireChange() {
284             ChangeListener JavaDoc[] _listeners;
285             synchronized (listeners) {
286                 if (listeners.isEmpty()) {
287                     return;
288                 }
289                 _listeners = listeners.toArray(new ChangeListener JavaDoc[listeners.size()]);
290             }
291             ChangeEvent JavaDoc ev = new ChangeEvent JavaDoc(this);
292             for (ChangeListener JavaDoc l : _listeners) {
293                 l.stateChanged(ev);
294             }
295         }
296         
297         private void update() {
298             RequestProcessor.getDefault().post(this);
299         }
300         
301         public void run() {
302             isBuilt();
303         }
304         
305         public void propertyChange(PropertyChangeEvent JavaDoc evt) {
306             assert evt.getSource() instanceof DataObject;
307             if (DataObject.PROP_MODIFIED.equals(evt.getPropertyName())) {
308                 update();
309             }
310         }
311         
312         public void fileChanged(FileEvent fe) {
313             update();
314         }
315         
316         public void fileDeleted(FileEvent fe) {
317             update();
318         }
319         
320         public void fileRenamed(FileRenameEvent fe) {
321             File JavaDoc target2 = findTarget(source.getPrimaryFile());
322             if (!Utilities.compareObjects(target, target2)) {
323                 // #45694: source file moved, recalculate target.
324
if (target != null) {
325                     FileChangeSupport.DEFAULT.removeListener(this, target);
326                 }
327                 if (target2 != null) {
328                     FileChangeSupport.DEFAULT.addListener(this, target2);
329                 }
330                 target = target2;
331             }
332             update();
333         }
334         
335         public void fileDataCreated(FileEvent fe) {
336             // ignore
337
}
338         
339         public void fileFolderCreated(FileEvent fe) {
340             // ignore
341
}
342         
343         public void fileAttributeChanged(FileAttributeEvent fe) {
344             // ignore
345
}
346         
347         public void fileCreated(FileChangeSupportEvent event) {
348             update();
349         }
350
351         public void fileDeleted(FileChangeSupportEvent event) {
352             update();
353         }
354
355         public void fileModified(FileChangeSupportEvent event) {
356             update();
357         }
358         
359         public String JavaDoc toString() {
360             return "GFBQ.StatusImpl[" + source.getPrimaryFile() + " -> " + target + "]"; // NOI18N
361
}
362
363     }
364     
365 }
366
Popular Tags