KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > velocity > runtime > resource > ResourceManagerImpl


1 package org.apache.velocity.runtime.resource;
2
3 /*
4  * Copyright 2000-2001,2004 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18
19 import java.util.ArrayList JavaDoc;
20 import java.util.Hashtable JavaDoc;
21 import java.util.Vector JavaDoc;
22
23 import java.io.InputStream JavaDoc;
24 import java.io.IOException JavaDoc;
25
26 import org.apache.velocity.runtime.RuntimeServices;
27 import org.apache.velocity.runtime.RuntimeConstants;
28
29 import org.apache.velocity.runtime.resource.ResourceFactory;
30 import org.apache.velocity.runtime.resource.loader.ResourceLoader;
31 import org.apache.velocity.runtime.resource.loader.ResourceLoaderFactory;
32
33 import org.apache.velocity.exception.ResourceNotFoundException;
34 import org.apache.velocity.exception.ParseErrorException;
35
36 import org.apache.commons.collections.ExtendedProperties;
37
38 /**
39  * Class to manage the text resource for the Velocity
40  * Runtime.
41  *
42  * @author <a HREF="mailto:jvanzyl@apache.org">Jason van Zyl</a>
43  * @author <a HREF="mailto:paulo.gaspar@krankikom.de">Paulo Gaspar</a>
44  * @author <a HREF="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
45  * @version $Id: ResourceManagerImpl.java,v 1.7.4.1 2004/03/03 23:23:01 geirm Exp $
46  */

