/* * Copyright 2000-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jetspeed.services.resources; // Java Core Classes import java.io.File; import java.io.IOException; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; // Turbine stuff. import org.apache.commons.configuration.Configuration; import org.apache.turbine.services.resources.ResourceService; import org.apache.turbine.services.resources.TurbineResourceService; import org.apache.turbine.services.TurbineServices; import org.apache.turbine.services.InitializationException; // Jetspeed classes import org.apache.jetspeed.services.logging.JetspeedLogFactoryService; import org.apache.jetspeed.services.logging.JetspeedLogger; /** * <p>This implementation of the <code>resourcesService</code> relies * on an external properties file for storing the configuration keys * and values</p> * * <P>In order to be compatible with legacy applications, this implementation * kept a static method for initializing the service, so it's still possible * to write the following code: * <p><code> * TurbineResourceService.setPropertiesName("d:/conf/Turbine.properties"); * Vector myVar = TurbineResources.getVector("myvar"); * </code></p> * * <p>This implementation allows the use of several pre-defined variables within * the configuration file. The variables are identified by the following * sequence of tokens: ${<varname>}. Varname is always folded to lowercase.</p> * <P>The predefined variables are: * <ul> * <li>webapp.dir: base directory for the web application * <li>jvm.dir: JVM startup directory * </ul> * </p> * <p>The init parameters of the servlet are also imported as default variables. * They may override the previously defined default variables * </p> * * @author <a href="mailto:raphael@apache.org">Rapha�l Luta</a> * @version $Id: VariableResourcesService.java,v 1.15 2004/02/23 03:29:53 jford Exp $ */ public class VariableResourcesService extends TurbineResourceService { /** * Static initialization of the logger for this class */ private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(VariableResourcesService.class.getName()); public static final String WEBAPP_DIR="webapp.dir"; public static final String WEB_DIR="web.dir"; public static final String JVM_DIR="jvm.dir"; public static final String START_TOKEN="${"; public static final String END_TOKEN="}"; /** The container for the generic resources. */ private Hashtable variables = null; /** The container for the generic resources. */ private Hashtable strings = null; private Hashtable vectors = null; private Hashtable arrays = null; /** * Late init. Don't return control until early init says we're done. */ public void init( ) { while( !getInit() ) { try { Thread.sleep(500); } catch (InterruptedException ie ) { logger.info("VariableResources service: Waiting for init()..." ); } } } /** * This method is called when the Service is initialized * * @param config a ServletConfig object */ public synchronized void init(ServletConfig config) throws InitializationException { if (getInit()) return; String props = config.getInitParameter(TurbineServices.PROPERTIES_PATH_KEY); variables = new Hashtable(); strings = new Hashtable(); vectors = new Hashtable(); arrays = new Hashtable(); initVariables(config); super.init(config); } /** * Initializer method that sets up the generic resources. * * @param confs A Configurations object. */ private void initVariables(ServletConfig config) { ServletContext ctxt = config.getServletContext(); String path = ctxt.getRealPath("/"); // define web app dir if (path != null) { variables.put(WEBAPP_DIR, normalizePath(path) ); } // FIXME. the following code blocks on Tomcat // when loaded on startup /* path = ctxt.getContext("/").getRealPath("/"); if (path != null ) { variables.put(WEB_DIR, normalizePath(path) ); } */ // define JVM app dir try { path = new File(".").getCanonicalPath(); if (path != null) { variables.put(JVM_DIR, normalizePath(path) ); } } catch (IOException e) { //very unlikely that the JVM can't //resolve its path //But logging it anyway... logger.error( "Exception define JVM app dir", e ); } // load servlet init parameters as variables, they may override // the previously defined variables. All param names are folded // to lower case Enumeration en = config.getInitParameterNames(); while( en.hasMoreElements() ) { String paramName = (String)en.nextElement(); String paramValue = config.getInitParameter(paramName); variables.put(paramName.toLowerCase(),paramValue); } } private static String normalizePath(String path) { // change all separators to forward // slashes if (File.separatorChar != '/') { path = path.replace(File.separatorChar,'/'); } // remove any trailing slash if (path.endsWith("/")) { path = path.substring(0,path.length()-1); } return path; } protected void setVariables(Hashtable vars) { synchronized (this) { this.variables = vars; this.strings = new Hashtable(); this.vectors = new Hashtable(); this.arrays = new Hashtable(); } } protected String substituteString( String base ) { if (base == null) return null; int begin = -1; int end = -1; int prec = 0-END_TOKEN.length(); String var = null; StringBuffer result = new StringBuffer(); // FIXME: we should probably allow the escaping of the start token while ( ((begin=base.indexOf(START_TOKEN,prec+END_TOKEN.length()))>-1) && ((end=base.indexOf(END_TOKEN,begin))>-1) ) { result.append(base.substring(prec+END_TOKEN.length(),begin)); var = base.substring(begin+START_TOKEN.length(),end); if (variables.get(var)!=null) { result.append(variables.get(var)); } prec=end; } result.append(base.substring(prec+END_TOKEN.length(),base.length())); return result.toString(); } /** * The purpose of this method is to get the configuration resource * with the given name as a string. * * @param name The resource name. * @return The value of the resource as a string. */ public String getString(String name) { String std = (String)strings.get(name); if (std == null) { std = substituteString(super.getString(name)); if (std != null) strings.put(name,std); } return std; } /** * The purpose of this method is to get the configuration resource * with the given name as a string, or a default value. * * @param name The resource name. * @param def The default value of the resource. * @return The value of the resource as a string. */ public String getString(String name, String def) { String std = getString(name); if (std == null) std = substituteString(def); return std; } /** * The purpose of this method is to get the configuration resource * with the given name as a string array. * * @param name The resource name. * @return The value of the resource as a string array. */ public String[] getStringArray(String name) { String[] std = (String[])arrays.get(name); if (std==null) { std = super.getStringArray(name); if (std != null) { for(int i=0;i<std.length;i++) { std[i]=substituteString(std[i]); } arrays.put(name,std); } } return std; } /** * The purpose of this method is to get the configuration resource * with the given name as a vector. * * @param name The resource name. * @return The value of the resource as a vector. */ public Vector getVector(String name) { Vector std = (Vector)vectors.get(name); if (std==null) { std = super.getVector(name); if (std != null) { Vector newstd = new Vector(); Enumeration en = std.elements(); while (en.hasMoreElements()) { newstd.addElement(substituteString((String)en.nextElement())); } std = newstd; vectors.put(name,std); } } return std; } /** * The purpose of this method is to get the configuration resource * with the given name as a vector, or a default value. * * @param name The resource name. * @param def The default value of the resource. * @return The value of the resource as a vector. */ public Vector getVector(String name, Vector def) { Vector std = getVector(name); if ( std == null) { if (def != null) { std = new Vector(); Enumeration en = def.elements(); while (en.hasMoreElements()) { std.addElement(substituteString((String)en.nextElement())); } } } return std; } /** * The purpose of this method is to extract a subset of configuraton * resources sharing a common name prefix. The prefix is stripped * from the names of the resulting resources. * * @param prefix the common name prefix * @return A ResourceService providing the subset of configuration. */ public ResourceService getResources(String prefix) { Configuration config = getConfiguration().subset(prefix); if (config == null) { return null; } VariableResourcesService res = new VariableResourcesService(); try { res.init(config); } catch (Exception e) { logger.error( "Unable to init resources for " + prefix, e ); } res.setVariables(this.variables); return (ResourceService)res; } }