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