001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.daemon.support; 019 020 import java.io.FileInputStream; 021 import java.io.FileNotFoundException; 022 import java.io.IOException; 023 import java.util.ArrayList; 024 import java.util.Properties; 025 import java.text.ParseException; 026 027 /** 028 * Used by jsvc for Daemon configuration. 029 * <p> 030 * Configuration is read from properties file. 031 * If no properties file is given the <code>daemon.properties</code> 032 * is used from the current directory. 033 * </p> 034 * <p> 035 * The properties file can have property values expanded at runtime 036 * by using System properties or execution environment. The part 037 * of the property value between <code>${</code> and <code>}</code> 038 * will be used as System property or environment key. If found then 039 * the entire <code>${foo}</code> will be replaced by the value of 040 * either system property or environment variable named <code>foo</code>. 041 * </p> 042 * <p> 043 * If no variable is found the <code>${foo}</code> will be passed as is. 044 * In case of <code>$${foo}</code> this will be unescaped and resulting 045 * value will be <code>${foo}</code>. 046 * </p> 047 * 048 * @version 1.0 <i>(SVN $Revision: 925053 $)</i> 049 * @author Mladen Turk 050 */ 051 public final class DaemonConfiguration 052 { 053 /** 054 * Default configuration file name. 055 */ 056 protected final static String DEFAULT_CONFIG = "daemon.properties"; 057 /** 058 * Property prefix 059 */ 060 protected final static String PREFIX = "daemon."; 061 private final static String BTOKEN = "${"; 062 private final static String ETOKEN = "}"; 063 064 065 private final Properties configurationProperties; 066 private final Properties systemProperties; 067 068 /** 069 * Default constructor 070 */ 071 public DaemonConfiguration() 072 { 073 configurationProperties = new Properties(); 074 systemProperties = System.getProperties(); 075 } 076 077 /** 078 * Load the configuration properties file. 079 * 080 * @param fileName The properties file to load. 081 * @return <code>true</code> if the file was loaded. 082 */ 083 public boolean load(String fileName) 084 { 085 boolean ok = false; 086 try { 087 if (fileName == null) 088 fileName = DEFAULT_CONFIG; 089 FileInputStream file = new FileInputStream(fileName); 090 configurationProperties.clear(); 091 configurationProperties.load(file); 092 ok = true; 093 } 094 catch (FileNotFoundException ex) { 095 // fileName does not exist 096 } 097 catch (IOException ex) { 098 // Error reading properties file 099 } 100 return ok; 101 } 102 103 private String expandProperty(String propValue) 104 throws ParseException 105 { 106 StringBuffer expanded; 107 int btoken; 108 int ctoken = 0; 109 110 if (propValue == null) 111 return null; 112 expanded = new StringBuffer(); 113 btoken = propValue.indexOf(BTOKEN); 114 while (btoken != -1) { 115 if (btoken > 0 && propValue.charAt(btoken - 1) == BTOKEN.charAt(0)) { 116 // Skip and unquote. 117 expanded.append(propValue.substring(ctoken, btoken)); 118 ctoken = btoken + 1; 119 btoken = propValue.indexOf(BTOKEN, btoken + BTOKEN.length()); 120 continue; 121 } 122 int etoken = propValue.indexOf(ETOKEN, btoken); 123 if (etoken != -1) { 124 String variable = propValue.substring(btoken + BTOKEN.length(), etoken); 125 String sysvalue = systemProperties.getProperty(variable); 126 if (sysvalue == null) { 127 // Try with the environment if there was no 128 // property by that name. 129 sysvalue = System.getenv(variable); 130 } 131 if (sysvalue != null) { 132 String strtoken = propValue.substring(ctoken, btoken); 133 expanded.append(strtoken); 134 expanded.append(sysvalue); 135 ctoken = etoken + ETOKEN.length(); 136 } 137 } 138 else { 139 // We have "${" without "}" 140 throw new ParseException("Error while looking for teminating '" + 141 ETOKEN + "'", btoken); 142 } 143 btoken = propValue.indexOf(BTOKEN, etoken + ETOKEN.length()); 144 } 145 // Add what's left. 146 expanded.append(propValue.substring(ctoken, propValue.length())); 147 return expanded.toString(); 148 } 149 150 /** 151 * Get the configuration property. 152 * @param name The name of the property to get. 153 * 154 * @throws ParseException if the property is wrongly formatted. 155 */ 156 public String getProperty(String name) 157 throws ParseException 158 { 159 if (name == null) 160 return null; 161 else 162 return expandProperty(configurationProperties.getProperty(PREFIX + name)); 163 } 164 165 /** 166 * Get the configuration property array. 167 * <p> 168 * Property array is constructed form the lsit of properties 169 * which end with <code>[index]</code> 170 * </p> 171 * <pre> 172 * daemon.arg[0] = argument 1 173 * daemon.arg[1] = argument 2 174 * daemon.arg[2] = argument 3 175 * </pre> 176 * @param name The name of the property array to get. 177 * 178 * @throws ParseException if the property is wrongly formatted. 179 */ 180 public String[] getPropertyArray(String name) 181 throws ParseException 182 { 183 ArrayList list = new ArrayList(); 184 String args; 185 186 // Load daemon.arg[0] ... daemon.arg[n] into the String array. 187 // 188 while ((args = getProperty(name + "[" + list.size() + "]")) != null) { 189 list.add(args); 190 } 191 return (String[])list.toArray(new String[list.size()]); 192 } 193 194 } 195