001: /*
002: * Copyright 2002-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.core.io.support;
018:
019: import java.io.IOException;
020: import java.io.InputStream;
021: import java.io.InputStreamReader;
022: import java.util.Properties;
023:
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026:
027: import org.springframework.core.io.Resource;
028: import org.springframework.util.DefaultPropertiesPersister;
029: import org.springframework.util.PropertiesPersister;
030: import org.springframework.util.CollectionUtils;
031:
032: /**
033: * Base class for JavaBean-style components that need to load properties
034: * from one or more resources. Supports local properties as well, with
035: * configurable overriding.
036: *
037: * @author Juergen Hoeller
038: * @since 1.2.2
039: */
040: public abstract class PropertiesLoaderSupport {
041:
042: public static final String XML_FILE_EXTENSION = ".xml";
043:
044: /** Logger available to subclasses */
045: protected final Log logger = LogFactory.getLog(getClass());
046:
047: private Properties[] localProperties;
048:
049: private Resource[] locations;
050:
051: private boolean localOverride = false;
052:
053: private boolean ignoreResourceNotFound = false;
054:
055: private String fileEncoding;
056:
057: private PropertiesPersister propertiesPersister = new DefaultPropertiesPersister();
058:
059: /**
060: * Set local properties, e.g. via the "props" tag in XML bean definitions.
061: * These can be considered defaults, to be overridden by properties
062: * loaded from files.
063: */
064: public void setProperties(Properties properties) {
065: this .localProperties = new Properties[] { properties };
066: }
067:
068: /**
069: * Set local properties, e.g. via the "props" tag in XML bean definitions,
070: * allowing for merging multiple properties sets into one.
071: */
072: public void setPropertiesArray(Properties[] propertiesArray) {
073: this .localProperties = propertiesArray;
074: }
075:
076: /**
077: * Set a location of a properties file to be loaded.
078: * <p>Can point to a classic properties file or to an XML file
079: * that follows JDK 1.5's properties XML format.
080: */
081: public void setLocation(Resource location) {
082: this .locations = new Resource[] { location };
083: }
084:
085: /**
086: * Set locations of properties files to be loaded.
087: * <p>Can point to classic properties files or to XML files
088: * that follow JDK 1.5's properties XML format.
089: */
090: public void setLocations(Resource[] locations) {
091: this .locations = locations;
092: }
093:
094: /**
095: * Set whether local properties override properties from files.
096: * Default is "false": properties from files override local defaults.
097: * Can be switched to "true" to let local properties override defaults
098: * from files.
099: */
100: public void setLocalOverride(boolean localOverride) {
101: this .localOverride = localOverride;
102: }
103:
104: /**
105: * Set if failure to find the property resource should be ignored.
106: * True is appropriate if the properties file is completely optional.
107: * Default is "false".
108: */
109: public void setIgnoreResourceNotFound(boolean ignoreResourceNotFound) {
110: this .ignoreResourceNotFound = ignoreResourceNotFound;
111: }
112:
113: /**
114: * Set the encoding to use for parsing properties files.
115: * <p>Default is none, using the <code>java.util.Properties</code>
116: * default encoding.
117: * <p>Only applies to classic properties files, not to XML files.
118: * @see org.springframework.util.PropertiesPersister#load
119: */
120: public void setFileEncoding(String encoding) {
121: this .fileEncoding = encoding;
122: }
123:
124: /**
125: * Set the PropertiesPersister to use for parsing properties files.
126: * The default is DefaultPropertiesPersister.
127: * @see org.springframework.util.DefaultPropertiesPersister
128: */
129: public void setPropertiesPersister(
130: PropertiesPersister propertiesPersister) {
131: this .propertiesPersister = (propertiesPersister != null ? propertiesPersister
132: : new DefaultPropertiesPersister());
133: }
134:
135: /**
136: * Return a merged Properties instance containing both the
137: * loaded properties and properties set on this FactoryBean.
138: */
139: protected Properties mergeProperties() throws IOException {
140: Properties result = new Properties();
141:
142: if (this .localOverride) {
143: // Load properties from file upfront, to let local properties override.
144: loadProperties(result);
145: }
146:
147: if (this .localProperties != null) {
148: for (int i = 0; i < this .localProperties.length; i++) {
149: CollectionUtils.mergePropertiesIntoMap(
150: this .localProperties[i], result);
151: }
152: }
153:
154: if (!this .localOverride) {
155: // Load properties from file afterwards, to let those properties override.
156: loadProperties(result);
157: }
158:
159: return result;
160: }
161:
162: /**
163: * Load properties into the given instance.
164: * @param props the Properties instance to load into
165: * @throws java.io.IOException in case of I/O errors
166: * @see #setLocations
167: */
168: protected void loadProperties(Properties props) throws IOException {
169: if (this .locations != null) {
170: for (int i = 0; i < this .locations.length; i++) {
171: Resource location = this .locations[i];
172: if (logger.isInfoEnabled()) {
173: logger.info("Loading properties file from "
174: + location);
175: }
176: InputStream is = null;
177: try {
178: is = location.getInputStream();
179: if (location.getFilename().endsWith(
180: XML_FILE_EXTENSION)) {
181: this .propertiesPersister.loadFromXml(props, is);
182: } else {
183: if (this .fileEncoding != null) {
184: this .propertiesPersister.load(props,
185: new InputStreamReader(is,
186: this .fileEncoding));
187: } else {
188: this .propertiesPersister.load(props, is);
189: }
190: }
191: } catch (IOException ex) {
192: if (this .ignoreResourceNotFound) {
193: if (logger.isWarnEnabled()) {
194: logger
195: .warn("Could not load properties from "
196: + location
197: + ": "
198: + ex.getMessage());
199: }
200: } else {
201: throw ex;
202: }
203: } finally {
204: if (is != null) {
205: is.close();
206: }
207: }
208: }
209: }
210: }
211:
212: }
|