2009/04/15 - Apache HiveMind has been retired.

For more information, please explore the Attic.

Clover coverage report - Code Coverage for hivemind release 1.2.1
Coverage timestamp: Fri Feb 10 2006 16:33:43 PST
file stats: LOC: 227   Methods: 3
NCLOC: 123   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
SymbolExpander.java 100% 100% 100% 100%
coverage
 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 org.apache.commons.logging.Log;
 18    import org.apache.commons.logging.LogFactory;
 19    import org.apache.hivemind.ErrorHandler;
 20    import org.apache.hivemind.Location;
 21    import org.apache.hivemind.SymbolSource;
 22   
 23    /**
 24    * A simple parser used to identify symbols in a string and expand them via a
 25    * {@link org.apache.hivemind.SymbolSource}.
 26    *
 27    * @author Howard Lewis Ship
 28    */
 29    public class SymbolExpander
 30    {
 31    private ErrorHandler _errorHandler;
 32   
 33    private SymbolSource _source;
 34   
 35  155 public SymbolExpander(ErrorHandler handler, SymbolSource source)
 36    {
 37  155 _errorHandler = handler;
 38  155 _source = source;
 39    }
 40   
 41    private static final Log LOG = LogFactory.getLog(SymbolExpander.class);
 42   
 43    private static final int STATE_START = 0;
 44   
 45    private static final int STATE_DOLLAR = 1;
 46   
 47    private static final int STATE_COLLECT_SYMBOL_NAME = 2;
 48   
 49    /**
 50    * <p>
 51    * Identifies symbols in the text and expands them, using the {@link SymbolSource}. Returns the
 52    * modified text. May return text if text does not contain any symbols.
 53    *
 54    * @param text
 55    * the text to scan
 56    * @param location
 57    * the location to report errors (undefined symbols)
 58    */
 59  7157 public String expandSymbols(String text, Location location)
 60    {
 61  7157 StringBuffer result = new StringBuffer(text.length());
 62  7157 char[] buffer = text.toCharArray();
 63  7157 int state = STATE_START;
 64  7157 int blockStart = 0;
 65  7157 int blockLength = 0;
 66  7157 int symbolStart = -1;
 67  7157 int symbolLength = 0;
 68  7157 int i = 0;
 69  7157 int braceDepth = 0;
 70  7157 boolean anySymbols = false;
 71   
 72  7157 while (i < buffer.length)
 73    {
 74  132237 char ch = buffer[i];
 75   
 76  132237 switch (state)
 77    {
 78  132135 case STATE_START:
 79   
 80  132135 if (ch == '$')
 81    {
 82  18 state = STATE_DOLLAR;
 83  18 i++;
 84  18 continue;
 85    }
 86   
 87  132117 blockLength++;
 88  132117 i++;
 89  132117 continue;
 90   
 91  17 case STATE_DOLLAR:
 92   
 93  17 if (ch == '{')
 94    {
 95  14 state = STATE_COLLECT_SYMBOL_NAME;
 96  14 i++;
 97   
 98  14 symbolStart = i;
 99  14 symbolLength = 0;
 100  14 braceDepth = 1;
 101   
 102  14 continue;
 103    }
 104   
 105    // Any time two $$ appear, it is collapsed down to a single $,
 106    // but the next character is passed through un-interpreted (even if it
 107    // is a brace).
 108   
 109  3 if (ch == '$')
 110    {
 111    // This is effectively a symbol, meaning that the input string
 112    // will not equal the output string.
 113   
 114  2 anySymbols = true;
 115   
 116  2 if (blockLength > 0)
 117  1 result.append(buffer, blockStart, blockLength);
 118   
 119  2 result.append(ch);
 120   
 121  2 i++;
 122  2 blockStart = i;
 123  2 blockLength = 0;
 124  2 state = STATE_START;
 125   
 126  2 continue;
 127    }
 128   
 129    // The '$' was just what it was, not the start of a ${} expression
 130    // block, so include it as part of the static text block.
 131   
 132  1 blockLength++;
 133   
 134  1 state = STATE_START;
 135  1 continue;
 136   
 137  85 case STATE_COLLECT_SYMBOL_NAME:
 138   
 139  85 if (ch != '}')
 140    {
 141  71 if (ch == '{')
 142  1 braceDepth++;
 143   
 144  71 i++;
 145  71 symbolLength++;
 146  71 continue;
 147    }
 148   
 149  14 braceDepth--;
 150   
 151  14 if (braceDepth > 0)
 152    {
 153  1 i++;
 154  1 symbolLength++;
 155  1 continue;
 156    }
 157   
 158    // Hit the closing brace of a symbol.
 159   
 160    // Degenerate case: the string "${}".
 161   
 162  13 if (symbolLength == 0)
 163  1 blockLength += 3;
 164   
 165    // Append anything up to the start of the sequence (this is static
 166    // text between symbol references).
 167   
 168  13 if (blockLength > 0)
 169  6 result.append(buffer, blockStart, blockLength);
 170   
 171  13 if (symbolLength > 0)
 172    {
 173  12 String variableName = text.substring(symbolStart, symbolStart
 174    + symbolLength);
 175   
 176  12 result.append(expandSymbol(variableName, location));
 177   
 178  12 anySymbols = true;
 179    }
 180   
 181  13 i++;
 182  13 blockStart = i;
 183  13 blockLength = 0;
 184   
 185    // And drop into state start
 186   
 187  13 state = STATE_START;
 188   
 189  13 continue;
 190    }
 191   
 192    }
 193   
 194    // If get this far without seeing any variables, then just pass
 195    // the input back.
 196   
 197  7157 if (!anySymbols)
 198  7144 return text;
 199   
 200    // OK, to handle the end. Couple of degenerate cases where
 201    // a ${...} was incomplete, so we adust the block length.
 202   
 203  13 if (state == STATE_DOLLAR)
 204  1 blockLength++;
 205   
 206  13 if (state == STATE_COLLECT_SYMBOL_NAME)
 207  1 blockLength += symbolLength + 2;
 208   
 209  13 if (blockLength > 0)
 210  5 result.append(buffer, blockStart, blockLength);
 211   
 212  13 return result.toString();
 213    }
 214   
 215  12 private String expandSymbol(String name, Location location)
 216    {
 217  12 String value = _source.valueForSymbol(name);
 218   
 219  12 if (value != null)
 220  10 return value;
 221   
 222  2 _errorHandler.error(LOG, ImplMessages.noSuchSymbol(name), location, null);
 223   
 224  2 return "${" + name + "}";
 225    }
 226   
 227    }