/* * Copyright 2013 NGDATA nv * Copyright 2008 Outerthought bvba and Schaubroeck nv * * 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.lilyproject.runtime.model; import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLEncoder; import java.util.Properties; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; public class PropertyResolver { private PropertyResolver() { } public static String resolveProperties(String input) { return resolveProperties(input, System.getProperties()); } /** * Resolves properties in the input string referenced using * ${property} syntax. Special 'function' properties are also * supported, which use a syntax like ${url-encode:something}. * Nested syntax is also supported, e.g. * ${property and ${anotherproperty}}, which is mostly useful * in combination with the function properties like 'url-encode:'. */ public static String resolveProperties(String input, Properties properties) { StringBuilder result = new StringBuilder(input.length()); StringBuilder propertyBuffer = null; Stack openPropertyBuffers = new Stack(); final int STATE_DEFAULT = 0; final int STATE_IN_PROP = 1; int state = STATE_DEFAULT; for (int i = 0; i < input.length(); i++) { char c = input.charAt(i); switch (c) { case '$': if (i + 1 < input.length() && input.charAt(i + 1) == '{') { if (state == STATE_IN_PROP) { openPropertyBuffers.push(propertyBuffer); } i++; state = STATE_IN_PROP; propertyBuffer = new StringBuilder(); } else { (state == STATE_IN_PROP ? propertyBuffer : result).append("$"); } break; case '}': if (state == STATE_IN_PROP) { String propName = propertyBuffer.toString(); String propValue = evaluateProperty(propName, properties); String propEvalResult = propValue != null ? propValue : "${" + propName + "}"; if (!openPropertyBuffers.empty()) { propertyBuffer = (StringBuilder)openPropertyBuffers.pop(); propertyBuffer.append(propEvalResult); // stay in STATE_IN_PROP } else { result.append(propEvalResult); state = STATE_DEFAULT; } } else { result.append(c); } break; default: (state == STATE_IN_PROP ? propertyBuffer : result).append(c); } } if (state == STATE_IN_PROP) { // process any property buffers still open do { if (!openPropertyBuffers.empty()) { propertyBuffer = ((StringBuilder)openPropertyBuffers.pop()).append("${").append(propertyBuffer); } else { result.append("${").append(propertyBuffer); propertyBuffer = null; } } while (propertyBuffer != null); } return result.toString(); } private static Pattern PROP_PATTERN = Pattern.compile("^([^:]+):(.+)$"); /** * Evaluates properties containing special syntax. * * <p>Allows for things like ${url-encode:propname}. */ private static String evaluateProperty(String input, Properties properties) { Matcher matcher = PROP_PATTERN.matcher(input); if (matcher.matches()) { String action = matcher.group(1); String value = matcher.group(2); try { if (action.equals("url-encode")) { return URLEncoder.encode(value, "UTF-8"); } else if (action.equals("double-url-encode")) { return URLEncoder.encode(URLEncoder.encode(value, "UTF-8"), "UTF-8"); } else if (action.equals("tripple-url-encode")) { return URLEncoder.encode(URLEncoder.encode(URLEncoder.encode(value, "UTF-8"), "UTF-8"), "UTF-8"); } else if (action.equals("uri-path-encode")) { try { return new URI(null, null, value, null).getRawSchemeSpecificPart(); } catch (URISyntaxException e) { throw new RuntimeException("Error in uri-path-encode function of property resolver.", e); } } else if (action.equals("file-to-uri")) { return new File(value).toURI().toString(); } else { return null; } } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } else { return properties.getProperty(input); } } }