KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > java > plugin > standard > ShadingPathResolver


1 /*****************************************************************************
2  * Java Plug-in Framework (JPF)
3  * Copyright (C) 2004-2006 Dmitry Olshansky
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *****************************************************************************/

19 package org.java.plugin.standard;
20
21 import java.io.BufferedInputStream JavaDoc;
22 import java.io.BufferedOutputStream JavaDoc;
23 import java.io.File JavaDoc;
24 import java.io.FileFilter JavaDoc;
25 import java.io.FileInputStream JavaDoc;
26 import java.io.FileOutputStream JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.InputStream JavaDoc;
29 import java.io.OutputStream JavaDoc;
30 import java.net.JarURLConnection JavaDoc;
31 import java.net.MalformedURLException JavaDoc;
32 import java.net.URL JavaDoc;
33 import java.net.URLConnection JavaDoc;
34 import java.text.DateFormat JavaDoc;
35 import java.text.ParseException JavaDoc;
36 import java.text.SimpleDateFormat JavaDoc;
37 import java.util.Calendar JavaDoc;
38 import java.util.Collection JavaDoc;
39 import java.util.Date JavaDoc;
40 import java.util.Enumeration JavaDoc;
41 import java.util.HashMap JavaDoc;
42 import java.util.HashSet JavaDoc;
43 import java.util.Iterator JavaDoc;
44 import java.util.LinkedList JavaDoc;
45 import java.util.Locale JavaDoc;
46 import java.util.Map JavaDoc;
47 import java.util.Properties JavaDoc;
48 import java.util.Set JavaDoc;
49 import java.util.StringTokenizer JavaDoc;
50 import java.util.regex.Pattern JavaDoc;
51 import java.util.zip.ZipEntry JavaDoc;
52 import java.util.zip.ZipFile JavaDoc;
53 import java.util.zip.ZipInputStream JavaDoc;
54
55 import org.apache.commons.logging.Log;
56 import org.apache.commons.logging.LogFactory;
57 import org.java.plugin.registry.Identity;
58 import org.java.plugin.registry.Library;
59 import org.java.plugin.registry.PluginAttribute;
60 import org.java.plugin.registry.PluginDescriptor;
61 import org.java.plugin.registry.PluginElement;
62 import org.java.plugin.registry.PluginFragment;
63 import org.java.plugin.registry.UniqueIdentity;
64 import org.java.plugin.util.ExtendedProperties;
65 import org.java.plugin.util.IoUtil;
66
67 /**
68  * This implementation of path resolver makes "shadow copy" of plug-in resources
69  * before resolving paths to them, this helps avoid locking of local resources
70  * and run native code from remote locations.
71  * <p>
72  * <b>Configuration parameters</b>
73  * </p>
74  * <p>
75  * This path resolver implementation supports following configuration
76  * parameters:
77  * <dl>
78  * <dt>shadowFolder</dt>
79  * <dd>Path to the folder where to copy resources to prevent their locking. By
80  * default this will be
81  * <code>System.getProperty("java.io.tmpdir") + "/.jpf-shadow"</code>.
82  * Please note that this folder will be maintained automatically by the
83  * Framework and might be cleared without any confirmation or notification.
84  * So it is strongly not recommended to use plug-ins folder (or other
85  * sensitive application directory) as shadow folder, this may lead to
86  * losing your data.</dd>
87  * <dt>unpackMode</dt>
88  * <dd>If <code>always</code>, "JAR'ed" or "ZIP'ed" plug-ins will be
89  * un-compressed to the shadow folder, if <code>never</code>, they will be
90  * just copied, if <code>smart</code>, the processing depends on plug-in
91  * content - if plug-in contains JAR libraries, it will be un-packed,
92  * otherwise just copied to shadow folder. It is also possible to add
93  * boolean "unpack" attribute to plug-in manifest, in this case, it's value
94  * will be taken into account. The default parameter value is
95  * <code>smart</code>.</dd>
96  * <dt>excludes</dt>
97  * <dd>Pipe <code>'|'</code> separated list of regular expression patterns
98  * to be used to exclude files to be shadowed. By default no files excluded.
99  * </dd>
100  * <dt>includes</dt>
101  * <dd>Pipe <code>'|'</code> separated list of regular expression patterns
102  * to be used to include files to be shadowed. By default all files
103  * included.</dd>
104  * </dl>
105  * </p>
106  *
107  * @version $Id: ShadingPathResolver.java,v 1.16 2006/10/19 18:41:19 ddimon Exp $
108  */

