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 2725 2007-04-01 18:49:29Z taqua $
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    }