47 public class ResourceManagerImpl implements ResourceManager
48 {
49     /**
50      * A template resources.
51      */

52     public static final int RESOURCE_TEMPLATE = 1;
53     
54     /**
55      * A static content resource.
56      */

57     public static final int RESOURCE_CONTENT = 2;
58
59     /**
60      * token used to identify the loader internally
61      */

62     private static final String JavaDoc RESOURCE_LOADER_IDENTIFIER = "_RESOURCE_LOADER_IDENTIFIER_";
63
64     /**
65      * Object implementing ResourceCache to
66      * be our resource manager's Resource cache.
67      */

68     protected ResourceCache globalCache = null;
69     
70     /**
71      * The List of templateLoaders that the Runtime will
72      * use to locate the InputStream source of a template.
73      */

74     protected ArrayList JavaDoc resourceLoaders = new ArrayList JavaDoc();
75     
76     /**
77      * This is a list of the template input stream source
78      * initializers, basically properties for a particular
79      * template stream source. The order in this list
80      * reflects numbering of the properties i.e.
81      *
82      * <loader-id>.resource.loader.<property> = <value>
83      */

84     private ArrayList JavaDoc sourceInitializerList = new ArrayList JavaDoc();
85     
86     /**
87      * This is a map of public name of the template
88      * stream source to it's initializer. This is so
89      * that clients of velocity can set properties of
90      * a template source stream with its public name.
91      * So for example, a client could set the
92      * File.resource.path property and this would
93      * change the resource.path property for the
94      * file template stream source.
95      */

96     private Hashtable JavaDoc sourceInitializerMap = new Hashtable JavaDoc();
97
98     /**
99      * Each loader needs a configuration object for
100      * its initialization, this flags keeps track of whether
101      * or not the configuration objects have been created
102      * for the resource loaders.
103      */

104     private boolean resourceLoaderInitializersActive = false;
105
106     /**
107      * switch to turn off log notice when a resource is found for
108      * the first time.
109      */

110     private boolean logWhenFound = true;
111
112     protected RuntimeServices rsvc = null;
113
114     /**
115      * Initialize the ResourceManager.
116      */

117     public void initialize( RuntimeServices rs )
118         throws Exception JavaDoc
119     {
120         rsvc = rs;
121         
122         rsvc.info("Default ResourceManager initializing. (" + this.getClass() + ")");
123
124         ResourceLoader resourceLoader;
125         
126         assembleResourceLoaderInitializers();
127         
128         for (int i = 0; i < sourceInitializerList.size(); i++)
129         {
130             ExtendedProperties configuration = (ExtendedProperties) sourceInitializerList.get(i);
131             String JavaDoc loaderClass = configuration.getString("class");
132
133             if ( loaderClass == null)
134             {
135                 rsvc.error( "Unable to find '"
136                                 + configuration.getString(RESOURCE_LOADER_IDENTIFIER)
137                                 + ".resource.loader.class' specification in configuation."
138                                 + " This is a critical value. Please adjust configuration.");
139                 continue;
140             }
141
142             resourceLoader = ResourceLoaderFactory.getLoader( rsvc, loaderClass);
143             resourceLoader.commonInit( rsvc, configuration);
144             resourceLoader.init(configuration);
145             resourceLoaders.add(resourceLoader);
146
147         }
148
149         /*
150          * now see if this is overridden by configuration
151          */

152
153         logWhenFound = rsvc.getBoolean( RuntimeConstants.RESOURCE_MANAGER_LOGWHENFOUND, true );
154
155         /*
156          * now, is a global cache specified?
157          */

158          
159         String JavaDoc claz = rsvc.getString( RuntimeConstants.RESOURCE_MANAGER_CACHE_CLASS );
160         
161         Object JavaDoc o = null;
162         
163         if ( claz != null && claz.length() > 0 )
164         {
165             try
166             {
167                o = Class.forName( claz ).newInstance();
168             }
169             catch (ClassNotFoundException JavaDoc cnfe )
170             {
171                 String JavaDoc err = "The specified class for ResourceCache ("
172                     + claz
173                     + ") does not exist (or is not accessible to the current classlaoder).";
174                  rsvc.error( err );
175                  
176                  o = null;
177             }
178             
179             if (!(o instanceof ResourceCache) )
180             {
181                 String JavaDoc err = "The specified class for ResourceCache ("
182                     + claz
183                     + ") does not implement org.apache.runtime.resource.ResourceCache."
184                     + " ResourceManager. Using default ResourceCache implementation.";
185                     
186                 rsvc.error( err);
187                 
188                 o = null;
189             }
190         }
191         
192         /*
193          * if we didn't get through that, just use the default.
194          */

195          
196         if ( o == null)
197             o = new ResourceCacheImpl();
198             
199          globalCache = (ResourceCache) o;
200             
201          globalCache.initialize( rsvc );
202
203          rsvc.info("Default ResourceManager initialization complete.");
204
205         }
206
207     /**
208      * This will produce a List of Hashtables, each
209      * hashtable contains the intialization info for
210      * a particular resource loader. This Hastable
211      * will be passed in when initializing the
212      * the template loader.
213      */

214     private void assembleResourceLoaderInitializers()
215     {
216         if (resourceLoaderInitializersActive)
217         {
218             return;
219         }
220
221         Vector JavaDoc resourceLoaderNames =
222             rsvc.getConfiguration().getVector(RuntimeConstants.RESOURCE_LOADER);
223
224         for (int i = 0; i < resourceLoaderNames.size(); i++)
225         {
226             /*
227              * The loader id might look something like the following:
228              *
229              * file.resource.loader
230              *
231              * The loader id is the prefix used for all properties
232              * pertaining to a particular loader.
233              */

234             String JavaDoc loaderID =
235                 resourceLoaderNames.get(i) + "." + RuntimeConstants.RESOURCE_LOADER;
236
237             ExtendedProperties loaderConfiguration =
238                 rsvc.getConfiguration().subset(loaderID);
239
240             /*
241              * we can't really count on ExtendedProperties to give us an empty set
242              */

243
244             if ( loaderConfiguration == null)
245             {
246                 rsvc.warn("ResourceManager : No configuration information for resource loader named '"
247                           + resourceLoaderNames.get(i) + "'. Skipping.");
248                 continue;
249             }
250
251             /*
252              * add the loader name token to the initializer if we need it
253              * for reference later. We can't count on the user to fill
254              * in the 'name' field
255              */

256
257             loaderConfiguration.setProperty( RESOURCE_LOADER_IDENTIFIER, resourceLoaderNames.get(i));
258
259             /*
260              * Add resources to the list of resource loader
261              * initializers.
262              */

263             sourceInitializerList.add(loaderConfiguration);
264         }
265         
266         resourceLoaderInitializersActive = true;
267     }
268
269     /**
270      * Gets the named resource. Returned class type corresponds to specified type
271      * (i.e. <code>Template</code> to <code>RESOURCE_TEMPLATE</code>).
272      *
273      * @param resourceName The name of the resource to retrieve.
274      * @param resourceType The type of resource (<code>RESOURCE_TEMPLATE</code>,
275      * <code>RESOURCE_CONTENT</code>, etc.).
276      * @param encoding The character encoding to use.
277      * @return Resource with the template parsed and ready.
278      * @throws ResourceNotFoundException if template not found
279      * from any available source.
280      * @throws ParseErrorException if template cannot be parsed due
281      * to syntax (or other) error.
282      * @throws Exception if a problem in parse
283      */

284     public Resource getResource(String JavaDoc resourceName, int resourceType, String JavaDoc encoding )
285         throws ResourceNotFoundException, ParseErrorException, Exception JavaDoc
286     {
287         /*
288          * Check to see if the resource was placed in the cache.
289          * If it was placed in the cache then we will use
290          * the cached version of the resource. If not we
291          * will load it.
292          */

293         
294         Resource resource = globalCache.get(resourceName);
295
296         if( resource != null)
297         {
298             /*
299              * refresh the resource
300              */

301              
302             try
303             {
304                 refreshResource( resource, encoding );
305             }
306             catch( ResourceNotFoundException rnfe )
307             {
308                 /*
309                  * something exceptional happened to that resource
310                  * this could be on purpose,
311                  * so clear the cache and try again
312                  */

313                  
314                  globalCache.remove( resourceName );
315      
316                  return getResource( resourceName, resourceType, encoding );
317             }
318             catch( ParseErrorException pee )
319             {
320                 rsvc.error(
321                     "ResourceManager.getResource() exception: " + pee);
322                 
323                 throw pee;
324             }
325             catch( Exception JavaDoc eee )
326             {
327                 rsvc.error(
328                     "ResourceManager.getResource() exception: " + eee);
329                 
330                 throw eee;
331             }
332         }
333         else
334         {
335             try
336             {
337                 /*
338                  * it's not in the cache, so load it.
339                  */

340
341                 resource = loadResource( resourceName, resourceType, encoding );
342                       
343                 if (resource.getResourceLoader().isCachingOn())
344                 {
345                     globalCache.put(resourceName, resource);
346                 }
347             }
348             catch( ResourceNotFoundException rnfe2 )
349             {
350                 rsvc.error(
351                     "ResourceManager : unable to find resource '" + resourceName +
352                         "' in any resource loader.");
353                 
354                 throw rnfe2;
355             }
356             catch( ParseErrorException pee )
357             {
358                 rsvc.error(
359                     "ResourceManager.getResource() parse exception: " + pee);
360                 
361                 throw pee;
362             }
363             catch( Exception JavaDoc ee )
364             {
365                 rsvc.error(
366                     "ResourceManager.getResource() exception new: " + ee);
367
368                 throw ee;
369             }
370         }
371
372         return resource;
373     }
374     
375     /**
376      * Loads a resource from the current set of resource loaders
377      *
378      * @param resourceName The name of the resource to retrieve.
379      * @param resourceType The type of resource (<code>RESOURCE_TEMPLATE</code>,
380      * <code>RESOURCE_CONTENT</code>, etc.).
381      * @param encoding The character encoding to use.
382      * @return Resource with the template parsed and ready.
383      * @throws ResourceNotFoundException if template not found
384      * from any available source.
385      * @throws ParseErrorException if template cannot be parsed due
386      * to syntax (or other) error.
387      * @throws Exception if a problem in parse
388      */

389     protected Resource loadResource(String JavaDoc resourceName, int resourceType, String JavaDoc encoding )
390         throws ResourceNotFoundException, ParseErrorException, Exception JavaDoc
391     {
392         Resource resource = ResourceFactory.getResource(resourceName, resourceType);
393                 
394         resource.setRuntimeServices( rsvc );
395
396         resource.setName( resourceName );
397         resource.setEncoding( encoding );
398                 
399         /*
400          * Now we have to try to find the appropriate
401          * loader for this resource. We have to cycle through
402          * the list of available resource loaders and see
403          * which one gives us a stream that we can use to
404          * make a resource with.
405          */

406
407         long howOldItWas = 0; // Initialize to avoid warnings
408

409         ResourceLoader resourceLoader = null;
410
411         for (int i = 0; i < resourceLoaders.size(); i++)
412         {
413             resourceLoader = (ResourceLoader) resourceLoaders.get(i);
414             resource.setResourceLoader(resourceLoader);
415             
416             /*
417              * catch the ResourceNotFound exception
418              * as that is ok in our new multi-loader environment
419              */

420
421             try
422             {
423                 if (resource.process())
424                 {
425                      /*
426                       * FIXME (gmj)
427                       * moved in here - technically still
428                       * a problem - but the resource needs to be
429                       * processed before the loader can figure
430                       * it out due to to the new
431                       * multi-path support - will revisit and fix
432                       */

433
434                      if ( logWhenFound )
435                      {
436                          rsvc.info("ResourceManager : found " + resourceName +
437                                       " with loader " + resourceLoader.getClassName() );
438                      }
439    
440                      howOldItWas = resourceLoader.getLastModified( resource );
441                      break;
442                  }
443             }
444             catch( ResourceNotFoundException rnfe )
445             {
446                 /*
447                  * that's ok - it's possible to fail in
448                  * multi-loader environment
449                  */

450             }
451         }
452                 
453         /*
454          * Return null if we can't find a resource.
455          */

456         if (resource.getData() == null)
457         {
458             throw new ResourceNotFoundException(
459                 "Unable to find resource '" + resourceName + "'");
460         }
461
462         /*
463          * some final cleanup
464          */

465          
466         resource.setLastModified( howOldItWas );
467          
468         resource.setModificationCheckInterval(
469             resourceLoader.getModificationCheckInterval());
470         
471         resource.touch();
472     
473         return resource;
474     }
475     
476     /**
477      * Takes an existing resource, and 'refreshes' it. This
478      * generally means that the source of the resource is checked
479      * for changes according to some cache/check algorithm
480      * and if the resource changed, then the resource data is
481      * reloaded and re-parsed.
482      *
483      * @param resource resource to refresh
484      *
485      * @throws ResourceNotFoundException if template not found
486      * from current source for this Resource
487      * @throws ParseErrorException if template cannot be parsed due
488      * to syntax (or other) error.
489      * @throws Exception if a problem in parse
490      */

491     protected void refreshResource( Resource resource, String JavaDoc encoding )
492         throws ResourceNotFoundException, ParseErrorException, Exception JavaDoc
493     {
494         /*
495          * The resource knows whether it needs to be checked
496          * or not, and the resource's loader can check to
497          * see if the source has been modified. If both
498          * these conditions are true then we must reload
499          * the input stream and parse it to make a new
500          * AST for the resource.
501          */

502         if ( resource.requiresChecking() )
503         {
504             /*
505              * touch() the resource to reset the counters
506              */

507
508             resource.touch();
509             
510             if( resource.isSourceModified() )
511             {
512                 /*
513                  * now check encoding info. It's possible that the newly declared
514                  * encoding is different than the encoding already in the resource
515                  * this strikes me as bad...
516                  */

517                 
518                 if (!resource.getEncoding().equals( encoding ) )
519                 {
520                     rsvc.error("Declared encoding for template '" + resource.getName()
521                                   + "' is different on reload. Old = '" + resource.getEncoding()
522                                   + "' New = '" + encoding );
523     
524                     resource.setEncoding( encoding );
525                 }
526
527                 /*
528                  * read how old the resource is _before_
529                  * processing (=>reading) it
530                  */

531                 long howOldItWas = resource.getResourceLoader().getLastModified( resource );
532
533                 /*
534                  * read in the fresh stream and parse
535                  */

536
537                 resource.process();
538
539                 /*
540                  * now set the modification info and reset
541                  * the modification check counters
542                  */

543                 
544                 resource.setLastModified( howOldItWas );
545             }
546         }
547     }
548
549      /**
550      * Gets the named resource. Returned class type corresponds to specified type
551      * (i.e. <code>Template</code> to <code>RESOURCE_TEMPLATE</code>).
552      *
553      * @param resourceName The name of the resource to retrieve.
554      * @param resourceType The type of resource (<code>RESOURCE_TEMPLATE</code>,
555      * <code>RESOURCE_CONTENT</code>, etc.).
556      * @return Resource with the template parsed and ready.
557      * @throws ResourceNotFoundException if template not found
558      * from any available source.
559      * @throws ParseErrorException if template cannot be parsed due
560      * to syntax (or other) error.
561      * @throws Exception if a problem in parse
562      *
563      * @deprecated Use
564      * {@link #getResource(String resourceName, int resourceType,
565      * String encoding )}
566      */

567     public Resource getResource(String JavaDoc resourceName, int resourceType )
568         throws ResourceNotFoundException, ParseErrorException, Exception JavaDoc
569     {
570         return getResource( resourceName, resourceType, RuntimeConstants.ENCODING_DEFAULT);
571     }
572
573     /**
574      * Determines is a template exists, and returns name of the loader that
575      * provides it. This is a slightly less hokey way to support
576      * the Velocity.templateExists() utility method, which was broken
577      * when per-template encoding was introduced. We can revisit this.
578      *
579      * @param resourceName Name of template or content resource
580      * @return class name of loader than can provide it
581      */

582     public String JavaDoc getLoaderNameForResource(String JavaDoc resourceName )
583     {
584         ResourceLoader resourceLoader = null;
585        
586         /*
587          * loop through our loaders...
588          */

589         for (int i = 0; i < resourceLoaders.size(); i++)
590         {
591             resourceLoader = (ResourceLoader) resourceLoaders.get(i);
592
593             InputStream JavaDoc is = null;
594
595             /*
596              * if we find one that can provide the resource,
597              * return the name of the loaders's Class
598              */

599             try
600             {
601                 is=resourceLoader.getResourceStream( resourceName );
602                
603                 if( is != null)
604                 {
605                     return resourceLoader.getClass().toString();
606                 }
607             }
608             catch( ResourceNotFoundException e)
609             {
610                 /*
611                  * this isn't a problem. keep going
612                  */

613             }
614             finally
615             {
616                 /*
617                  * if we did find one, clean up because we were
618                  * returned an open stream
619                  */

620                 if (is != null)
621                 {
622                     try
623                     {
624                         is.close();
625                     }
626                     catch( IOException JavaDoc ioe)
627                     {
628                     }
629                 }
630             }
631         }
632
633         return null;
634     }
635 }
636
637
638
Popular Tags