109 public class ShadingPathResolver extends StandardPathResolver {
110     private static final String JavaDoc UNPACK_MODE_ALWAIS = "always"; //$NON-NLS-1$
111
private static final String JavaDoc UNPACK_MODE_NEVER = "never"; //$NON-NLS-1$
112
private static final String JavaDoc UNPACK_MODE_SMART = "smart"; //$NON-NLS-1$
113

114     private File JavaDoc shadowFolder;
115     private String JavaDoc unpackMode;
116     private Map JavaDoc shadowUrlMap = new HashMap JavaDoc(); // <pluginId or fragmentId, shadow URL>
117
private Map JavaDoc unpackModeMap = new HashMap JavaDoc(); // <pluginId or fragmentId, Boolean>
118
private ShadowDataController controller;
119
120     /**
121      * @see org.java.plugin.PathResolver#configure(ExtendedProperties)
122      */

123     public synchronized void configure(final ExtendedProperties config)
124             throws Exception JavaDoc {
125         super.configure(config);
126         String JavaDoc folder = config.getProperty("shadowFolder"); //$NON-NLS-1$
127
if ((folder != null) && (folder.length() > 0)) {
128             try {
129                 shadowFolder = new File JavaDoc(folder).getCanonicalFile();
130             } catch (IOException JavaDoc ioe) {
131                 log.warn("failed initializing shadow folder " + folder //$NON-NLS-1$
132
+ ", falling back to the default folder", ioe); //$NON-NLS-1$
133
}
134         }
135         if (shadowFolder == null) {
136             shadowFolder = new File JavaDoc(System.getProperty("java.io.tmpdir"), //$NON-NLS-1$
137
".jpf-shadow"); //$NON-NLS-1$
138
}
139         log.debug("shadow folder is " + shadowFolder); //$NON-NLS-1$
140
if (!shadowFolder.exists()) {
141             shadowFolder.mkdirs();
142         }
143         unpackMode = config.getProperty("unpackMode", UNPACK_MODE_SMART); //$NON-NLS-1$
144
log.debug("unpack mode parameter value is " + unpackMode); //$NON-NLS-1$
145
controller = ShadowDataController.init(shadowFolder,
146                 buildFileFilter(config));
147         log.info("configured, shadow folder is " + shadowFolder); //$NON-NLS-1$
148
}
149     
150     private FileFilter JavaDoc buildFileFilter(final ExtendedProperties config) {
151         final FileFilter JavaDoc includesFilter;
152         String JavaDoc patterns = config.getProperty("includes"); //$NON-NLS-1$
153
if ((patterns != null) && (patterns.trim().length() > 0)) {
154             includesFilter = new RegexpFileFilter(patterns);
155         } else {
156             includesFilter = null;
157         }
158         final FileFilter JavaDoc excludesFilter;
159         patterns = config.getProperty("excludes"); //$NON-NLS-1$
160
if ((patterns != null) && (patterns.trim().length() > 0)) {
161             excludesFilter = new RegexpFileFilter(patterns);
162         } else {
163             excludesFilter = null;
164         }
165         if ((excludesFilter == null) && (includesFilter == null)) {
166             return null;
167         }
168         return new CombinedFileFilter(includesFilter, excludesFilter);
169     }
170
171     /**
172      * @see org.java.plugin.standard.StandardPathResolver#registerContext(
173      * org.java.plugin.registry.Identity, java.net.URL)
174      */

175     public void registerContext(Identity idt, URL JavaDoc url) {
176         super.registerContext(idt, url);
177         Boolean JavaDoc mode;
178         if (UNPACK_MODE_ALWAIS.equalsIgnoreCase(unpackMode)) {
179             mode = Boolean.TRUE;
180         } else if (UNPACK_MODE_NEVER.equalsIgnoreCase(unpackMode)) {
181             mode = Boolean.FALSE;
182         } else {
183             PluginDescriptor descr = null;
184             PluginFragment fragment = null;
185             if (idt instanceof PluginDescriptor) {
186                 descr = (PluginDescriptor) idt;
187             } else if (idt instanceof PluginFragment) {
188                 fragment = (PluginFragment) idt;
189                 descr = fragment.getRegistry().getPluginDescriptor(
190                         fragment.getPluginId());
191             } else if (idt instanceof PluginElement) {
192                 PluginElement element = (PluginElement) idt;
193                 descr = element.getDeclaringPluginDescriptor();
194                 fragment = element.getDeclaringPluginFragment();
195             } else {
196                 throw new IllegalArgumentException JavaDoc("unknown identity class " //$NON-NLS-1$
197
+ idt.getClass().getName());
198             }
199             mode = getUnpackMode(descr, fragment);
200         }
201         log.debug("unpack mode for " + idt + " is " + mode); //$NON-NLS-1$ //$NON-NLS-2$
202
unpackModeMap.put(idt.getId(), mode);
203     }
204     
205     private Boolean JavaDoc getUnpackMode(final PluginDescriptor descr,
206             final PluginFragment fragment) {
207         for (Iterator JavaDoc it = filterCollection(descr.getAttributes("unpack"), //$NON-NLS-1$
208
fragment).iterator(); it.hasNext();) {
209             return Boolean.valueOf("false".equalsIgnoreCase( //$NON-NLS-1$
210
((PluginAttribute) it.next()).getValue()));
211         }
212         for (Iterator JavaDoc it = filterCollection(descr.getLibraries(),
213                 fragment).iterator(); it.hasNext();) {
214             Library lib = (Library) it.next();
215             if (lib.isCodeLibrary() && (lib.getPath().toLowerCase(
216                             Locale.getDefault()).endsWith(".jar") //$NON-NLS-1$
217
|| lib.getPath().toLowerCase(
218                             Locale.getDefault()).endsWith(".zip"))) { //$NON-NLS-1$
219
return Boolean.TRUE;
220             }
221         }
222         return Boolean.FALSE;
223     }
224     
225     private Collection JavaDoc filterCollection(final Collection JavaDoc coll,
226             final PluginFragment fragment) {
227         if (fragment == null) {
228             return coll;
229         }
230         LinkedList JavaDoc result = new LinkedList JavaDoc();
231         for (Iterator JavaDoc it = coll.iterator(); it.hasNext();) {
232             PluginElement element = (PluginElement) it.next();
233             if (fragment.equals(element.getDeclaringPluginFragment())) {
234                 result.add(element);
235             }
236         }
237         return result;
238     }
239     
240     /**
241      * @see org.java.plugin.standard.StandardPathResolver#unregisterContext(
242      * java.lang.String)
243      */

244     public void unregisterContext(String JavaDoc id) {
245         shadowUrlMap.remove(id);
246         unpackModeMap.remove(id);
247         super.unregisterContext(id);
248     }
249
250     /**
251      * @see org.java.plugin.PathResolver#resolvePath(
252      * org.java.plugin.registry.Identity, java.lang.String)
253      */

254     public URL JavaDoc resolvePath(final Identity idt, final String JavaDoc path) {
255         URL JavaDoc baseUrl;
256         if (idt instanceof PluginDescriptor) {
257             baseUrl = getBaseUrl((PluginDescriptor) idt);
258         } else if (idt instanceof PluginFragment) {
259             baseUrl = getBaseUrl((PluginFragment) idt);
260         } else if (idt instanceof PluginElement) {
261             PluginElement element = (PluginElement) idt;
262             if (element.getDeclaringPluginFragment() != null) {
263                 baseUrl = getBaseUrl(
264                         element.getDeclaringPluginFragment());
265             } else {
266                 baseUrl = getBaseUrl(
267                         element.getDeclaringPluginDescriptor());
268             }
269         } else {
270             throw new IllegalArgumentException JavaDoc("unknown identity class " //$NON-NLS-1$
271
+ idt.getClass().getName());
272         }
273         return resolvePath(baseUrl, path);
274     }
275     
276     protected synchronized URL JavaDoc getBaseUrl(final UniqueIdentity uid) {
277         URL JavaDoc result = (URL JavaDoc) shadowUrlMap.get(uid.getId());
278         if (result != null) {
279             return result;
280         }
281         result = controller.shadowResource(getRegisteredContext(uid.getId()),
282                 uid.getUniqueId(),
283                 ((Boolean JavaDoc) unpackModeMap.get(uid.getId())).booleanValue());
284         shadowUrlMap.put(uid.getId(), result);
285         return result;
286     }
287 }
288
289 final class ShadingUtil {
290     static String JavaDoc getExtension(final String JavaDoc name) {
291         if ((name == null) || (name.length() == 0)) {
292             return null;
293         }
294         int p = name.lastIndexOf('.');
295         if ((p != -1) && (p > 0) && (p < name.length() - 1)) {
296             return name.substring(p + 1);
297         }
298         return null;
299     }
300     
301     static void unpack(final ZipFile JavaDoc zipFile,
302             final File JavaDoc destFolder) throws IOException JavaDoc {
303         for (Enumeration JavaDoc en = zipFile.entries(); en.hasMoreElements();) {
304             ZipEntry JavaDoc entry = (ZipEntry JavaDoc) en.nextElement();
305             String JavaDoc name = entry.getName();
306             File JavaDoc entryFile =
307                 new File JavaDoc(destFolder.getCanonicalPath() + "/" + name); //$NON-NLS-1$
308
if (name.endsWith("/")) { //$NON-NLS-1$
309
if (!entryFile.exists() && !entryFile.mkdirs()) {
310                     throw new IOException JavaDoc("can't create folder " + entryFile); //$NON-NLS-1$
311
}
312             } else {
313                 File JavaDoc folder = entryFile.getParentFile();
314                 if (!folder.exists() && !folder.mkdirs()) {
315                     throw new IOException JavaDoc("can't create folder " + folder); //$NON-NLS-1$
316
}
317                 OutputStream JavaDoc out = new BufferedOutputStream JavaDoc(
318                         new FileOutputStream JavaDoc(entryFile, false));
319                 try {
320                     InputStream JavaDoc in = zipFile.getInputStream(entry);
321                     try {
322                         IoUtil.copyStream(in, out, 1024);
323                     } finally {
324                         in.close();
325                     }
326                 } finally {
327                     out.close();
328                 }
329             }
330             entryFile.setLastModified(entry.getTime());
331         }
332     }
333     
334     static void unpack(final InputStream JavaDoc strm,
335             final File JavaDoc destFolder) throws IOException JavaDoc {
336         ZipInputStream JavaDoc zipStrm = new ZipInputStream JavaDoc(strm);
337         ZipEntry JavaDoc entry = zipStrm.getNextEntry();
338         while (entry != null) {
339             String JavaDoc name = entry.getName();
340             File JavaDoc entryFile =
341                 new File JavaDoc(destFolder.getCanonicalPath() + "/" + name); //$NON-NLS-1$
342
if (name.endsWith("/")) { //$NON-NLS-1$
343
if (!entryFile.exists() && !entryFile.mkdirs()) {
344                     throw new IOException JavaDoc("can't create folder " + entryFile); //$NON-NLS-1$
345
}
346             } else {
347                 File JavaDoc folder = entryFile.getParentFile();
348                 if (!folder.exists() && !folder.mkdirs()) {
349                     throw new IOException JavaDoc("can't create folder " + folder); //$NON-NLS-1$
350
}
351                 OutputStream JavaDoc out = new BufferedOutputStream JavaDoc(
352                         new FileOutputStream JavaDoc(entryFile, false));
353                 try {
354                     IoUtil.copyStream(zipStrm, out, 1024);
355                 } finally {
356                     out.close();
357                 }
358             }
359             entryFile.setLastModified(entry.getTime());
360             entry = zipStrm.getNextEntry();
361         }
362     }
363     
364     static boolean deleteFile(final File JavaDoc file) {
365         if (file.isDirectory()) {
366             IoUtil.emptyFolder(file);
367         }
368         return file.delete();
369     }
370     
371     static Date JavaDoc getLastModified(final URL JavaDoc url) throws IOException JavaDoc {
372         long result = 0;
373         File JavaDoc sourceFile = null;
374         if ("jar".equalsIgnoreCase(url.getProtocol())) { //$NON-NLS-1$
375
String JavaDoc urlStr = url.toExternalForm();
376             int p = urlStr.indexOf("!/"); //$NON-NLS-1$
377
if (p != -1) {
378                 sourceFile = IoUtil.url2file(new URL JavaDoc(urlStr.substring(4, p)));
379             }
380         }
381         if (sourceFile == null) {
382             sourceFile = IoUtil.url2file(url);
383         }
384         if (sourceFile != null) {
385             result = sourceFile.lastModified();
386         } else {
387             URLConnection JavaDoc cnn = url.openConnection();
388             try {
389                 cnn.setUseCaches(false);
390                 result = cnn.getLastModified();
391             } finally {
392                 cnn.getInputStream().close();
393             }
394         }
395         if (result == 0) {
396             throw new IOException JavaDoc(
397                     "can't retrieve modification date for resource " //$NON-NLS-1$
398
+ url);
399         }
400         // for some reason modification milliseconds for some files are unstable
401
Calendar JavaDoc cldr = Calendar.getInstance(Locale.ENGLISH);
402         cldr.setTime(new Date JavaDoc(result));
403         cldr.set(Calendar.MILLISECOND, 0);
404         return cldr.getTime();
405     }
406     
407     private static String JavaDoc getRelativePath(final File JavaDoc base, final File JavaDoc file)
408             throws IOException JavaDoc {
409         String JavaDoc basePath;
410         String JavaDoc filePath = file.getCanonicalPath();
411         if (base.isFile()) {
412             File JavaDoc baseParent = base.getParentFile();
413             if (baseParent == null) {
414                 return null;
415             }
416             basePath = baseParent.getCanonicalPath();
417         } else {
418             basePath = base.getCanonicalPath();
419         }
420         if (!basePath.endsWith(File.separator)) {
421             basePath += File.separator;
422         }
423         int p = basePath.indexOf(File.separatorChar);
424         String JavaDoc prefix = null;
425         while (p != -1) {
426             String JavaDoc newPrefix = basePath.substring(0, p + 1);
427             if (!filePath.startsWith(newPrefix)) {
428                 break;
429             }
430             prefix = newPrefix;
431             p = basePath.indexOf(File.separatorChar, p + 1);
432         }
433         if (prefix == null) {
434             return null;
435         }
436         filePath = filePath.substring(prefix.length());
437         if (prefix.length() == basePath.length()) {
438             return filePath;
439         }
440         int c = 0;
441         p = basePath.indexOf(File.separatorChar, prefix.length());
442         while (p != -1) {
443             c++;
444             p = basePath.indexOf(File.separatorChar, p + 1);
445         }
446         for (int i = 0; i < c; i++) {
447             filePath = ".." + File.separator + filePath; //$NON-NLS-1$
448
}
449         return filePath;
450     }
451     
452     private static String JavaDoc getRelativeUrl(final File JavaDoc base, final File JavaDoc file)
453             throws IOException JavaDoc {
454         String JavaDoc result = ShadingUtil.getRelativePath(base, file);
455         if (result == null) {
456             return null;
457         }
458         result = result.replace('\\', '/');
459         if (file.isDirectory() && !result.endsWith("/")) { //$NON-NLS-1$
460
result += "/"; //$NON-NLS-1$
461
}
462         return result;
463     }
464
465     static String JavaDoc getRelativeUrl(final File JavaDoc base, final URL JavaDoc url)
466             throws IOException JavaDoc {
467         File JavaDoc file = IoUtil.url2file(url);
468         if (file != null) {
469             String JavaDoc result = getRelativeUrl(base, file);
470             if (result != null) {
471                 return result;
472             }
473         }
474         if ("jar".equalsIgnoreCase(url.getProtocol())) { //$NON-NLS-1$
475
String JavaDoc urlStr = url.toExternalForm();
476             int p = urlStr.indexOf("!/"); //$NON-NLS-1$
477
if (p != -1) {
478                 return "jar:" //$NON-NLS-1$
479
+ getRelativeUrl(base, new URL JavaDoc(urlStr.substring(4, p)))
480                     + urlStr.substring(p);
481             }
482         }
483         return url.toExternalForm();
484     }
485     
486     static URL JavaDoc buildURL(final URL JavaDoc base, final String JavaDoc url)
487             throws MalformedURLException JavaDoc {
488         if (!url.toLowerCase(Locale.ENGLISH).startsWith("jar:")) { //$NON-NLS-1$
489
return new URL JavaDoc(base, url);
490         }
491         int p = url.indexOf("!/"); //$NON-NLS-1$
492
if (p == -1) {
493             return new URL JavaDoc(base, url);
494         }
495         return new URL JavaDoc("jar:" //$NON-NLS-1$
496
+ new URL JavaDoc(base, url.substring(4, p)).toExternalForm()
497                 + url.substring(p));
498     }
499     
500     private ShadingUtil() {
501         // no-op
502
}
503 }
504
505 final class ShadowDataController {
506     private static final String JavaDoc META_FILE_NAME = ".meta"; //$NON-NLS-1$
507

508     private final Log log = LogFactory.getLog(ShadowDataController.class);
509     private final File JavaDoc shadowFolder;
510     private final URL JavaDoc shadowFolderUrl;
511     private final Properties JavaDoc metaData;
512     private final DateFormat JavaDoc dtf = new SimpleDateFormat JavaDoc("yyyy-MM-dd HH:mm:ss"); //$NON-NLS-1$
513
private final FileFilter JavaDoc fileFilter;
514     
515     static ShadowDataController init(final File JavaDoc shadowFolder,
516             final FileFilter JavaDoc filter) throws IOException JavaDoc {
517         ShadowDataController result =
518             new ShadowDataController(shadowFolder, filter);
519         result.quickCheck();
520         result.save();
521         return result;
522     }
523
524     private ShadowDataController(final File JavaDoc folder, final FileFilter JavaDoc filter)
525             throws IOException JavaDoc {
526         shadowFolder = folder;
527         fileFilter = filter;
528         shadowFolderUrl = IoUtil.file2url(folder);
529         File JavaDoc metaFile = new File JavaDoc(shadowFolder, META_FILE_NAME);
530         metaData = new Properties JavaDoc();
531         if (metaFile.isFile()) {
532             try {
533                 InputStream JavaDoc in = new FileInputStream JavaDoc(metaFile);
534                 try {
535                     metaData.load(in);
536                 } finally {
537                     in.close();
538                 }
539                 if (log.isDebugEnabled()) {
540                     log.debug("meta-data loaded from file " + metaFile); //$NON-NLS-1$
541
}
542             } catch (IOException JavaDoc ioe) {
543                 log.warn("failed loading meta-data from file " + metaFile, ioe); //$NON-NLS-1$
544
}
545         }
546     }
547     
548     private void save() {
549         File JavaDoc metaFile = new File JavaDoc(shadowFolder, META_FILE_NAME);
550         try {
551             OutputStream JavaDoc out = new FileOutputStream JavaDoc(metaFile, false);
552             try {
553                 metaData.store(out, "This is automatically generated file."); //$NON-NLS-1$
554
} finally {
555                 out.close();
556             }
557             if (log.isDebugEnabled()) {
558                 log.debug("meta-data saved to file " + metaFile); //$NON-NLS-1$
559
}
560         } catch (IOException JavaDoc ioe) {
561             log.warn("failed saving meta-data to file " + metaFile, ioe); //$NON-NLS-1$
562
}
563     }
564     
565     private void quickCheck() {
566         File JavaDoc[] files = shadowFolder.listFiles(new ShadowFileFilter());
567         for (int i = 0; i < files.length; i++) {
568             File JavaDoc file = files[i];
569             if (metaData.containsValue(file.getName())) {
570                 continue;
571             }
572             if (ShadingUtil.deleteFile(file)) {
573                 if (log.isDebugEnabled()) {
574                     log.debug("deleted shadow file " + file); //$NON-NLS-1$
575
}
576             } else {
577                 log.warn("can't delete shadow file " + file); //$NON-NLS-1$
578
}
579         }
580         Set JavaDoc uids = new HashSet JavaDoc();
581         for (Iterator JavaDoc it = metaData.entrySet().iterator(); it.hasNext();) {
582             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
583             String JavaDoc key = (String JavaDoc) entry.getKey();
584             if (!key.startsWith("uid:")) { //$NON-NLS-1$
585
continue;
586             }
587             uids.add(entry.getValue());
588         }
589         for (Iterator JavaDoc it = uids.iterator(); it.hasNext();) {
590             quickCheck((String JavaDoc) it.next());
591         }
592     }
593     
594     private void quickCheck(final String JavaDoc uid) {
595         if (log.isDebugEnabled()) {
596             log.debug("quick check of UID " + uid); //$NON-NLS-1$
597
}
598         String JavaDoc url = metaData.getProperty("source:" + uid, null); //$NON-NLS-1$
599
String JavaDoc file = metaData.getProperty("file:" + uid, null); //$NON-NLS-1$
600
String JavaDoc modified = metaData.getProperty("modified:" + uid, null); //$NON-NLS-1$
601
if ((url == null) || (file == null) || (modified == null)) {
602             if (log.isDebugEnabled()) {
603                 log.debug("meta-data incomplete, UID=" + uid); //$NON-NLS-1$
604
}
605             remove(uid);
606             return;
607         }
608         try {
609             if (!dtf.parse(modified).equals(ShadingUtil.getLastModified(
610                     ShadingUtil.buildURL(shadowFolderUrl, url)))) {
611                 if (log.isDebugEnabled()) {
612                     log.debug("source modification detected, UID=" + uid //$NON-NLS-1$
613
+ ", source=" + url); //$NON-NLS-1$
614
}
615                 remove(uid);
616             }
617         } catch (IOException JavaDoc ioe) {
618             log.warn("quick check failed", ioe); //$NON-NLS-1$
619
remove(uid);
620         } catch (ParseException JavaDoc pe) {
621             log.warn("quick check failed", pe); //$NON-NLS-1$
622
remove(uid);
623         }
624     }
625     
626     private void remove(final String JavaDoc uid) {
627         String JavaDoc file = metaData.getProperty("file:" + uid, null); //$NON-NLS-1$
628
if (file != null) {
629             File JavaDoc lostFile = new File JavaDoc(shadowFolder, file);
630             if (ShadingUtil.deleteFile(lostFile)) {
631                 if (log.isDebugEnabled()) {
632                     log.debug("deleted lost file " + file); //$NON-NLS-1$
633
}
634             } else {
635                 log.warn("can't delete lost file " + file); //$NON-NLS-1$
636
}
637         }
638         boolean removed = metaData.remove("uid:" + uid) != null; //$NON-NLS-1$
639
removed |= metaData.remove("source:" + uid) != null; //$NON-NLS-1$
640
removed |= metaData.remove("file:" + uid) != null; //$NON-NLS-1$
641
removed |= metaData.remove("modified:" + uid) != null; //$NON-NLS-1$
642
if (removed && log.isDebugEnabled()) {
643             log.debug("removed meta-data, UID=" + uid); //$NON-NLS-1$
644
}
645     }
646     
647     private URL JavaDoc add(final String JavaDoc uid, final URL JavaDoc sourceUrl, final File JavaDoc file,
648             final Date JavaDoc modified) throws IOException JavaDoc {
649         URL JavaDoc result = IoUtil.file2url(file);
650         metaData.setProperty("uid:" + uid, uid); //$NON-NLS-1$
651
String JavaDoc source = ShadingUtil.getRelativeUrl(shadowFolder, sourceUrl);
652         metaData.setProperty("source:" + uid, source); //$NON-NLS-1$
653
metaData.setProperty("file:" + uid, file.getName()); //$NON-NLS-1$
654
metaData.setProperty("modified:" + uid, dtf.format(modified)); //$NON-NLS-1$
655
save();
656         if (log.isDebugEnabled()) {
657             log.debug("shading done, UID=" + uid + ", source=" //$NON-NLS-1$ //$NON-NLS-2$
658
+ source + ", file=" + result //$NON-NLS-1$
659
+ ", modified=" + dtf.format(modified)); //$NON-NLS-1$
660
}
661         return result;
662     }
663     
664     URL JavaDoc shadowResource(final URL JavaDoc source, final String JavaDoc uid,
665             final boolean unpack) {
666         try {
667             URL JavaDoc result = deepCheck(source, uid);
668             if (result != null) {
669                 if (log.isDebugEnabled()) {
670                     log.debug("got actual shaded resource, UID=" + uid //$NON-NLS-1$
671
+ ", source=" + source //$NON-NLS-1$
672
+ ", file=" + result); //$NON-NLS-1$
673
}
674                 return result;
675             }
676         } catch (Exception JavaDoc e) {
677             log.warn("deep check failed, UID=" + uid //$NON-NLS-1$
678
+ ", URL=" + source, e); //$NON-NLS-1$
679
remove(uid);
680         }
681         Date JavaDoc lastModified;
682         try {
683             lastModified = ShadingUtil.getLastModified(source);
684         } catch (IOException JavaDoc ioe) {
685             log.error("shading failed, can't get modification date for " //$NON-NLS-1$
686
+ source, ioe);
687             return source;
688         }
689         File JavaDoc file = IoUtil.url2file(source);
690         if ((file != null) && file.isDirectory()) {
691             // copy local folder to the shadow directory
692
try {
693                 File JavaDoc rootFolder = new File JavaDoc(shadowFolder, uid);
694                 IoUtil.copyFolder(file, rootFolder, true, true, fileFilter);
695                 return add(uid, source, rootFolder, lastModified);
696             } catch (IOException JavaDoc ioe) {
697                 log.error("failed shading local folder " + file, ioe); //$NON-NLS-1$
698
return source;
699             }
700         }
701         try {
702             if ("jar".equalsIgnoreCase(source.getProtocol())) { //$NON-NLS-1$
703
String JavaDoc urlStr = source.toExternalForm();
704                 int p = urlStr.indexOf("!/"); //$NON-NLS-1$
705
if (p == -1) {
706                     p = urlStr.length();
707                 }
708                 URL JavaDoc jarFileURL = new URL JavaDoc(urlStr.substring(4, p));
709                 if (!unpack) {
710                     String JavaDoc ext = ShadingUtil.getExtension(jarFileURL.getFile());
711                     if (ext == null) {
712                         ext = "jar"; //$NON-NLS-1$
713
}
714                     File JavaDoc shadowFile = new File JavaDoc(shadowFolder, uid + '.' + ext);
715                     File JavaDoc sourceFile = IoUtil.url2file(jarFileURL);
716                     InputStream JavaDoc in;
717                     if (sourceFile != null) {
718                         in = new BufferedInputStream JavaDoc(
719                                 new FileInputStream JavaDoc(sourceFile));
720                     } else {
721                         in = jarFileURL.openStream();
722                     }
723                     try {
724                         OutputStream JavaDoc out =
725                             new FileOutputStream JavaDoc(shadowFile, false);
726                         try {
727                             IoUtil.copyStream(in, out, 1024);
728                         } finally {
729                             out.close();
730                         }
731                     } finally {
732                         in.close();
733                     }
734                     return add(uid, source, shadowFile, lastModified);
735                 }
736                 URLConnection JavaDoc cnn = null;
737                 try {
738                     File JavaDoc sourceFile = IoUtil.url2file(jarFileURL);
739                     ZipFile JavaDoc zipFile;
740                     if (sourceFile != null) {
741                         zipFile = new ZipFile JavaDoc(sourceFile);
742                     } else {
743                         cnn = source.openConnection();
744                         cnn.setUseCaches(false);
745                         zipFile = ((JarURLConnection JavaDoc) cnn).getJarFile();
746                     }
747                     File JavaDoc rootFolder = new File JavaDoc(shadowFolder, uid);
748                     try {
749                         ShadingUtil.unpack(zipFile, rootFolder);
750                     } finally {
751                         zipFile.close();
752                     }
753                     return add(uid, source, rootFolder, lastModified);
754                 } finally {
755                     if (cnn != null) {
756                         cnn.getInputStream().close();
757                     }
758                 }
759             }
760         } catch (IOException JavaDoc ioe) {
761             log.error("failed shading URL connection " + source, ioe); //$NON-NLS-1$
762
return source;
763         }
764         String JavaDoc fileName = source.getFile();
765         if (fileName == null) {
766             log.warn("can't get file name from resource " + source //$NON-NLS-1$
767
+ ", shading failed"); //$NON-NLS-1$
768
return source;
769         }
770         String JavaDoc ext = ShadingUtil.getExtension(fileName);
771         if (ext == null) {
772             log.warn("can't get file name extension for resource " + source //$NON-NLS-1$
773
+ ", shading failed"); //$NON-NLS-1$
774
return source;
775         }
776         if (unpack && ("jar".equalsIgnoreCase(ext) //$NON-NLS-1$
777
|| "zip".equalsIgnoreCase(ext))) { //$NON-NLS-1$
778
try {
779                 InputStream JavaDoc strm = source.openStream();
780                 File JavaDoc rootFolder = new File JavaDoc(shadowFolder, uid);
781                 try {
782                     ShadingUtil.unpack(strm, rootFolder);
783                 } finally {
784                     strm.close();
785                 }
786                 return add(uid, source, rootFolder, lastModified);
787             } catch (IOException JavaDoc ioe) {
788                 log.error("failed shading packed resource " + source, ioe); //$NON-NLS-1$
789
return source;
790             }
791         }
792         try {
793             File JavaDoc shadowFile = new File JavaDoc(shadowFolder, uid + '.' + ext);
794             InputStream JavaDoc in = source.openStream();
795             try {
796                 OutputStream JavaDoc out = new FileOutputStream JavaDoc(shadowFile, false);
797                 try {
798                     IoUtil.copyStream(in, out, 1024);
799                 } finally {
800                     out.close();
801                 }
802             } finally {
803                 in.close();
804             }
805             return add(uid, source, shadowFile, lastModified);
806         } catch (IOException JavaDoc ioe) {
807             log.error("failed shading resource file " + source, ioe); //$NON-NLS-1$
808
return source;
809         }
810     }
811     
812     private URL JavaDoc deepCheck(final URL JavaDoc source, final String JavaDoc uid) throws Exception JavaDoc {
813         String JavaDoc url = metaData.getProperty("source:" + uid, null); //$NON-NLS-1$
814
if (url == null) {
815             if (log.isDebugEnabled()) {
816                 log.debug("URL not found in meta-data, UID=" + uid); //$NON-NLS-1$
817
}
818             remove(uid);
819             return null;
820         }
821         if (log.isDebugEnabled()) {
822             log.debug("URL found in meta-data, UID=" //$NON-NLS-1$
823
+ uid + ", source=" + source //$NON-NLS-1$
824
+ ", storedURL=" + url); //$NON-NLS-1$
825
}
826         URL JavaDoc storedSource = ShadingUtil.buildURL(shadowFolderUrl, url);
827         if (!storedSource.equals(source)) {
828             if (log.isDebugEnabled()) {
829                 log.debug("inconsistent URL found in meta-data, UID=" //$NON-NLS-1$
830
+ uid + ", source=" + source //$NON-NLS-1$
831
+ ", storedSource=" + storedSource); //$NON-NLS-1$
832
}
833             remove(uid);
834             return null;
835         }
836         String JavaDoc modified = metaData.getProperty("modified:" + uid, null); //$NON-NLS-1$
837
if (modified == null) {
838             if (log.isDebugEnabled()) {
839                 log.debug("modification info not found in meta-data, UID=" //$NON-NLS-1$
840
+ uid);
841             }
842             remove(uid);
843             return null;
844         }
845         if (!ShadingUtil.getLastModified(source).equals(dtf.parse(modified))) {
846             if (log.isDebugEnabled()) {
847                 log.debug("source modification detected, UID=" + uid //$NON-NLS-1$
848
+ ", source=" + source); //$NON-NLS-1$
849
}
850             remove(uid);
851             return null;
852         }
853         String JavaDoc fileStr = metaData.getProperty("file:" + uid, null); //$NON-NLS-1$
854
if (fileStr == null) {
855             if (log.isDebugEnabled()) {
856                 log.debug("file info not found in meta-data, UID=" + uid); //$NON-NLS-1$
857
}
858             remove(uid);
859             return null;
860         }
861         File JavaDoc file = new File JavaDoc(shadowFolder, fileStr);
862         if (!file.exists()) {
863             if (log.isDebugEnabled()) {
864                 log.debug("shadow file not found, UID=" + uid //$NON-NLS-1$
865
+ ", source=" + source //$NON-NLS-1$
866
+ ", file=" + file); //$NON-NLS-1$
867
}
868             remove(uid);
869             return null;
870         }
871         File JavaDoc sourceFile = IoUtil.url2file(source);
872         if ((sourceFile != null) && sourceFile.isDirectory()) {
873             IoUtil.synchronizeFolders(sourceFile, file, fileFilter);
874             if (log.isDebugEnabled()) {
875                 log.debug("folders synchronized, UID=" + uid //$NON-NLS-1$
876
+ ", srcFile=" + sourceFile //$NON-NLS-1$
877
+ ", destFile=" + file); //$NON-NLS-1$
878
}
879         } else {
880             if (log.isDebugEnabled()) {
881                 log.debug("source " + source + " (file is " + sourceFile //$NON-NLS-1$ //$NON-NLS-2$
882
+ ") is not local folder, " //$NON-NLS-1$
883
+ "skipping synchronization, UID=" + uid); //$NON-NLS-1$
884
}
885         }
886         return IoUtil.file2url(file);
887     }
888     
889     static class ShadowFileFilter implements FileFilter JavaDoc {
890         /**
891          * @see java.io.FileFilter#accept(java.io.File)
892          */

893         public boolean accept(final File JavaDoc file) {
894             return !META_FILE_NAME.equals(file.getName());
895         }
896     }
897 }
898
899 final class RegexpFileFilter implements FileFilter JavaDoc {
900     private final Pattern JavaDoc[] patterns;
901     
902     RegexpFileFilter(final String JavaDoc str) {
903         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(str, "|", false); //$NON-NLS-1$
904
patterns = new Pattern JavaDoc[st.countTokens()];
905         for (int i = 0; i < patterns.length; i++) {
906             String JavaDoc pattern = st.nextToken();
907             if ((pattern == null) || (pattern.trim().length() == 0)) {
908                 continue;
909             }
910             patterns[i] = Pattern.compile(pattern.trim());
911         }
912     }
913
914     /**
915      * @see java.io.FileFilter#accept(java.io.File)
916      */

917     public boolean accept(final File JavaDoc file) {
918         for (int i = 0; i < patterns.length; i++) {
919             if (patterns[i] == null) {
920                 continue;
921             }
922             if (patterns[i].matcher(file.getName()).matches()) {
923                 return true;
924             }
925         }
926         return false;
927     }
928 }
929
930 final class CombinedFileFilter implements FileFilter JavaDoc {
931     private final FileFilter JavaDoc includesFilter;
932     private final FileFilter JavaDoc excludesFilter;
933
934     CombinedFileFilter(final FileFilter JavaDoc includes, final FileFilter JavaDoc excludes) {
935         includesFilter = includes;
936         excludesFilter = excludes;
937     }
938
939     /**
940      * @see java.io.FileFilter#accept(java.io.File)
941      */

942     public boolean accept(final File JavaDoc file) {
943         if (includesFilter != null) {
944             if (includesFilter.accept(file)) {
945                 return true;
946             }
947         }
948         if ((excludesFilter != null) && excludesFilter.accept(file)) {
949             return false;
950         }
951         return true;
952     }
953 }
954
Popular Tags