View Javadoc

1   /*
2    * Copyright 2000-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.jetspeed.services.resources;
18  
19  // Java Core Classes
20  import java.io.File;
21  import java.io.IOException;
22  import java.util.Enumeration;
23  import java.util.Hashtable;
24  import java.util.Vector;
25  import javax.servlet.ServletConfig;
26  import javax.servlet.ServletContext;
27  
28  // Turbine stuff.
29  import org.apache.commons.configuration.Configuration;
30  import org.apache.turbine.services.resources.ResourceService;
31  import org.apache.turbine.services.resources.TurbineResourceService;
32  import org.apache.turbine.services.TurbineServices;
33  import org.apache.turbine.services.InitializationException;
34  
35  // Jetspeed classes
36  import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
37  import org.apache.jetspeed.services.logging.JetspeedLogger;
38  
39  /***
40   * <p>This implementation of the <code>resourcesService</code> relies
41   * on an external properties file for storing the configuration keys
42   * and values</p>
43   *
44   * <P>In order to be compatible with legacy applications, this implementation
45   * kept a static method for initializing the service, so it's still possible
46   * to write the following code:
47   * <p><code>
48   * TurbineResourceService.setPropertiesName("d:/conf/Turbine.properties");
49   * Vector myVar = TurbineResources.getVector("myvar");
50   * </code></p>
51   *
52   * <p>This implementation allows the use of several pre-defined variables within
53   *    the configuration file. The variables are identified by the following
54   *    sequence of tokens: ${<varname>}. Varname is always folded to lowercase.</p>
55   *  <P>The predefined variables are:
56   *    <ul>
57   *       <li>webapp.dir: base directory for the web application
58   *       <li>jvm.dir: JVM startup directory
59   *     </ul>
60   *  </p>
61   *  <p>The init parameters of the servlet are also imported as default variables.
62   *     They may override the previously defined default variables
63   *  </p>
64   *
65   * @author <a href="mailto:raphael@apache.org">Raphaël Luta</a>
66   * @version $Id: VariableResourcesService.java,v 1.15 2004/02/23 03:29:53 jford Exp $
67   */
68  public class VariableResourcesService extends TurbineResourceService
69  {
70      /***
71       * Static initialization of the logger for this class
72       */    
73      private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(VariableResourcesService.class.getName());
74      
75      public static final String WEBAPP_DIR="webapp.dir";
76      public static final String WEB_DIR="web.dir";
77      public static final String JVM_DIR="jvm.dir";
78      public static final String START_TOKEN="${";
79      public static final String END_TOKEN="}";
80      
81      /*** The container for the generic resources. */
82      private Hashtable variables = null;
83  
84      /*** The container for the generic resources. */
85      private Hashtable strings = null;
86      private Hashtable vectors = null;
87      private Hashtable arrays = null;
88  
89  
90      /***
91       * Late init. Don't return control until early init says we're done.
92       */
93      public void init( )
94      {
95          while( !getInit() ) {
96              try {
97                  Thread.sleep(500);
98              } catch (InterruptedException ie ) {
99                  logger.info("VariableResources service: Waiting for init()..." );
100             }
101         }
102     }
103 
104 
105     /***
106      * This method is called when the Service is initialized
107      *
108      * @param config a ServletConfig object
109      */
110     public synchronized void init(ServletConfig config) throws InitializationException
111     {        
112         if (getInit()) return;
113         String props = config.getInitParameter(TurbineServices.PROPERTIES_PATH_KEY);
114 
115         variables = new Hashtable();
116         strings = new Hashtable();
117         vectors = new Hashtable();
118         arrays = new Hashtable();
119         initVariables(config);
120 
121         super.init(config);
122     }
123 
124     /***
125      * Initializer method that sets up the generic resources.
126      *
127      * @param confs A Configurations object.
128      */
129     private void initVariables(ServletConfig config)
130     {
131         ServletContext ctxt = config.getServletContext();
132         
133         String path = ctxt.getRealPath("/");
134         
135         // define web app dir
136         if (path != null) {
137             variables.put(WEBAPP_DIR, normalizePath(path) );
138         }
139         
140         // FIXME. the following code blocks on Tomcat 
141         // when loaded on startup
142         /*
143         path = ctxt.getContext("/").getRealPath("/");
144         if (path != null ) {
145             variables.put(WEB_DIR, normalizePath(path) );
146         }
147         */
148 
149         // define JVM app dir
150         try {
151             path = new File(".").getCanonicalPath();
152             if (path != null) {
153                 variables.put(JVM_DIR, normalizePath(path) );
154             }
155         } catch (IOException e) {
156             //very unlikely that the JVM can't 
157             //resolve its path
158             //But logging it anyway...
159             logger.error( "Exception define JVM app dir", e );
160         }
161 
162         // load servlet init parameters as variables, they may override
163         // the previously defined variables. All param names are folded
164         // to lower case
165         
166         Enumeration en = config.getInitParameterNames();
167         while( en.hasMoreElements() ) {
168             String paramName = (String)en.nextElement();
169             String paramValue = config.getInitParameter(paramName);
170             variables.put(paramName.toLowerCase(),paramValue);
171         }
172             
173     }
174 
175     private static String normalizePath(String path) {
176         // change all separators to forward
177         // slashes
178         if (File.separatorChar != '/') {
179             path = path.replace(File.separatorChar,'/');
180         }
181         
182         // remove any trailing slash
183         if (path.endsWith("/")) {
184             path = path.substring(0,path.length()-1);
185         }
186         
187         return path;
188     }
189     
190     protected void setVariables(Hashtable vars)
191     {
192         synchronized (this)
193         {
194             this.variables = vars;
195             this.strings = new Hashtable();
196             this.vectors = new Hashtable();
197             this.arrays = new Hashtable();
198         }
199     }
200     
201     protected String substituteString( String base ) {
202         if (base == null) return null;
203         
204         int begin = -1;
205         int end = -1;
206         int prec = 0-END_TOKEN.length();
207         String var = null;
208         StringBuffer result = new StringBuffer();
209         
210         // FIXME: we should probably allow the escaping of the start token
211         while ( ((begin=base.indexOf(START_TOKEN,prec+END_TOKEN.length()))>-1)
212                 && ((end=base.indexOf(END_TOKEN,begin))>-1) ) {
213             
214             result.append(base.substring(prec+END_TOKEN.length(),begin));
215             var = base.substring(begin+START_TOKEN.length(),end);
216             if (variables.get(var)!=null) {
217                 result.append(variables.get(var));
218             }
219             prec=end;
220         }
221         result.append(base.substring(prec+END_TOKEN.length(),base.length()));
222         
223         return result.toString();
224     }
225         
226         
227     /***
228      * The purpose of this method is to get the configuration resource
229      * with the given name as a string.
230      *
231      * @param name The resource name.
232      * @return The value of the resource as a string.
233      */
234     public String getString(String name)
235     {
236         String std = (String)strings.get(name);
237         
238         if (std == null) {
239             std = substituteString(super.getString(name));
240             if (std != null) strings.put(name,std);
241         }
242         
243         return std;
244     }
245 
246     /***
247      * The purpose of this method is to get the configuration resource
248      * with the given name as a string, or a default value.
249      *
250      * @param name The resource name.
251      * @param def The default value of the resource.
252      * @return The value of the resource as a string.
253      */
254     public String getString(String name,
255                                    String def)
256     {
257         String std = getString(name);
258         
259         if (std == null)
260             std = substituteString(def);
261     
262         return std;
263     }
264 
265     /***
266      * The purpose of this method is to get the configuration resource
267      * with the given name as a string array.
268      *
269      * @param name The resource name.
270      * @return The value of the resource as a string array.
271      */
272     public String[] getStringArray(String name)
273     {
274         String[] std = (String[])arrays.get(name);
275         if (std==null) {
276             std = super.getStringArray(name);
277             if (std != null) {
278                 for(int i=0;i<std.length;i++) {
279                     std[i]=substituteString(std[i]);
280                 }
281                 arrays.put(name,std);
282             }
283         }
284         
285         return std;
286     }
287 
288     /***
289      * The purpose of this method is to get the configuration resource
290      * with the given name as a vector.
291      *
292      * @param name The resource name.
293      * @return The value of the resource as a vector.
294      */
295     public Vector getVector(String name)
296     {
297         Vector std = (Vector)vectors.get(name);
298         
299         if (std==null) {
300             std = super.getVector(name);
301             if (std != null) {
302                 Vector newstd = new Vector();
303                 Enumeration en = std.elements();
304                 while (en.hasMoreElements()) {
305                     newstd.addElement(substituteString((String)en.nextElement()));
306                 }
307                 std = newstd;
308                 vectors.put(name,std);
309             }
310         }
311         
312         return std;
313     }
314 
315     /***
316      * The purpose of this method is to get the configuration resource
317      * with the given name as a vector, or a default value.
318      *
319      * @param name The resource name.
320      * @param def The default value of the resource.
321      * @return The value of the resource as a vector.
322      */
323     public Vector getVector(String name,
324                                    Vector def)
325     {
326         Vector std = getVector(name); 
327         if ( std == null) {
328             if (def != null) {
329                 std = new Vector();
330                 Enumeration en = def.elements();
331                 while (en.hasMoreElements()) {
332                     std.addElement(substituteString((String)en.nextElement()));
333                 }
334             }
335         }
336 
337         return std;
338     }
339 
340     /***
341      * The purpose of this method is to extract a subset of configuraton
342      * resources sharing a common name prefix. The prefix is stripped
343      * from the names of the resulting resources.
344      *
345      * @param prefix the common name prefix
346      * @return A ResourceService providing the subset of configuration.
347      */
348     public ResourceService getResources(String prefix)
349     {
350         Configuration config = getConfiguration().subset(prefix);
351         
352         if (config == null)
353         {
354             return null;
355         }
356         
357         VariableResourcesService res = new VariableResourcesService();
358         try 
359         { 
360             res.init(config); 
361         } 
362         catch (Exception e) 
363         {
364             logger.error( "Unable to init resources for " + prefix, e );
365         }
366         res.setVariables(this.variables);
367         return (ResourceService)res;
368     }
369 
370 
371 }