EMMA Coverage Report (generated Tue May 18 22:13:27 CDT 2004)
[all classes][org.apache.velocity.runtime.resource]

COVERAGE SUMMARY FOR SOURCE FILE [ResourceManagerImpl.java]

nameclass, %method, %block, %line, %
ResourceManagerImpl.java100% (1/1)62%  (5/8)54%  (312/574)55%  (71/130)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ResourceManagerImpl100% (1/1)62%  (5/8)54%  (312/574)55%  (71/130)
getLoaderNameForResource (String): String 0%   (0/1)0%   (0/51)0%   (0/16)
getResource (String, int): Resource 0%   (0/1)0%   (0/6)0%   (0/1)
refreshResource (Resource, String): void 0%   (0/1)0%   (0/49)0%   (0/10)
getResource (String, int, String): Resource 100% (1/1)31%  (36/115)33%  (9/27)
initialize (RuntimeServices): void 100% (1/1)63%  (101/160)70%  (23/33)
assembleResourceLoaderInitializers (): void 100% (1/1)76%  (53/70)77%  (10/13)
loadResource (String, int, String): Resource 100% (1/1)99%  (92/93)95%  (21/22)
ResourceManagerImpl (): void 100% (1/1)100% (30/30)100% (8/8)

1package 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 
19import java.util.ArrayList;
20import java.util.Hashtable;
21import java.util.Vector;
22 
23import java.io.InputStream;
24import java.io.IOException;
25 
26import org.apache.velocity.runtime.RuntimeServices;
27import org.apache.velocity.runtime.RuntimeConstants;
28 
29import org.apache.velocity.runtime.resource.ResourceFactory;
30import org.apache.velocity.runtime.resource.loader.ResourceLoader;
31import org.apache.velocity.runtime.resource.loader.ResourceLoaderFactory;
32 
33import org.apache.velocity.exception.ResourceNotFoundException;
34import org.apache.velocity.exception.ParseErrorException;
35 
36import 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 */
47public 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 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 resourceLoaders = new ArrayList();
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 sourceInitializerList = new ArrayList();
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 sourceInitializerMap = new Hashtable();
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
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 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 claz = rsvc.getString( RuntimeConstants.RESOURCE_MANAGER_CACHE_CLASS );
160        
161        Object o = null;
162        
163        if ( claz != null && claz.length() > 0 )
164        {
165            try
166            {
167               o = Class.forName( claz ).newInstance();
168            }
169            catch (ClassNotFoundException cnfe )
170            {
171                String 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 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 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 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 resourceName, int resourceType, String encoding )
285        throws ResourceNotFoundException, ParseErrorException, Exception
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 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 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 resourceName, int resourceType, String encoding )
390        throws ResourceNotFoundException, ParseErrorException, Exception
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 encoding )
492        throws ResourceNotFoundException, ParseErrorException, Exception
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 resourceName, int resourceType  )
568        throws ResourceNotFoundException, ParseErrorException, Exception
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 getLoaderNameForResource(String 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 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 ioe)
627                    {
628                    }
629                }
630            }
631        }
632 
633        return null;
634    }
635}
636 
637 

[all classes][org.apache.velocity.runtime.resource]
EMMA 2.0.4015 (stable) (C) Vladimir Roubtsov