KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > hivemind > impl > SymbolExpanderImpl


1 // Copyright 2004, 2005 The Apache Software Foundation
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15 package org.apache.hivemind.impl;
16
17 import java.util.Iterator JavaDoc;
18 import java.util.List JavaDoc;
19
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import org.apache.hivemind.ErrorHandler;
23 import org.apache.hivemind.Location;
24 import org.apache.hivemind.SymbolExpander;
25 import org.apache.hivemind.SymbolSource;
26 import org.apache.hivemind.order.Orderer;
27
28 /**
29  * A simple parser used to identify symbols in a string and expand them via a
30  * {@link org.apache.hivemind.SymbolSource}.
31  *
32  * @author Howard Lewis Ship
33  */

34 public class SymbolExpanderImpl implements SymbolExpander
35 {
36     private static final Log LOG = LogFactory.getLog(SymbolExpanderImpl.class);
37
38     private static final int STATE_START = 0;
39
40     private static final int STATE_DOLLAR = 1;
41
42     private static final int STATE_COLLECT_SYMBOL_NAME = 2;
43     
44     private ErrorHandler _errorHandler;
45
46     private SymbolSource[] _symbolSources;
47
48     private List JavaDoc _contributedSymbolSources;
49
50     public SymbolExpanderImpl(ErrorHandler handler, List JavaDoc symbolSourceContributions)
51     {
52         _errorHandler = handler;
53         _contributedSymbolSources = symbolSourceContributions;
54     }
55
56     public SymbolExpanderImpl(ErrorHandler handler, SymbolSource[] symbolSources)
57     {
58         _errorHandler = handler;
59         _symbolSources = symbolSources;
60     }
61     
62     private synchronized SymbolSource[] initContributedSymbolSources(List JavaDoc contributions)
63     {
64         SymbolSource[] symbolSources;
65         
66         Orderer o = new Orderer(LogFactory.getLog(SymbolExpander.class), _errorHandler, XmlImplMessages
67                 .symbolSourceContribution());
68
69         Iterator JavaDoc i = contributions.iterator();
70         while (i.hasNext())
71         {
72             SymbolSourceContribution c = (SymbolSourceContribution) i.next();
73
74             o.add(c, c.getName(), c.getPrecedingNames(), c.getFollowingNames());
75         }
76
77         List JavaDoc sources = o.getOrderedObjects();
78
79         int count = sources.size();
80
81         symbolSources = new SymbolSource[count];
82
83         for (int j = 0; j < count; j++)
84         {
85             SymbolSourceContribution c = (SymbolSourceContribution) sources.get(j);
86             symbolSources[j] = c.getSource();
87         }
88
89         return symbolSources;
90     }
91
92     public String JavaDoc valueForSymbol(String JavaDoc name)
93     {
94         if (_symbolSources == null && _contributedSymbolSources != null) {
95             // Load the contributions as late as possible since the
96
// parsing of the xml contributions will trigger a recursive call.
97
_symbolSources = initContributedSymbolSources(_contributedSymbolSources);
98             _contributedSymbolSources = null;
99         }
100         
101         for (int i = 0; i < _symbolSources.length; i++)
102         {
103             String JavaDoc value = _symbolSources[i].valueForSymbol(name);
104
105             if (value != null)
106                 return value;
107         }
108
109         return null;
110     }
111
112     /**
113      * @see org.apache.hivemind.SymbolExpander#expandSymbols(java.lang.String, org.apache.hivemind.Location)
114      */

115     public String JavaDoc expandSymbols(String JavaDoc text, Location location)
116     {
117         StringBuffer JavaDoc result = new StringBuffer JavaDoc(text.length());
118         char[] buffer = text.toCharArray();
119         int state = STATE_START;
120         int blockStart = 0;
121         int blockLength = 0;
122         int symbolStart = -1;
123         int symbolLength = 0;
124         int i = 0;
125         int braceDepth = 0;
126         boolean anySymbols = false;
127
128         while (i < buffer.length)
129         {
130             char ch = buffer[i];
131
132             switch (state)
133             {
134                 case STATE_START:
135
136                     if (ch == '$')
137                     {
138                         state = STATE_DOLLAR;
139                         i++;
140                         continue;
141                     }
142
143                     blockLength++;
144                     i++;
145                     continue;
146
147                 case STATE_DOLLAR:
148
149                     if (ch == '{')
150                     {
151                         state = STATE_COLLECT_SYMBOL_NAME;
152                         i++;
153
154                         symbolStart = i;
155                         symbolLength = 0;
156                         braceDepth = 1;
157
158                         continue;
159                     }
160
161                     // Any time two $$ appear, it is collapsed down to a single $,
162
// but the next character is passed through un-interpreted (even if it
163
// is a brace).
164

165                     if (ch == '$')
166                     {
167                         // This is effectively a symbol, meaning that the input string
168
// will not equal the output string.
169

170                         anySymbols = true;
171
172                         if (blockLength > 0)
173                             result.append(buffer, blockStart, blockLength);
174
175                         result.append(ch);
176
177                         i++;
178                         blockStart = i;
179                         blockLength = 0;
180                         state = STATE_START;
181
182                         continue;
183                     }
184
185                     // The '$' was just what it was, not the start of a ${} expression
186
// block, so include it as part of the static text block.
187

188                     blockLength++;
189
190                     state = STATE_START;
191                     continue;
192
193                 case STATE_COLLECT_SYMBOL_NAME:
194
195                     if (ch != '}')
196                     {
197                         if (ch == '{')
198                             braceDepth++;
199
200                         i++;
201                         symbolLength++;
202                         continue;
203                     }
204
205                     braceDepth--;
206
207                     if (braceDepth > 0)
208                     {
209                         i++;
210                         symbolLength++;
211                         continue;
212                     }
213
214                     // Hit the closing brace of a symbol.
215

216                     // Degenerate case: the string "${}".
217

218                     if (symbolLength == 0)
219                         blockLength += 3;
220
221                     // Append anything up to the start of the sequence (this is static
222
// text between symbol references).
223

224                     if (blockLength > 0)
225                         result.append(buffer, blockStart, blockLength);
226
227                     if (symbolLength > 0)
228                     {
229                         String JavaDoc variableName = text.substring(symbolStart, symbolStart
230                                 + symbolLength);
231
232                         result.append(expandSymbol(variableName, location));
233
234                         anySymbols = true;
235                     }
236
237                     i++;
238                     blockStart = i;
239                     blockLength = 0;
240
241                     // And drop into state start
242

243                     state = STATE_START;
244
245                     continue;
246             }
247
248         }
249
250         // If get this far without seeing any variables, then just pass
251
// the input back.
252

253         if (!anySymbols)
254             return text;
255
256         // OK, to handle the end. Couple of degenerate cases where
257
// a ${...} was incomplete, so we adust the block length.
258

259         if (state == STATE_DOLLAR)
260             blockLength++;
261
262         if (state == STATE_COLLECT_SYMBOL_NAME)
263             blockLength += symbolLength + 2;
264
265         if (blockLength > 0)
266             result.append(buffer, blockStart, blockLength);
267
268         return result.toString();
269     }
270
271     private String JavaDoc expandSymbol(String JavaDoc name, Location location)
272     {
273         String JavaDoc value = valueForSymbol(name);
274
275         if (value != null)
276             return value;
277
278         _errorHandler.error(LOG, XmlImplMessages.noSuchSymbol(name), location, null);
279
280         return "${" + name + "}";
281     }
282
283 }
Popular Tags