/* * Copyright 2008 the original author or authors. * * 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.constretto.internal.store; import org.constretto.ConfigurationStore; import org.constretto.exception.ConstrettoException; import org.constretto.internal.ConstrettoUtils; import org.constretto.model.Resource; import org.constretto.model.TaggedPropertySet; import java.io.IOException; import java.io.InputStream; import java.util.*; import static org.constretto.internal.ConstrettoUtils.mergePropertiesIntoMap; /** * This is a store for text files implementing key=value pairs. Also, it supports adding a convention of tgsa to * ordinary properties. For tags, we use a specific prefix which can be configured by the user, whose default value is "@". * <p/> * Please see {@link org.constretto.ConstrettoBuilder#addCurrentTag(String)} for more information on the tag concept. * * @author <a href="mailto:kristoffer.moum@arktekk.no">Kristoffer Moum</a> */ public class PropertiesStore implements ConfigurationStore { private static final String TAG_PREFIX = "@"; private static final String PROPERTY_CONTEXT_SEPARATOR = "."; private final Map<String, String> properties; public PropertiesStore() { this.properties = new HashMap<String, String>(); } private PropertiesStore(Map<String, String> properties) { this.properties = properties; } public PropertiesStore addResource(Resource resource) { addResourcesAsProperties(resource); return new PropertiesStore(properties); } public List<TaggedPropertySet> parseConfiguration() { return getPropertySets(); } private void addPropertiesToMap(Properties... props) { for (Properties p : props) { mergePropertiesIntoMap(parseProperties(p), this.properties); } } /** * Used by sublclasses * * @param props the properties currently read * @return the argument */ protected Properties parseProperties(Properties props) { return props; } /** * Assumes that the passed resources wrap files that conform to {@link java.util.Properties}. The contents of these * files are added to the local representation of all application properties to be handled by this store. * * @param resources Spring resource paths to the property files used to back this store */ private void addResourcesAsProperties(Resource... resources) { for (Resource r : resources) { InputStream is = null; try { if (r.exists()) { is = r.getInputStream(); Properties props = new Properties(); props.load(is); addPropertiesToMap(props); } } catch (IOException e) { throw new ConstrettoException(e); } finally { try { if (is != null) { is.close(); } } catch (Exception e){ //We do not care if close does not work } } } } /** * Get all property sets that are relevant to this store, i.e. both tagged as well as untagged properties. A * single PropertySet is added per tag and then finally a single PropertySet containing all untaggef * properties. * * @return A list of all property sets, never null. */ private List<TaggedPropertySet> getPropertySets() { List<TaggedPropertySet> taggedPropertySets = new ArrayList<TaggedPropertySet>(); Set<String> tags = getTags(this.properties); for (String tag : tags) { taggedPropertySets.add(new TaggedPropertySet(tag, getPropertiesByTag(tag, this.properties), getClass())); } Map<String, String> unTaggedProperties = getUnTaggedProperties(this.properties); if (!unTaggedProperties.isEmpty()) { taggedPropertySets.add(new TaggedPropertySet(getUnTaggedProperties(this.properties), getClass())); } return taggedPropertySets; } private boolean isTag(String key) { return key.startsWith(TAG_PREFIX); } private Map<String, String> getPropertiesByTag(String nonPrefixedTag, Map<String, String> allProperties) { String prefixedTag = prefixTag(nonPrefixedTag); Map<String, String> taggedProperties = new HashMap<String, String>(); for (Map.Entry<String, String> entry : allProperties.entrySet()) { if (entry.getKey().startsWith(prefixedTag)) { String strippedKey = stripTag(entry.getKey(), nonPrefixedTag); if (!strippedKey.equals("")) { taggedProperties.put(strippedKey, entry.getValue()); } } } return taggedProperties; } /** * Get a map of untagged properties, i.e. their keys do not conform to {@link #isTag(String)}. * * @param properties a map of the properties of which to run through * @return a map of untagged properties, never null */ private Map<String, String> getUnTaggedProperties(Map<String, String> properties) { Map<String, String> unTagged = new HashMap<String, String>(); for (Map.Entry<String, String> entry : properties.entrySet()) { if (!isTag(entry.getKey())) { unTagged.put(entry.getKey(), entry.getValue()); } } return unTagged; } private Set<String> getTags(Map<String, String> properties) { Set<String> tags = new HashSet<String>(); for (String key : properties.keySet()) { String tag = getTag(key); if (tag != null) { tags.add(tag); } } return tags; } /** * Remove the actual tag from the passed key. I.e. a key is flagged as a tag by the following * entry: @tag.key=value. This method removes the tag information, i.e. "@tag.". * * @param key full, tagged key * @return the trimmed key, i.e. untagged. For passed keys that are untagged, null is returned */ private String getTag(String key) { if (isTag(key)) { return ConstrettoUtils.substringBetween(key, TAG_PREFIX, PROPERTY_CONTEXT_SEPARATOR); } else { return null; } } private String prefixTag(String tag) { return TAG_PREFIX + tag; } private String stripTag(String key, String tag) { return ConstrettoUtils.substringAfter(key, TAG_PREFIX + tag + PROPERTY_CONTEXT_SEPARATOR); } }