Package: PropertyPlaceholderResolver$1

PropertyPlaceholderResolver$1

nameinstructionbranchcomplexitylinemethod
transform(String, String, String)
M: 2 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
{...}
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2008, 2010 VMware Inc.
3: * All rights reserved. This program and the accompanying materials
4: * are made available under the terms of the Eclipse Public License v1.0
5: * which accompanies this distribution, and is available at
6: * http://www.eclipse.org/legal/epl-v10.html
7: *
8: * Contributors:
9: * VMware Inc. - initial contribution
10: *******************************************************************************/
11:
12: package org.eclipse.virgo.util.common;
13:
14: import java.util.Enumeration;
15: import java.util.Properties;
16: import java.util.Stack;
17: import java.util.UUID;
18: import java.util.regex.Matcher;
19: import java.util.regex.Pattern;
20:
21: /**
22: * Utility class for resolving placeholders inside a {@link Properties} instance. These placeholders can refer to other
23: * properties in the <code>Properties</code> instance. The place holders may also have a modifier in them
24: *
25: * <pre>
26: * ${com.springsource:modifier}
27: * </pre>
28: *
29: * where everything after the colon is considered the modifier. This class does not interpret these modifiers but
30: * rather delegates to a {@link PlaceholderValueTransformer} for processing.
31: * <p />
32: *
33: * <strong>Concurrent Semantics</strong><br />
34: *
35: * Threadsafe.
36: */
37: public final class PropertyPlaceholderResolver {
38:
39: private static final Pattern PATTERN = Pattern.compile("\\$\\{([^:\\}]*):?([^\\}]*)?\\}");
40:
41: private static final PlaceholderValueTransformer IDENTITY_TRANSFORMER = new PlaceholderValueTransformer() {
42:
43: public String transform(String propertyName, String propertyValue, String modifier) {
44: return propertyValue;
45: }
46:
47: };
48:
49: /**
50: * Resolves all placeholders in the supplied {@link Properties} instance.
51: *
52: * @param input the properties to resolve.
53: * @return the resolved properties.
54: */
55: public Properties resolve(Properties input) {
56: return resolve(input, IDENTITY_TRANSFORMER);
57: }
58:
59: /**
60: * Resolves all placeholders in the supplied {@link Properties} instance and transform any based on their modifiers.
61: *
62: * @param input the properties to resolve.
63: * @param transformer a transformer for handling property modifiers
64: * @return the resolved properties.
65: */
66: public Properties resolve(Properties input, PlaceholderValueTransformer transformer) {
67: Properties result = new Properties();
68: Enumeration<?> propertyNames = input.propertyNames();
69:
70: while (propertyNames.hasMoreElements()) {
71:                         String propertyName = (String) propertyNames.nextElement();
72:                         result.setProperty(propertyName, resolveProperty(propertyName, input, transformer));
73:                         
74:                 }
75:
76: return result;
77: }
78:
79: /**
80: * Resolves all placeholders in the supplied string with values from a {@link Properties} instance.
81: *
82: * @param input the string to resolve
83: * @param props the properties to use for resolution
84: * @return the resolved string
85: */
86: public String resolve(String input, Properties props) {
87: return resolve(input, props, IDENTITY_TRANSFORMER);
88: }
89:
90: /**
91: * Resolves all placeholders in the supplied string with values from a {@link Properties} instance and transform any
92: * based on their modifiers.
93: *
94: * @param input the string to resolve
95: * @param props the properties to use for resolution
96: * @param transformer a transformer for handling property modifiers
97: * @return the resolved string
98: */
99: public String resolve(String input, Properties props, PlaceholderValueTransformer transformer) {
100: String key = UUID.randomUUID().toString();
101: props.put(key, input);
102: String value = resolveProperty(key, props, transformer);
103: props.remove(key);
104: return value;
105: }
106:
107: private String resolveProperty(String name, Properties props, PlaceholderValueTransformer transformer) {
108: Stack<String> visitState = new Stack<String>();
109: return resolve(name, props, transformer, visitState);
110: }
111:
112: private String resolve(String name, Properties props, PlaceholderValueTransformer transformer, Stack<String> visitState) {
113: visitState.push(name);
114:
115: String initialValue = props.getProperty(name);
116: if(initialValue == null) {
117: throw new RuntimeException("No value found for placeholder '" + name + "'");
118: }
119:
120: Matcher matcher = PATTERN.matcher(initialValue);
121:
122: StringBuffer sb = new StringBuffer();
123: while (matcher.find()) {
124: String propName = matcher.group(1);
125: if (visitState.contains(propName)) {
126: throw new IllegalArgumentException(formatPropertyCycleMessage(visitState));
127: }
128:
129: String value = resolve(propName, props, transformer, visitState);
130: if (matcher.group(2).length() > 0) {
131: value = transformer.transform(propName, value, matcher.group(2));
132: }
133: matcher.appendReplacement(sb, escapeBackslashes(value));
134: }
135: matcher.appendTail(sb);
136:
137: visitState.pop();
138: return sb.toString();
139: }
140:
141: private static String escapeBackslashes(String string) {
142: StringBuffer sb = new StringBuffer(string.length());
143: int bsIndex = string.indexOf("\\");
144: int pos = 0;
145: while (bsIndex != -1) {
146: sb.append(string.substring(pos,bsIndex+1));
147: sb.append("\\"); // another backslash
148: pos = bsIndex+1;
149: bsIndex = string.indexOf("\\",pos);
150: }
151: sb.append(string.substring(pos, string.length()));
152: return new String(sb);
153: }
154:
155: private String formatPropertyCycleMessage(Stack<String> visitState) {
156: StringBuilder sb = new StringBuilder();
157: sb.append("Circular reference in property definitions: ");
158: for (String name : visitState) {
159: sb.append(name).append(" -> ");
160: }
161:
162: sb.append(visitState.iterator().next());
163: return sb.toString();
164: }
165:
166: /**
167: * An interface for property placeholder modifiers. Implementations of this interface are called when a property
168: * placeholder modifier is detected on a class.
169: * <p />
170: *
171: * <strong>Concurrent Semantics</strong><br />
172: *
173: * Implementations must be threadsafe.
174: *
175: */
176: public static interface PlaceholderValueTransformer {
177:
178: /**
179: * Transforms a property from its initial value to some other value
180: *
181: * @param propertyName the name of the property being transformed
182: * @param propertyValue the original value of the property
183: * @param modifier the modifer string attached to the placeholder
184: * @return A string that has been modified by this transformer and to be used in place of the original value
185: */
186: String transform(String propertyName, String propertyValue, String modifier);
187: }
188: }