View Javadoc
1   /**
2    * Copyright 2010-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community 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
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
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.
15   */
16  package org.kuali.common.util.properties;
17  
18  import static com.google.common.base.Preconditions.checkArgument;
19  import static com.google.common.base.Preconditions.checkNotNull;
20  
21  import java.util.Set;
22  import java.util.regex.Matcher;
23  import java.util.regex.Pattern;
24  
25  import org.apache.commons.lang3.StringUtils;
26  import org.kuali.common.util.log.LoggerUtils;
27  import org.slf4j.Logger;
28  import org.springframework.util.PropertyPlaceholderHelper;
29  
30  import com.google.common.collect.Sets;
31  
32  public final class RicePropertyPlaceholderHelper extends PropertyPlaceholderHelper {
33  
34  	private static final Logger logger = LoggerUtils.make();
35  
36  	private final boolean convertUnresolvablePlaceholdersToEmpty;
37  	private final String placeholderRegex;
38  	private final Pattern pattern;
39  
40  	private RicePropertyPlaceholderHelper(Builder builder) {
41  		super(builder.placeholderPrefix, builder.placeholderSuffix, builder.valueSeparator, builder.allowUnresolvablePlaceholders);
42  		this.convertUnresolvablePlaceholdersToEmpty = builder.convertUnresolvablePlaceholdersToEmpty;
43  		this.placeholderRegex = builder.placeholderRegex;
44  		this.pattern = builder.pattern;
45  	}
46  
47  	public static RicePropertyPlaceholderHelper create() {
48  		return builder().build();
49  	}
50  
51  	public static Builder builder() {
52  		return new Builder();
53  	}
54  
55  	public static class Builder {
56  
57  		private boolean allowUnresolvablePlaceholders = true;
58  		private boolean convertUnresolvablePlaceholdersToEmpty = true;
59  		private String placeholderPrefix = "${";
60  		private String placeholderSuffix = "}";
61  		private String valueSeparator = ":";
62  		private String placeholderRegex = "\\$\\{([^{}]+)\\}";
63  
64  		// Filled in by the build() method
65  		private Pattern pattern;
66  
67  		public Builder placeholderRegex(String placeholderRegex) {
68  			this.placeholderRegex = placeholderRegex;
69  			return this;
70  		}
71  
72  		public Builder convertUnresolvablePlaceholdersToEmpty(boolean convertUnresolvablePlaceholdersToEmpty) {
73  			this.convertUnresolvablePlaceholdersToEmpty = convertUnresolvablePlaceholdersToEmpty;
74  			return this;
75  		}
76  
77  		public Builder placeholderPrefix(String placeholderPrefix) {
78  			this.placeholderPrefix = placeholderPrefix;
79  			return this;
80  		}
81  
82  		public Builder placeholderSuffix(String placeholderSuffix) {
83  			this.placeholderSuffix = placeholderSuffix;
84  			return this;
85  		}
86  
87  		public Builder valueSeparator(String valueSeparator) {
88  			this.valueSeparator = valueSeparator;
89  			return this;
90  		}
91  
92  		public Builder allowUnresolvablePlaceholders(boolean allowUnresolvablePlaceholders) {
93  			this.allowUnresolvablePlaceholders = allowUnresolvablePlaceholders;
94  			return this;
95  		}
96  
97  		public RicePropertyPlaceholderHelper build() {
98  			this.pattern = Pattern.compile(placeholderRegex);
99  			RicePropertyPlaceholderHelper instance = new RicePropertyPlaceholderHelper(this);
100 			validate(instance);
101 			return instance;
102 		}
103 
104 		private static void validate(RicePropertyPlaceholderHelper instance) {
105 			checkArgument(!StringUtils.isBlank(instance.placeholderRegex), "'placeholderRegex' cannot be blank");
106 			checkNotNull(instance.pattern, "'pattern' cannot be null");
107 		}
108 
109 		public boolean isAllowUnresolvablePlaceholders() {
110 			return allowUnresolvablePlaceholders;
111 		}
112 
113 		public void setAllowUnresolvablePlaceholders(boolean allowUnresolvablePlaceholders) {
114 			this.allowUnresolvablePlaceholders = allowUnresolvablePlaceholders;
115 		}
116 
117 		public boolean isConvertUnresolvablePlaceholdersToEmpty() {
118 			return convertUnresolvablePlaceholdersToEmpty;
119 		}
120 
121 		public void setConvertUnresolvablePlaceholdersToEmpty(boolean convertUnresolvablePlaceholdersToEmpty) {
122 			this.convertUnresolvablePlaceholdersToEmpty = convertUnresolvablePlaceholdersToEmpty;
123 		}
124 
125 		public String getPlaceholderPrefix() {
126 			return placeholderPrefix;
127 		}
128 
129 		public void setPlaceholderPrefix(String placeholderPrefix) {
130 			this.placeholderPrefix = placeholderPrefix;
131 		}
132 
133 		public String getPlaceholderSuffix() {
134 			return placeholderSuffix;
135 		}
136 
137 		public void setPlaceholderSuffix(String placeholderSuffix) {
138 			this.placeholderSuffix = placeholderSuffix;
139 		}
140 
141 		public String getValueSeparator() {
142 			return valueSeparator;
143 		}
144 
145 		public void setValueSeparator(String valueSeparator) {
146 			this.valueSeparator = valueSeparator;
147 		}
148 	}
149 
150 	public boolean isConvertUnresolvablePlaceholdersToEmpty() {
151 		return convertUnresolvablePlaceholdersToEmpty;
152 	}
153 
154 	protected Conversion convertToEmpty(String value) {
155 		return convert(value, "");
156 	}
157 
158 	public static class Conversion {
159 
160 		public Conversion(String original, String converted, Set<String> keys) {
161 			checkNotNull(original, "original cannot be null");
162 			checkNotNull(converted, "converted cannot be null");
163 			checkNotNull(keys, "keys cannot be null");
164 			this.original = original;
165 			this.converted = converted;
166 			this.keys = keys;
167 		}
168 
169 		private final String original;
170 		private final String converted;
171 		private final Set<String> keys;
172 
173 		public String getOriginal() {
174 			return original;
175 		}
176 
177 		public String getConverted() {
178 			return converted;
179 		}
180 
181 		public Set<String> getKeys() {
182 			return keys;
183 		}
184 	}
185 
186 	protected Conversion convert(String value, String token) {
187 		String result = value;
188 		Matcher matcher = pattern.matcher(value);
189 		Set<String> keys = Sets.newTreeSet();
190 		while (matcher.find()) {
191 			// Get the first, outermost ${} in the string
192 			// This removes the ${} and produces the enclosed key
193 			keys.add(matcher.group(1));
194 
195 			// Replace the first ${} with token
196 			result = matcher.replaceFirst(token);
197 
198 			// Reset the matcher so we can continue examining the string
199 			matcher = matcher.reset(result);
200 		}
201 
202 		// All placeholders have been replaced with the empty string at this point
203 		return new Conversion(value, result, keys);
204 	}
205 
206 	protected String convert(String string) {
207 		if (convertUnresolvablePlaceholdersToEmpty) {
208 			Conversion result = convert(string, "");
209 			for (String key : result.getKeys()) {
210 				logger.info("? unknown - [{}] - converted to \"\"", key);
211 			}
212 			return result.getConverted();
213 		} else {
214 			return string;
215 		}
216 	}
217 
218 	@Override
219 	public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
220 		String replaced = super.replacePlaceholders(value, placeholderResolver);
221 		if (convertUnresolvablePlaceholdersToEmpty) {
222 			Conversion result = convert(replaced, "");
223 			for (String key : result.getKeys()) {
224 				logger.info("? unknown - [{}] - converted to \"\"", key);
225 			}
226 			return result.getConverted();
227 		} else {
228 			return replaced;
229 		}
230 	}
231 
232 	public String getPlaceholderRegex() {
233 		return placeholderRegex;
234 	}
235 
236 	public Pattern getPattern() {
237 		return pattern;
238 	}
239 }