001 /**
002 * ========================================
003 * JFreeReport : a free Java report library
004 * ========================================
005 *
006 * Project Info: http://reporting.pentaho.org/
007 *
008 * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
009 *
010 * This library is free software; you can redistribute it and/or modify it under the terms
011 * of the GNU Lesser General Public License as published by the Free Software Foundation;
012 * either version 2.1 of the License, or (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016 * See the GNU Lesser General Public License for more details.
017 *
018 * You should have received a copy of the GNU Lesser General Public License along with this
019 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020 * Boston, MA 02111-1307, USA.
021 *
022 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023 * in the United States and other countries.]
024 *
025 * ------------
026 * $Id: PropertyLookupParser.java,v 1.7 2007/04/01 18:49:33 taqua Exp $
027 * ------------
028 * (C) Copyright 2000-2005, by Object Refinery Limited.
029 * (C) Copyright 2005-2007, by Pentaho Corporation.
030 */
031
032 package org.jfree.report.util;
033
034 import java.io.Serializable;
035
036 /**
037 * The property lookup parser is used to resolve embedded references to
038 * properties within strings.
039 * <p>
040 * The default format of the property specification is:
041 * <code>${property-name}</code> where 'property-name is the name of the
042 * property. If this construct is found within the text, it is replaced with
043 * the value returned from a call to "lookupVariable".
044 *
045 * @author Thomas Morgner
046 */
047 public abstract class PropertyLookupParser implements Serializable
048 {
049 /** A parse state indicator signaling that the parser is outside a property. */
050 private static final int EXPECT_DOLLAR = 0;
051 /** A parse state indicator signaling that an open brace is expected. */
052 private static final int EXPECT_OPEN_BRACE = 1;
053
054 /**
055 * A parse state indicator signaling that a closed brace is expected. All chars
056 * received, which are not equal to the closed brace, count as property name.
057 */
058 private static final int EXPECT_CLOSE_BRACE = 2;
059 /** The initial marker char, a $ by default. */
060 private char markerChar;
061 /** The closing brace char. */
062 private char closingBraceChar;
063 /** The opening brace char. */
064 private char openingBraceChar;
065 /** The escape char. */
066 private char escapeChar;
067
068 /**
069 * Initializes the parser to the default format of "${..}". The
070 * escape char will be a backslash.
071 */
072 protected PropertyLookupParser ()
073 {
074 markerChar = '$';
075 closingBraceChar = '}';
076 openingBraceChar = '{';
077 escapeChar = '\\';
078 }
079
080 /**
081 * Returns the currently defined closed-brace char.
082 *
083 * @return the closed-brace char.
084 */
085 public char getClosingBraceChar ()
086 {
087 return closingBraceChar;
088 }
089
090 /**
091 * Defines the closing brace character.
092 * @param closingBraceChar the closed-brace character.
093 */
094 public void setClosingBraceChar (final char closingBraceChar)
095 {
096 this.closingBraceChar = closingBraceChar;
097 }
098
099 /**
100 * Returns the escape char.
101 * @return the escape char.
102 */
103 public char getEscapeChar ()
104 {
105 return escapeChar;
106 }
107
108 /**
109 * Defines the escape char.
110 *
111 * @param escapeChar the escape char
112 */
113 public void setEscapeChar (final char escapeChar)
114 {
115 this.escapeChar = escapeChar;
116 }
117
118 /**
119 * Returns the currently defined opening-brace char.
120 *
121 * @return the opening-brace char.
122 */
123 public char getOpeningBraceChar ()
124 {
125 return openingBraceChar;
126 }
127
128 /**
129 * Defines the opening brace character.
130 * @param openingBraceChar the opening-brace character.
131 */
132 public void setOpeningBraceChar (final char openingBraceChar)
133 {
134 this.openingBraceChar = openingBraceChar;
135 }
136
137 /**
138 * Returns initial property marker char.
139 * @return the initial property marker character.
140 */
141 public char getMarkerChar ()
142 {
143 return markerChar;
144 }
145
146 /**
147 * Defines initial property marker char.
148 * @param markerChar the initial property marker character.
149 */
150 public void setMarkerChar (final char markerChar)
151 {
152 this.markerChar = markerChar;
153 }
154
155 /**
156 * Translates the given string and resolves the embedded property references.
157 *
158 * @param value the raw value,
159 * @return the fully translated string.
160 */
161 public String translateAndLookup (final String value)
162 {
163 if (value == null)
164 {
165 return null;
166 }
167
168 final char[] chars = value.toCharArray();
169 final StringBuffer result = new StringBuffer(chars.length);
170 boolean haveEscape = false;
171 int state = EXPECT_DOLLAR;
172 final StringBuffer propertyName = new StringBuffer();
173
174 for (int i = 0; i < chars.length; i++)
175 {
176 final char c = chars[i];
177
178 if (haveEscape)
179 {
180 haveEscape = false;
181 if (state == EXPECT_CLOSE_BRACE)
182 {
183 propertyName.append(c);
184 }
185 else
186 {
187 result.append(c);
188 }
189 continue;
190 }
191
192 if (state == EXPECT_DOLLAR && c == markerChar)
193 {
194 state = EXPECT_OPEN_BRACE;
195 continue;
196 }
197 if (state == EXPECT_OPEN_BRACE)
198 {
199 if (c == openingBraceChar)
200 {
201 state = EXPECT_CLOSE_BRACE;
202 continue;
203 }
204 else
205 {
206 result.append(markerChar);
207 state = 0;
208 }
209 }
210 if (state == EXPECT_CLOSE_BRACE && c == closingBraceChar)
211 {
212 final String s = lookupVariable(propertyName.toString());
213 if (s == null)
214 {
215 result.append(markerChar);
216 result.append(openingBraceChar);
217 result.append(propertyName);
218 result.append(closingBraceChar);
219 }
220 else
221 {
222 result.append(s);
223 }
224 propertyName.delete(0, propertyName.length());
225 state = 0;
226 continue;
227 }
228
229 if (c == escapeChar)
230 {
231 haveEscape = true;
232 continue;
233 }
234
235 if (state == EXPECT_CLOSE_BRACE)
236 {
237 propertyName.append(c);
238 }
239 else
240 {
241 result.append(c);
242 }
243 }
244
245 if (state >= EXPECT_OPEN_BRACE)
246 {
247 result.append(markerChar);
248 if (state >= EXPECT_CLOSE_BRACE)
249 {
250 result.append(openingBraceChar);
251 result.append(propertyName);
252 }
253 }
254 return result.toString();
255 }
256
257 /**
258 * Looks up the property with the given name.
259 *
260 * @param property the name of the property to look up.
261 * @return the translated value.
262 */
263 protected abstract String lookupVariable (String property);
264 }