KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sape > carbon > core > config > type > TokenReplacer


1 /*
2  * The contents of this file are subject to the Sapient Public License
3  * Version 1.0 (the "License"); you may not use this file except in compliance
4  * with the License. You may obtain a copy of the License at
5  * http://carbon.sf.net/License.html.
6  *
7  * Software distributed under the License is distributed on an "AS IS" basis,
8  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
9  * the specific language governing rights and limitations under the License.
10  *
11  * The Original Code is The Carbon Component Framework.
12  *
13  * The Initial Developer of the Original Code is Sapient Corporation
14  *
15  * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
16  */

17
18 package org.sape.carbon.core.config.type;
19
20
21 import java.lang.reflect.InvocationTargetException JavaDoc;
22 import java.util.StringTokenizer JavaDoc;
23
24 import org.sape.carbon.core.bootstrap.BootStrapper;
25 import org.sape.carbon.core.config.Config;
26 import org.sape.carbon.core.config.Configuration;
27 import org.sape.carbon.core.config.PropertyConfiguration;
28 import org.sape.carbon.core.util.reflection.BeanUtil;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32
33 /**
34  * <P>This class provides tokenization and value linking for configuration
35  * values in order to minimize the duplication of data. It supports two
36  * types of value replacement, document property and deployment property.</P>
37  *
38  * <P>The Document Property has a form of {document-name$attribute-name}. This
39  * would search for a document named <code>document-name</code> and then look
40  * for an attribute named <code>attribute-name</code>.</P>
41  *
42  * <P>The Deployment Property lookup has a form of {deployment-property}.
43  * This would
44  * retrieve the Deployment Property <code>deployment-property</code> from
45  * the BootStrapper.
46  * This mechanism should not be used for normal
47  * configurations and is specially provided for instances where deployment
48  * values can not or do not want to be known ahead of time (such as the base
49  * file-system directory of config or a database password).</P>
50  *
51  * @see org.sape.carbon.core.bootstrap.BootStrapper
52  *
53  * Copyright 2002 Sapient
54  * @since carbon 1.0
55  * @author Douglas Voet, April 2002
56  * @version $Revision: 1.19 $($Author: dvoet $ / $Date: 2003/05/05 21:21:20 $)
57  */

