1:
31: package ;
32:
33: import ;
34: import ;
35: import ;
36: import ;
37: import ;
38: import ;
39:
40: import ;
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50:
51:
66: public class ResourceManager
67: {
68:
72: private static final Set failedModules = new HashSet();
73:
74: private ArrayList resourceLoaders;
75: private ArrayList resourceFactories;
76: private ResourceDataCache dataCache;
77: private ResourceFactoryCache factoryCache;
78:
79: private static final String LOADER_PREFIX = "org.jfree.resourceloader.loader.";
80: private static final String FACTORY_TYPE_PREFIX = "org.jfree.resourceloader.factory.type.";
81: public static final String DATA_CACHE_PROVIDER_KEY = "org.jfree.resourceloader.cache.DataCacheProvider";
82: public static final String FACTORY_CACHE_PROVIDER_KEY = "org.jfree.resourceloader.cache.FactoryCacheProvider";
83:
84: public ResourceManager()
85: {
86: resourceLoaders = new ArrayList();
87: resourceFactories = new ArrayList();
88: dataCache = new NullResourceDataCache();
89: factoryCache = new NullResourceFactoryCache();
90: }
91:
92:
99: public synchronized ResourceKey createKey(final Object data)
100: throws ResourceKeyCreationException
101: {
102: return createKey(data, null);
103: }
104:
105:
113: public synchronized ResourceKey createKey(final Object data, final Map parameters)
114: throws ResourceKeyCreationException
115: {
116: if (data == null)
117: {
118: throw new NullPointerException("Key data must not be null.");
119: }
120:
121: final Iterator values = resourceLoaders.iterator();
122: while (values.hasNext())
123: {
124: final ResourceLoader loader = (ResourceLoader) values.next();
125: try
126: {
127: final ResourceKey key = loader.createKey(data, parameters);
128: if (key != null)
129: {
130: return key;
131: }
132: }
133: catch (ResourceKeyCreationException rkce)
134: {
135:
136: }
137: }
138:
139: throw new ResourceKeyCreationException
140: ("Unable to create key: No loader was able " +
141: "to handle the given key data: " + data);
142: }
143:
144:
155: public ResourceKey deriveKey(final ResourceKey parent, final String path)
156: throws ResourceKeyCreationException
157: {
158: return deriveKey(parent, path, null);
159: }
160:
161:
175: public ResourceKey deriveKey(final ResourceKey parent, final String path, final Map parameters)
176: throws ResourceKeyCreationException
177: {
178: if (path == null)
179: {
180: throw new NullPointerException("Key data must not be null.");
181: }
182: if (parent == null)
183: {
184: return createKey(path, parameters);
185: }
186:
187:
188:
189:
190: ResourceKeyCreationException rce = null;
191: for (int i = 0; i < resourceLoaders.size(); i++)
192: {
193: final ResourceLoader loader = (ResourceLoader) resourceLoaders.get(i);
194: if (loader.isSupportedKey(parent) == false)
195: {
196: continue;
197: }
198: try
199: {
200: final ResourceKey key = loader.deriveKey(parent, path, parameters);
201: if (key != null)
202: {
203: return key;
204: }
205: }
206: catch (ResourceKeyCreationException rcke)
207: {
208: rce = rcke;
209: }
210: }
211:
212:
213:
214: for (int i = 0; i < resourceLoaders.size(); i++)
215: {
216: final ResourceLoader loader = (ResourceLoader) resourceLoaders.get(i);
217: final ResourceKey key = loader.createKey(path, parameters);
218: if (key != null)
219: {
220: return key;
221: }
222: }
223:
224: if (rce != null)
225: {
226: throw rce;
227: }
228: throw new ResourceKeyCreationException
229: ("Unable to create key: No such schema or the key was not recognized.");
230: }
231:
232:
238: private ResourceLoader findBySchema(final ResourceKey key)
239: {
240: for (int i = 0; i < resourceLoaders.size(); i++)
241: {
242: final ResourceLoader loader = (ResourceLoader) resourceLoaders.get(i);
243: if (loader.isSupportedKey(key))
244: {
245: return loader;
246: }
247: }
248: return null;
249: }
250:
251:
258: public URL toURL(final ResourceKey key)
259: {
260: final ResourceLoader loader = findBySchema(key);
261: if (loader == null)
262: {
263: return null;
264: }
265: return loader.toURL(key);
266: }
267:
268: public ResourceData load(final ResourceKey key) throws ResourceLoadingException
269: {
270: final ResourceLoader loader = findBySchema(key);
271: if (loader == null)
272: {
273: throw new ResourceLoadingException
274: ("Invalid key: No resource-loader registered for schema: " + key.getSchema());
275: }
276:
277: final ResourceDataCacheEntry cached = dataCache.get(key);
278: if (cached != null)
279: {
280: final ResourceData data = cached.getData();
281:
282: if (cached.getStoredVersion() < 0)
283: {
284:
285: return data;
286: }
287:
288: final long version = data.getVersion(this);
289: if (version < 0)
290: {
291:
292:
293:
294: dataCache.remove(data);
295: }
296: else if (cached.getStoredVersion() == version)
297: {
298: return data;
299: }
300: else
301: {
302: dataCache.remove(data);
303: }
304: }
305: final ResourceData data = loader.load(key);
306: return dataCache.put(this, data);
307: }
308:
309: public Resource createDirectly(final Object keyValue, final Class target)
310: throws ResourceLoadingException,
311: ResourceCreationException,
312: ResourceKeyCreationException
313: {
314: final ResourceKey key = createKey(keyValue);
315: return create(key, null, target);
316: }
317:
318: public Resource create(final ResourceKey key, final ResourceKey context, final Class target)
319: throws ResourceLoadingException, ResourceCreationException
320: {
321: if (target == null)
322: {
323: throw new NullPointerException("Target must not be null");
324: }
325: if (key == null)
326: {
327: throw new NullPointerException("Key must not be null.");
328: }
329: return create(key, context, new Class[]{target});
330: }
331:
332: public Resource create(final ResourceKey key, final ResourceKey context)
333: throws ResourceLoadingException, ResourceCreationException
334: {
335: return create(key, context, (Class[]) null);
336: }
337:
338: public Resource create(final ResourceKey key, final ResourceKey context, final Class[] target)
339: throws ResourceLoadingException, ResourceCreationException
340: {
341: if (key == null)
342: {
343: throw new NullPointerException("Key must not be null.");
344: }
345:
346:
347:
348: final Resource resource = factoryCache.get(key);
349: if (resource != null)
350: {
351: if (isResourceUnchanged(resource))
352: {
353:
354: return resource;
355: }
356: else
357: {
358:
359: factoryCache.remove(resource);
360: }
361: }
362:
363:
364: if (target == null)
365: {
366: return autoCreateResource(key, context);
367: }
368:
369: ResourceCreationException exception = null;
370: final ResourceData data = load(key);
371: for (int i = 0; i < resourceFactories.size(); i++)
372: {
373: final ResourceFactory fact =
374: (ResourceFactory) resourceFactories.get(i);
375: if (isSupportedTarget(target, fact) == false)
376: {
377:
378: continue;
379: }
380:
381: try
382: {
383: return performCreate(data, fact, context);
384: }
385: catch (ContentNotRecognizedException ce)
386: {
387:
388: }
389: catch (ResourceCreationException rex)
390: {
391:
392: exception = rex;
393: if (Log.isDebugEnabled())
394: {
395: Log.debug("Failed at " + fact.getClass() + ": ", rex);
396: }
397: }
398:
399: }
400:
401: if (exception != null)
402: {
403: throw exception;
404: }
405: throw new ContentNotRecognizedException
406: ("None of the selected factories was able to handle the given data: " + key);
407: }
408:
409: private boolean isSupportedTarget(final Class[] target, final ResourceFactory fact)
410: {
411: final Class factoryType = fact.getFactoryType();
412: for (int j = 0; j < target.length; j++)
413: {
414: final Class aClass = target[j];
415: if (aClass != null && aClass.isAssignableFrom(factoryType))
416: {
417: return true;
418: }
419: }
420: return false;
421: }
422:
423: private Resource autoCreateResource(final ResourceKey key,
424: final ResourceKey context)
425: throws ResourceLoadingException, ResourceCreationException
426: {
427: final ResourceData data = load(key);
428:
429: final Iterator it = resourceFactories.iterator();
430: while (it.hasNext())
431: {
432: final ResourceFactory fact = (ResourceFactory) it.next();
433: try
434: {
435: final Resource res = performCreate(data, fact, context);
436: if (res != null)
437: {
438: return res;
439: }
440: }
441: catch (ResourceCreationException rex)
442: {
443:
444: }
445: }
446: throw new ResourceCreationException
447: ("No known factory was able to handle the given data.");
448: }
449:
450: private Resource performCreate(final ResourceData data,
451: final ResourceFactory fact,
452: final ResourceKey context)
453: throws ResourceLoadingException, ResourceCreationException
454: {
455: final Resource created = fact.create(this, data, context);
456: factoryCache.put(created);
457: return created;
458: }
459:
460: private boolean isResourceUnchanged(final Resource resource)
461: throws ResourceLoadingException
462: {
463: final ResourceKey[] deps = resource.getDependencies();
464: for (int i = 0; i < deps.length; i++)
465: {
466: final ResourceKey dep = deps[i];
467: final long version = resource.getVersion(dep);
468: if (version == -1)
469: {
470:
471: continue;
472: }
473:
474: final ResourceData data = load(dep);
475: if (data.getVersion(this) != version)
476: {
477:
478:
479: return false;
480: }
481: }
482:
483:
484: return true;
485: }
486:
487: public ResourceDataCache getDataCache()
488: {
489: return dataCache;
490: }
491:
492: public void setDataCache(final ResourceDataCache dataCache)
493: {
494: if (dataCache == null)
495: {
496: throw new NullPointerException();
497: }
498: this.dataCache = dataCache;
499: }
500:
501: public ResourceFactoryCache getFactoryCache()
502: {
503: return factoryCache;
504: }
505:
506: public void setFactoryCache(final ResourceFactoryCache factoryCache)
507: {
508: if (factoryCache == null)
509: {
510: throw new NullPointerException();
511: }
512: this.factoryCache = factoryCache;
513: }
514:
515: public void registerDefaults()
516: {
517:
518: registerDefaultLoaders();
519:
520:
521: registerDefaultFactories();
522:
523:
524: registerDataCache();
525: registerFactoryCache();
526: }
527:
528: public void registerDefaultFactories()
529: {
530: final Configuration config = LibLoaderBoot.getInstance().getGlobalConfig();
531: final Iterator itType = config.findPropertyKeys(FACTORY_TYPE_PREFIX);
532: while (itType.hasNext())
533: {
534: final String key = (String) itType.next();
535: final String factoryClass = config.getConfigProperty(key);
536:
537: final Object maybeFactory = ObjectUtilities.loadAndInstantiate
538: (factoryClass, ResourceManager.class, ResourceFactory.class);
539: if (maybeFactory instanceof ResourceFactory == false)
540: {
541: continue;
542: }
543:
544: final ResourceFactory factory = (ResourceFactory) maybeFactory;
545: factory.initializeDefaults();
546: registerFactory(factory);
547: }
548: }
549:
550: public void registerDataCache()
551: {
552: final Configuration config = LibLoaderBoot.getInstance().getGlobalConfig();
553: final String dataCacheProviderClass =
554: config.getConfigProperty(DATA_CACHE_PROVIDER_KEY);
555: if (dataCacheProviderClass == null)
556: {
557: return;
558: }
559: final Object maybeDataCacheProvider =
560: ObjectUtilities.loadAndInstantiate
561: (dataCacheProviderClass, ResourceManager.class, ResourceDataCacheProvider.class);
562: if (maybeDataCacheProvider instanceof ResourceDataCacheProvider)
563: {
564: final ResourceDataCacheProvider provider = (ResourceDataCacheProvider) maybeDataCacheProvider;
565: try
566: {
567: final ResourceDataCache cache = provider.createDataCache();
568: if (cache != null)
569: {
570: setDataCache(cache);
571: }
572: }
573: catch (Throwable e)
574: {
575:
576: synchronized (failedModules)
577: {
578: if (failedModules.contains(dataCacheProviderClass) == false)
579: {
580: Log.warn("Failed to create data cache: " + e.getLocalizedMessage());
581: failedModules.add(dataCacheProviderClass);
582: }
583: }
584: }
585: }
586: }
587:
588: public void registerFactoryCache()
589: {
590: final Configuration config = LibLoaderBoot.getInstance().getGlobalConfig();
591: final String cacheProviderClass = config.getConfigProperty
592: (FACTORY_CACHE_PROVIDER_KEY);
593: if (cacheProviderClass == null)
594: {
595: return;
596: }
597: final Object maybeCacheProvider = ObjectUtilities.loadAndInstantiate
598: (cacheProviderClass, ResourceManager.class, ResourceFactoryCacheProvider.class);
599:
600: if (maybeCacheProvider != null)
601: {
602: final ResourceFactoryCacheProvider provider = (ResourceFactoryCacheProvider) maybeCacheProvider;
603: try
604: {
605: final ResourceFactoryCache cache = provider.createFactoryCache();
606: if (cache != null)
607: {
608: setFactoryCache(cache);
609: }
610: }
611: catch (Throwable e)
612: {
613: synchronized (failedModules)
614: {
615: if (failedModules.contains(cacheProviderClass) == false)
616: {
617: Log.warn("Failed to create factory cache: " + e.getLocalizedMessage());
618: failedModules.add(cacheProviderClass);
619: }
620: }
621: }
622: }
623: }
624:
625: public void registerDefaultLoaders()
626: {
627: final Configuration config = LibLoaderBoot.getInstance().getGlobalConfig();
628: final Iterator it = config.findPropertyKeys(LOADER_PREFIX);
629: while (it.hasNext())
630: {
631: final String key = (String) it.next();
632: final String value = config.getConfigProperty(key);
633: final Object o = ObjectUtilities.loadAndInstantiate(value, ResourceManager.class, ResourceLoader.class);
634: if (o != null)
635: {
636: final ResourceLoader loader = (ResourceLoader) o;
637:
638: registerLoader(loader);
639: }
640: }
641: }
642:
643: public void registerLoader(final ResourceLoader loader)
644: {
645: if (loader == null)
646: {
647: throw new NullPointerException("ResourceLoader must not be null.");
648: }
649: loader.setResourceManager(this);
650: resourceLoaders.add(loader);
651: }
652:
653: public void registerFactory(final ResourceFactory factory)
654: {
655: if (factory == null)
656: {
657: throw new NullPointerException("ResourceFactory must not be null.");
658: }
659: resourceFactories.add(factory);
660: }
661:
662: }