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 3048 2007-07-28 18:02:42Z tmorgner $
027: * ------------
028: * (C) Copyright 2000-2005, by Object Refinery Limited.
029: * (C) Copyright 2005-2007, by Pentaho Corporation.
030: */package org.jfree.report.util;
031:
032: import java.io.Serializable;
033:
034: /**
035: * The property lookup parser is used to resolve embedded references to
036: * properties within strings.
037: * <p>
038: * The default format of the property specification is:
039: * <code>${property-name}</code> where 'property-name is the name of the
040: * property. If this construct is found within the text, it is replaced with
041: * the value returned from a call to "lookupVariable".
042: *
043: * @author Thomas Morgner
044: */
045: public abstract class PropertyLookupParser implements Serializable {
046: /** A parse state indicator signaling that the parser is outside a property. */
047: private static final int EXPECT_DOLLAR = 0;
048: /** A parse state indicator signaling that an open brace is expected. */
049: private static final int EXPECT_OPEN_BRACE = 1;
050:
051: /**
052: * A parse state indicator signaling that a closed brace is expected. All chars
053: * received, which are not equal to the closed brace, count as property name.
054: */
055: private static final int EXPECT_CLOSE_BRACE = 2;
056: /** The initial marker char, a $ by default. */
057: private char markerChar;
058: /** The closing brace char. */
059: private char closingBraceChar;
060: /** The opening brace char. */
061: private char openingBraceChar;
062: /** The escape char. */
063: private char escapeChar;
064:
065: /**
066: * Initializes the parser to the default format of "${..}". The
067: * escape char will be a backslash.
068: */
069: protected PropertyLookupParser() {
070: markerChar = '$';
071: closingBraceChar = '}';
072: openingBraceChar = '{';
073: escapeChar = '\\';
074: }
075:
076: /**
077: * Returns the currently defined closed-brace char.
078: *
079: * @return the closed-brace char.
080: */
081: public char getClosingBraceChar() {
082: return closingBraceChar;
083: }
084:
085: /**
086: * Defines the closing brace character.
087: * @param closingBraceChar the closed-brace character.
088: */
089: public void setClosingBraceChar(final char closingBraceChar) {
090: this .closingBraceChar = closingBraceChar;
091: }
092:
093: /**
094: * Returns the escape char.
095: * @return the escape char.
096: */
097: public char getEscapeChar() {
098: return escapeChar;
099: }
100:
101: /**
102: * Defines the escape char.
103: *
104: * @param escapeChar the escape char
105: */
106: public void setEscapeChar(final char escapeChar) {
107: this .escapeChar = escapeChar;
108: }
109:
110: /**
111: * Returns the currently defined opening-brace char.
112: *
113: * @return the opening-brace char.
114: */
115: public char getOpeningBraceChar() {
116: return openingBraceChar;
117: }
118:
119: /**
120: * Defines the opening brace character.
121: * @param openingBraceChar the opening-brace character.
122: */
123: public void setOpeningBraceChar(final char openingBraceChar) {
124: this .openingBraceChar = openingBraceChar;
125: }
126:
127: /**
128: * Returns initial property marker char.
129: * @return the initial property marker character.
130: */
131: public char getMarkerChar() {
132: return markerChar;
133: }
134:
135: /**
136: * Defines initial property marker char.
137: * @param markerChar the initial property marker character.
138: */
139: public void setMarkerChar(final char markerChar) {
140: this .markerChar = markerChar;
141: }
142:
143: /**
144: * Translates the given string and resolves the embedded property references.
145: *
146: * @param value the raw value,
147: * @return the fully translated string.
148: */
149: public String translateAndLookup(final String value) {
150: if (value == null) {
151: return null;
152: }
153:
154: final char[] chars = value.toCharArray();
155: final StringBuffer result = new StringBuffer(chars.length);
156: boolean haveEscape = false;
157: int state = EXPECT_DOLLAR;
158: final StringBuffer propertyName = new StringBuffer();
159:
160: for (int i = 0; i < chars.length; i++) {
161: final char c = chars[i];
162:
163: if (haveEscape) {
164: haveEscape = false;
165: if (state == EXPECT_CLOSE_BRACE) {
166: propertyName.append(c);
167: } else {
168: result.append(c);
169: }
170: continue;
171: }
172:
173: if (state == EXPECT_DOLLAR && c == markerChar) {
174: state = EXPECT_OPEN_BRACE;
175: continue;
176: }
177: if (state == EXPECT_OPEN_BRACE) {
178: if (c == openingBraceChar) {
179: state = EXPECT_CLOSE_BRACE;
180: continue;
181: } else {
182: result.append(markerChar);
183: state = 0;
184: }
185: }
186: if (state == EXPECT_CLOSE_BRACE && c == closingBraceChar) {
187: final String s = lookupVariable(propertyName.toString());
188: if (s == null) {
189: result.append(markerChar);
190: result.append(openingBraceChar);
191: result.append(propertyName);
192: result.append(closingBraceChar);
193: } else {
194: result.append(s);
195: }
196: propertyName.delete(0, propertyName.length());
197: state = 0;
198: continue;
199: }
200:
201: if (c == escapeChar) {
202: haveEscape = true;
203: continue;
204: }
205:
206: if (state == EXPECT_CLOSE_BRACE) {
207: propertyName.append(c);
208: } else {
209: result.append(c);
210: }
211: }
212:
213: if (state >= EXPECT_OPEN_BRACE) {
214: result.append(markerChar);
215: if (state >= EXPECT_CLOSE_BRACE) {
216: result.append(openingBraceChar);
217: result.append(propertyName);
218: }
219: }
220: return result.toString();
221: }
222:
223: /**
224: * Looks up the property with the given name.
225: *
226: * @param property the name of the property to look up.
227: * @return the translated value.
228: */
229: protected abstract String lookupVariable(String property);
230: }
|