58 class TokenReplacer {
59
60     /**
61      * Provides a handle to Apache-commons logger
62      */

63     private Log log = LogFactory.getLog(this.getClass());
64
65     /**
66      * The delimiter that begins a replaceable config value
67      */

68     private static final String JavaDoc BEGIN_DELIMETER = "{";
69
70     /**
71      * The end delimter that declares the end of a replaceable
72      * config value
73      */

74     private static final String JavaDoc END_DELIMETER = "}";
75
76     /**
77      * The delimeter used for seperating a config document name
78      * from the value that is required from it.
79      */

80     private static final String JavaDoc ATTRIBUTE_DELIMETER = "$";
81
82     /**
83      * The character set used to escape other delimeters so that
84      * they can be used as real values.
85      */

86     private static final String JavaDoc ESCAPE_DELIMETER = "\\";
87
88     /** Delimiters to tokenize on. */
89     private static final String JavaDoc ALL_DELIMETERS =
90         BEGIN_DELIMETER
91             + END_DELIMETER
92             + ATTRIBUTE_DELIMETER
93             + ESCAPE_DELIMETER;
94
95     /**
96      * The data to be tokenized, mapped and replaced necessary.
97      */

98     private String JavaDoc data;
99
100     /** The replaced value of the data. */
101     private String JavaDoc replacedValue = null;
102
103     /**
104      * Creates a new token replacer for the specified configuration
105      * value.
106      *
107      * @param data the data to run the replacer on
108      */

109     public TokenReplacer(String JavaDoc data) {
110         this.data = data;
111     }
112
113     /**
114      * Tests if the data contains tokens.
115      *
116      * @return if the data contains tokens
117      */

118     public boolean containsTokens() {
119         if (data == null) {
120             return false;
121         } else {
122             return data.indexOf(TokenReplacer.BEGIN_DELIMETER) != -1;
123         }
124     }
125
126     /**
127      * Replaces tokens within configuration attributes with values from
128      * other configurations. Tokens are in the
129      * form of {<i>configuration name</i>$<i>attribute name</i>}. If
130      * either '{', '}' or '$' are required in the actual value, escape them
131      * with a '\'.
132      *
133      * @return String the String to tokenize and replace
134      * @throws ConfigurationTypeException thrown when unable to retrieve a
135      * referenced value or in case there is a failure parse the reference.
136      */

137     public String JavaDoc replaceTokens() throws ConfigurationTypeException {
138
139         if (this.data == null) {
140             return null;
141         }
142
143         if (this.replacedValue == null) {
144             StringBuffer JavaDoc replacedValueBuffer = new StringBuffer JavaDoc();
145             StringBuffer JavaDoc configurationNameBuffer = new StringBuffer JavaDoc();
146             StringBuffer JavaDoc configurationAttributeNameBuffer = new StringBuffer JavaDoc();
147
148             StringBuffer JavaDoc workingBuffer = replacedValueBuffer;
149
150             // set the returnDelims parameter to true so we know which
151
// delimeters we find
152
StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(
153                 this.data, TokenReplacer.ALL_DELIMETERS, true);
154
155             while (tokenizer.hasMoreTokens()) {
156                 String JavaDoc nextToken = tokenizer.nextToken();
157
158                 if (nextToken.equals(TokenReplacer.ESCAPE_DELIMETER)) {
159                     // found an escape character, are we escaping anything?
160
if (tokenizer.hasMoreTokens()) {
161                         // let's see what the next token is
162
nextToken = tokenizer.nextToken();
163                         if (nextToken.length() == 1
164                            && ALL_DELIMETERS.indexOf(nextToken) != -1) {
165                             // nextToken is a delimeter so append it
166
// without the escape delimeter to the buffer
167
workingBuffer.append(nextToken);
168                         } else {
169                             // nextToken is not a delimeter so append it
170
// with the escape delimeter to the buffer
171
workingBuffer.append(
172                                 TokenReplacer.ESCAPE_DELIMETER);
173                             workingBuffer.append(nextToken);
174                         }
175                     } else {
176                         // no more tokens so there is nothing to escape
177
// just append the escape delimeter to the buffer
178
workingBuffer.append(TokenReplacer.ESCAPE_DELIMETER);
179                     }
180
181                 } else if (nextToken.equals(TokenReplacer.BEGIN_DELIMETER)) {
182
183                     if (workingBuffer == configurationNameBuffer) {
184                         // this means that we were already looking for a
185
// configuration name and found a delimeter in the
186
// wrong context
187
throw new TokenReplacementException(
188                             this.getClass(),
189                             "Found 2 "
190                                 + TokenReplacer.BEGIN_DELIMETER
191                                 + "'s without an intervening "
192                                 + TokenReplacer.END_DELIMETER
193                                 + " in ["
194                                 + this.data
195                                 + "]");
196                     }
197                     // this means that we found the start of something
198
// that needs to be replaced, start appending
199
// to the configurationNameBuffer to generate the
200
// name of the config node
201
workingBuffer = configurationNameBuffer;
202
203                 } else if (nextToken.equals(TokenReplacer.END_DELIMETER)) {
204                     // this means that we were looking for the name of
205
// an attribute and have found it, switch
206
// workingBuffer to replacedValueBuffer so we will
207
// append future tokens to it
208
workingBuffer = replacedValueBuffer;
209
210                     // since we have found a config and attribute name
211
// look it up a append it to the working buffer,
212
// but validate that we have values first
213
if (configurationNameBuffer.length() == 0) {
214                         throw new TokenReplacementException(
215                             this.getClass(),
216                             "Configuration name not found in "
217                                 + "token within configuration value ["
218                                 + this.data
219                                 + "]");
220                     }
221
222                     String JavaDoc replacementValue =
223                         lookupConfigurationValue(
224                             configurationNameBuffer.toString(),
225                             configurationAttributeNameBuffer.toString());
226
227                     workingBuffer.append(replacementValue);
228                     // now reset the configurationNameBuffer and
229
// configurationAttributeNameBuffer
230
configurationNameBuffer = new StringBuffer JavaDoc();
231                     configurationAttributeNameBuffer = new StringBuffer JavaDoc();
232
233                 } else if (
234                         nextToken.equals(TokenReplacer.ATTRIBUTE_DELIMETER)) {
235
236                     if (workingBuffer != configurationNameBuffer) {
237                         // this means that we found a delimeter in the
238
// wrong context
239
throw new TokenReplacementException(
240                             this.getClass(),
241                             "Found a "
242                                 + TokenReplacer.ATTRIBUTE_DELIMETER
243                                 + " in a bad context within ["
244                                 + this.data
245                                 + "]");
246                     }
247                     // found the configuration name, now start looking for
248
// the configuration attribute, start appending to
249
// configurationAttributeNameBuffer to generate the
250
// configuration attribute name
251
workingBuffer = configurationAttributeNameBuffer;
252
253                 } else {
254                     // the token is not a delimeter
255
// append nextToken to the workingBuffer
256
workingBuffer.append(nextToken);
257                 }
258             }
259
260             this.replacedValue = replacedValueBuffer.toString();
261         }
262
263         if (log.isDebugEnabled()) {
264             log.debug("Replacing configuration token ["
265                 + this.data
266                 + "] with ["
267                 + this.replacedValue
268                 + "]");
269         }
270
271         return this.replacedValue;
272     }
273
274     /**
275      * Looks up a Configuration value from the Config using token replacement.
276      *
277      * @param configName name of the configuration to lookup
278      * @param attributeName name of the attribute to retreive from config
279      * @return the String value of the configuration
280      * @throws TokenReplacementException indicates an error retreiving
281      * the value from the configuration
282      */

283     private String JavaDoc lookupConfigurationValue(
284         String JavaDoc configName,
285         String JavaDoc attributeName)
286         throws TokenReplacementException {
287
288         String JavaDoc attributeValue;
289
290         if ((attributeName == null) || (attributeName.equals(""))) {
291             // Handle specially as a system property
292
attributeValue =
293                 BootStrapper.getInstance().getDeploymentProperty(configName);
294         } else {
295             Configuration config =
296                 Config.getInstance().fetchConfiguration(configName);
297
298             if (config instanceof PropertyConfiguration) {
299
300                 // weakly type configuration
301
attributeValue =
302                     ((PropertyConfiguration) config).getProperty(attributeName);
303
304             } else {
305                 // strongly typed configuration, use BeanUtil to extract value
306
try {
307                     // According the java bean specification, the first letter
308
// of a bean property must be lowercase.
309
String JavaDoc beanPropertyName =
310                         attributeName.substring(0, 1).toLowerCase()
311                         + attributeName.substring(1);
312
313                     Object JavaDoc attributeObject =
314                         BeanUtil.getObjectAttribute(config, beanPropertyName);
315
316                     if (attributeObject == null) {
317                         attributeValue = null;
318                     } else {
319                         // use the type service to get the String value
320
attributeValue =
321                             ConfigurationTypeServiceFactory.getInstance().
322                             toString(attributeObject.getClass(),
323                                      attributeObject);
324                     }
325
326
327                 } catch (IllegalArgumentException JavaDoc iae) {
328                     throw new TokenReplacementException(
329                         this.getClass(),
330                         "Exception replacing tokens in configuration: "
331                             + "Single attribute ["
332                             + attributeName
333                             + "] not found "
334                             + "in configuration ["
335                             + configName
336                             + "]",
337                         iae);
338
339                 } catch (NoSuchMethodException JavaDoc nsme) {
340                     throw new TokenReplacementException(
341                         this.getClass(),
342                         "Exception replacing tokens in configuration: "
343                             + "Attribute ["
344                             + attributeName
345                             + "] not found "
346                             + "in configuration ["
347                             + configName
348                             + "]",
349                         nsme);
350
351                 } catch (InvocationTargetException JavaDoc ite) {
352                     throw new TokenReplacementException(
353                         this.getClass(),
354                         "Exception replacing tokens in configuration: "
355                             + "Attribute ["
356                             + attributeName
357                             + "] not found "
358                             + "in configuration ["
359                             + configName
360                             + "]",
361                         ite.getTargetException());
362
363                 } catch (IllegalAccessException JavaDoc iae) {
364                     throw new TokenReplacementException(
365                         this.getClass(),
366                         "Exception replacing tokens in configuration: "
367                             + "Attribute ["
368                             + attributeName
369                             + "] not found "
370                             + "in configuration ["
371                             + configName
372                             + "]",
373                         iae);
374
375                 }
376             }
377         }
378
379         if (attributeValue == null) {
380             String JavaDoc message;
381             if ((attributeName == null) || (attributeName.equals(""))) {
382                 message =
383                     "Deployment Property not found: ["
384                     + configName
385                     + "]";
386
387             } else {
388                 message =
389                     "Configuration attribute not found: "
390                         + "ConfigurationDocument name ["
391                         + configName
392                         + "] attribute name ["
393                         + attributeName
394                         + "]";
395             }
396
397             throw new TokenReplacementException(this.getClass(),
398                 "Error replacing tokens in configuration: " + message);
399         }
400
401         return attributeValue;
402     }
403 }
Popular Tags