2
* Copyright 2003-2009 Terracotta, Inc.
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
8
* http://www.apache.org/licenses/LICENSE-2.0
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.
17
package net.sf.ehcache.config;
19
import net.sf.ehcache.CacheException;
20
import net.sf.ehcache.util.ClassLoaderUtil;
22
import javax.xml.parsers.SAXParser;
23
import javax.xml.parsers.SAXParserFactory;
24
import java.io.BufferedInputStream;
25
import java.io.ByteArrayInputStream;
27
import java.io.FileInputStream;
28
import java.io.IOException;
29
import java.io.InputStream;
30
import java.io.InputStreamReader;
31
import java.io.Reader;
33
import java.util.HashSet;
35
import java.util.logging.Level;
36
import java.util.logging.Logger;
37
import java.util.regex.Matcher;
38
import java.util.regex.Pattern;
41
* A utility class which configures beans from XML, using reflection.
44
* @version $Id: ConfigurationFactory.java 1012 2009-08-20 04:23:00Z gregluck $
46
public final class ConfigurationFactory {
48
private static final Logger LOG = Logger.getLogger(ConfigurationFactory.class.getName());
50
private static final String DEFAULT_CLASSPATH_CONFIGURATION_FILE = "/ehcache.xml";
51
private static final String FAILSAFE_CLASSPATH_CONFIGURATION_FILE = "/ehcache-failsafe.xml";
56
private ConfigurationFactory() {
61
* Configures a bean from an XML file.
63
public static Configuration parseConfiguration(final File file) throws CacheException {
65
throw new CacheException("Attempt to configure ehcache from null file.");
68
if (LOG.isLoggable(Level.FINE)) {
69
LOG.log(Level.FINE, "Configuring ehcache from file: " + file.toString());
71
Configuration configuration = null;
72
InputStream input = null;
74
input = new BufferedInputStream(new FileInputStream(file));
75
configuration = parseConfiguration(input);
76
} catch (Exception e) {
77
throw new CacheException("Error configuring from " + file + ". Initial cause was " + e.getMessage(), e);
83
} catch (IOException e) {
84
LOG.log(Level.SEVERE, "IOException while closing configuration input stream. Error was " + e.getMessage());
91
* Configures a bean from an XML file available as an URL.
93
public static Configuration parseConfiguration(final URL url) throws CacheException {
94
if (LOG.isLoggable(Level.FINE)) {
95
LOG.log(Level.FINE, "Configuring ehcache from URL: " + url);
97
Configuration configuration;
98
InputStream input = null;
100
input = url.openStream();
101
configuration = parseConfiguration(input);
102
} catch (Exception e) {
103
throw new CacheException("Error configuring from " + url + ". Initial cause was " + e.getMessage(), e);
109
} catch (IOException e) {
110
LOG.log(Level.SEVERE, "IOException while closing configuration input stream. Error was " + e.getMessage());
113
return configuration;
117
* Configures a bean from an XML file in the classpath.
119
public static Configuration parseConfiguration() throws CacheException {
120
ClassLoader standardClassloader = ClassLoaderUtil.getStandardClassLoader();
122
if (standardClassloader != null) {
123
url = standardClassloader.getResource(DEFAULT_CLASSPATH_CONFIGURATION_FILE);
126
url = ConfigurationFactory.class.getResource(DEFAULT_CLASSPATH_CONFIGURATION_FILE);
129
if (LOG.isLoggable(Level.FINE)) {
130
LOG.log(Level.FINE, "Configuring ehcache from ehcache.xml found in the classpath: " + url);
133
url = ConfigurationFactory.class.getResource(FAILSAFE_CLASSPATH_CONFIGURATION_FILE);
134
if (LOG.isLoggable(Level.WARNING)) {
135
LOG.log(Level.WARNING, "No configuration found. Configuring ehcache from ehcache-failsafe.xml "
136
+ " found in the classpath: " + url);
139
return parseConfiguration(url);
143
* Configures a bean from an XML input stream.
145
public static Configuration parseConfiguration(final InputStream inputStream) throws CacheException {
146
if (LOG.isLoggable(Level.FINE)) {
147
LOG.log(Level.FINE, "Configuring ehcache from InputStream");
150
Configuration configuration = new Configuration();
152
InputStream translatedInputStream = translateSystemProperties(inputStream);
153
final SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
154
final BeanHandler handler = new BeanHandler(configuration);
155
parser.parse(translatedInputStream, handler);
156
} catch (Exception e) {
157
throw new CacheException("Error configuring from input stream. Initial cause was " + e.getMessage(), e);
159
return configuration;
163
* Translates system properties which can be added as tokens to the config file using ${token} syntax.
165
* So, if the config file contains a character sequence "multicastGroupAddress=${multicastAddress}", and there is a system property
166
* multicastAddress=230.0.0.12 then the translated sequence becomes "multicastGroupAddress=230.0.0.12"
169
* @return a translated stream
171
private static InputStream translateSystemProperties(InputStream inputStream) throws IOException {
173
StringBuffer stringBuffer = new StringBuffer();
175
Reader reader = new InputStreamReader(inputStream, "UTF-8");
176
while ((c = reader.read()) != -1) {
177
stringBuffer.append((char) c);
179
String configuration = stringBuffer.toString();
181
Set tokens = extractPropertyTokens(configuration);
182
for (Object tokenObject : tokens) {
183
String token = (String) tokenObject;
184
String leftTrimmed = token.replaceAll("\\$\\{", "");
185
String trimmedToken = leftTrimmed.replaceAll("\\}", "");
187
String property = System.getProperty(trimmedToken);
188
if (property == null) {
189
if (LOG.isLoggable(Level.FINE)) {
190
LOG.log(Level.FINE, "Did not find a system property for the " + token +
191
" token specified in the configuration.Replacing with \"\"");
194
//replaceAll by default clobbers \ and $
195
String propertyWithQuotesProtected = Matcher.quoteReplacement(property);
196
configuration = configuration.replaceAll("\\$\\{" + trimmedToken + "\\}", propertyWithQuotesProtected);
197
if (LOG.isLoggable(Level.FINE)) {
198
LOG.log(Level.FINE, "Found system property value of " + property + " for the " + token +
199
" token specified in the configuration.");
203
return new ByteArrayInputStream(configuration.getBytes());
207
* Extracts properties of the form ${...}
209
* @param sourceDocument the source document
210
* @return a Set of properties. So, duplicates are only counted once.
212
static Set extractPropertyTokens(String sourceDocument) {
213
Set propertyTokens = new HashSet();
214
Pattern pattern = Pattern.compile("\\$\\{.+?\\}");
215
Matcher matcher = pattern.matcher(sourceDocument);
216
while (matcher.find()) {
217
String token = matcher.group();
218
propertyTokens.add(token);
220
return propertyTokens;