001: /*
002: * hgcommons 7
003: * Hammurapi Group Common Library
004: * Copyright (C) 2003 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/hammurapi-group/products/products/hgcommons/index.html
021: * e-Mail: support@hammurapi.biz
022: */
023: package biz.hammurapi.config;
024:
025: import java.util.HashSet;
026: import java.util.Set;
027: import java.util.StringTokenizer;
028:
029: /**
030: * Expands property value entries like ${myProperty} to property values.
031: * Nested properties are supportd, i.e. if myProperty value contains ${someOtherPropery}
032: * then it will also be expanded. ${ escaping is not supported.
033: * @author Pavel Vlasov
034: * @version $Revision: 1.3 $
035: */
036: public class PropertyParser {
037: private Context context;
038: private boolean useNameAsDefault;
039:
040: /**
041: * Creates a new instance of PropertyParser with system
042: * properties.
043: * @param useNameAsDefault If true then property name will be used
044: * as property default value.
045: */
046: public PropertyParser(boolean useNameAsDefault) {
047: context = new Context() {
048: public Object get(String name) {
049: return System.getProperty(name);
050: }
051: };
052:
053: this .useNameAsDefault = useNameAsDefault;
054: }
055:
056: /**
057: * Creates a new instance of PropertyParser
058: * @param properties Properties
059: * @param useNameAsDefault If true then property name will be used
060: * as property default value.
061: */
062: public PropertyParser(Context context, boolean useNameAsDefault) {
063: if (context == null) {
064: throw new NullPointerException("Context is null");
065: }
066: this .context = context;
067: this .useNameAsDefault = useNameAsDefault;
068: }
069:
070: /**
071: * Property parsing.
072: * Replaces string ${<property name>} with property value.
073: * If property value contains ${<other property name>} it
074: * will be parsed.
075: */
076: public String getParsedProperty(String key) {
077: return getParsedProperty(key, new HashSet());
078: }
079:
080: /**
081: * Parses a string by replacing occurences of ${<property name>}
082: * with property values.
083: * If property value contains ${<other property name>} it
084: * will be parsed.
085: */
086: public String parse(String str) {
087: return parse(str, null);
088: }
089:
090: private String getParsedProperty(String key, Set stack) {
091: Object o = context.get(key);
092: String pr;
093: if (o == null) {
094: if (useNameAsDefault) {
095: pr = key;
096: } else {
097: return null;
098: }
099: } else {
100: pr = o.toString();
101: }
102:
103: if (stack.contains(key)) {
104: throw new RuntimeConfigurationException(
105: "Circular reference in property substitution, property: "
106: + key);
107: }
108:
109: stack.add(key);
110:
111: return parse(pr, stack);
112: }
113:
114: private String parse(String str, Set stack) {
115: if (str == null) {
116: return null;
117: }
118:
119: StringTokenizer st = new StringTokenizer(str, "${}", true);
120:
121: StringBuffer ret = new StringBuffer();
122: /**
123: * Parser state:
124: * 0: Text
125: * 1: $
126: * 2: ${
127: */
128: int state = 0;
129:
130: String propName = null;
131: while (st.hasMoreTokens()) {
132: String tkn = st.nextToken();
133: switch (state) {
134: case 0:
135: if ("$".equals(tkn))
136: state = 1;
137: else
138: ret.append(tkn);
139: break;
140: case 1:
141: if ("{".equals(tkn))
142: state = 2;
143: else {
144: state = 0;
145: ret.append("$");
146: ret.append(tkn);
147: }
148: break;
149: case 2:
150: if ("}".equals(tkn)) {
151: String propVal = getParsedProperty(propName,
152: stack == null ? new HashSet() : stack);
153: ret.append(propVal == null ? "${" + propName + "}"
154: : propVal);
155: propName = null;
156: state = 0;
157: } else {
158: if (propName == null)
159: propName = tkn;
160: else
161: propName += tkn;
162: }
163: break;
164: default:
165: throw new IllegalStateException(
166: "Illegal parser state: " + state);
167: }
168: }
169:
170: if (state == 2)
171: ret.append("${" + propName);
172:
173: return ret.toString();
174: }
175: }
|