KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > variables > StringSubstitutionEngine


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.variables;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashSet JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.List JavaDoc;
17 import java.util.Stack JavaDoc;
18 import org.eclipse.core.runtime.CoreException;
19 import org.eclipse.core.runtime.IStatus;
20 import org.eclipse.core.runtime.Status;
21 import org.eclipse.core.variables.IDynamicVariable;
22 import org.eclipse.core.variables.IStringVariableManager;
23 import org.eclipse.core.variables.IValueVariable;
24 import org.eclipse.core.variables.VariablesPlugin;
25 import org.eclipse.osgi.util.NLS;
26
27 /**
28  * Performs string substitution for context and value variables.
29  */

30 public class StringSubstitutionEngine {
31     
32     // delimiters
33
private static final String JavaDoc VARIABLE_START = "${"; //$NON-NLS-1$
34
private static final char VARIABLE_END = '}';
35     private static final char VARIABLE_ARG = ':';
36     // parsing states
37
private static final int SCAN_FOR_START = 0;
38     private static final int SCAN_FOR_END = 1;
39     
40     /**
41      * Resulting string
42      */

43     private StringBuffer JavaDoc fResult;
44     
45     /**
46      * Whether substitutions were performed
47      */

48     private boolean fSubs;
49     
50     /**
51      * Stack of variables to resolve
52      */

53     private Stack JavaDoc fStack;
54     
55     class VariableReference {
56         
57         // the text inside the variable reference
58
private StringBuffer JavaDoc fText;
59         
60         public VariableReference() {
61             fText = new StringBuffer JavaDoc();
62         }
63         
64         public void append(String JavaDoc text) {
65             fText.append(text);
66         }
67         
68         public String JavaDoc getText() {
69             return fText.toString();
70         }
71     
72     }
73     
74     /**
75      * Performs recursive string substitution and returns the resulting string.
76      *
77      * @param expression expression to resolve
78      * @param reportUndefinedVariables whether to report undefined variables as an error
79      * @param manager registry of variables
80      * @return the resulting string with all variables recursively
81      * substituted
82      * @exception CoreException if unable to resolve a referenced variable or if a cycle exists
83      * in referenced variables
84      */

85     public String JavaDoc performStringSubstitution(String JavaDoc expression, boolean reportUndefinedVariables, boolean resolveVariables, IStringVariableManager manager) throws CoreException {
86         substitute(expression, reportUndefinedVariables, resolveVariables, manager);
87         List JavaDoc resolvedVariableSets = new ArrayList JavaDoc();
88         while (fSubs) {
89             HashSet JavaDoc resolved = substitute(fResult.toString(), reportUndefinedVariables, true, manager);
90             
91             for(int i=resolvedVariableSets.size()-1; i>=0; i--) {
92                 
93                 HashSet JavaDoc prevSet = (HashSet JavaDoc)resolvedVariableSets.get(i);
94
95                 if (prevSet.equals(resolved)) {
96                     HashSet JavaDoc conflictingSet = new HashSet JavaDoc();
97                     for (; i<resolvedVariableSets.size(); i++)
98                         conflictingSet.addAll((HashSet JavaDoc)resolvedVariableSets.get(i));
99                     
100                     StringBuffer JavaDoc problemVariableList = new StringBuffer JavaDoc();
101                     for (Iterator JavaDoc it=conflictingSet.iterator(); it.hasNext(); ) {
102                         problemVariableList.append(it.next().toString());
103                         problemVariableList.append(", "); //$NON-NLS-1$
104
}
105                     problemVariableList.setLength(problemVariableList.length()-2); //truncate the last ", "
106
throw new CoreException(new Status(IStatus.ERROR, VariablesPlugin.getUniqueIdentifier(), VariablesPlugin.REFERENCE_CYCLE_ERROR, NLS.bind(VariablesMessages.StringSubstitutionEngine_4, new String JavaDoc[]{problemVariableList.toString()}), null));
107                 }
108             }
109             
110             resolvedVariableSets.add(resolved);
111         }
112         return fResult.toString();
113     }
114     
115     /**
116      * Performs recursive string validation to ensure that all of the variables
117      * contained in the expression exist
118      * @param expression expression to validate
119      * @param manager registry of variables
120      * @exception CoreException if a referenced variable does not exist or if a cycle exists
121      * in referenced variables
122      */

123     public void validateStringVariables(String JavaDoc expression, IStringVariableManager manager) throws CoreException {
124         performStringSubstitution(expression, true, false, manager);
125     }
126     
127     /**
128      * Makes a substitution pass of the given expression returns a Set of the variables that were resolved in this
129      * pass
130      *
131      * @param expression source expression
132      * @param reportUndefinedVariables whether to report undefined variables as an error
133      * @param resolveVariables whether to resolve the value of any variables
134      * @exception CoreException if unable to resolve a variable
135      */

136     private HashSet JavaDoc substitute(String JavaDoc expression, boolean reportUndefinedVariables, boolean resolveVariables, IStringVariableManager manager) throws CoreException {
137         fResult = new StringBuffer JavaDoc(expression.length());
138         fStack = new Stack JavaDoc();
139         fSubs = false;
140         
141         HashSet JavaDoc resolvedVariables = new HashSet JavaDoc();
142
143         int pos = 0;
144         int state = SCAN_FOR_START;
145         while (pos < expression.length()) {
146             switch (state) {
147                 case SCAN_FOR_START:
148                     int start = expression.indexOf(VARIABLE_START, pos);
149                     if (start >= 0) {
150                         int length = start - pos;
151                         // copy non-variable text to the result
152
if (length > 0) {
153                             fResult.append(expression.substring(pos, start));
154                         }
155                         pos = start + 2;
156                         state = SCAN_FOR_END;
157
158                         fStack.push(new VariableReference());
159                     } else {
160                         // done - no more variables
161
fResult.append(expression.substring(pos));
162                         pos = expression.length();
163                     }
164                     break;
165                 case SCAN_FOR_END:
166                     // be careful of nested variables
167
start = expression.indexOf(VARIABLE_START, pos);
168                     int end = expression.indexOf(VARIABLE_END, pos);
169                     if (end < 0) {
170                         // variables are not completed
171
VariableReference tos = (VariableReference)fStack.peek();
172                         tos.append(expression.substring(pos));
173                         pos = expression.length();
174                     } else {
175                         if (start >= 0 && start < end) {
176                             // start of a nested variable
177
int length = start - pos;
178                             if (length > 0) {
179                                 VariableReference tos = (VariableReference)fStack.peek();
180                                 tos.append(expression.substring(pos, start));
181                             }
182                             pos = start + 2;
183                             fStack.push(new VariableReference());
184                         } else {
185                             // end of variable reference
186
VariableReference tos = (VariableReference)fStack.pop();
187                             String JavaDoc substring = expression.substring(pos, end);
188                             tos.append(substring);
189                             resolvedVariables.add(substring);
190                             
191                             pos = end + 1;
192                             String JavaDoc value= resolve(tos, reportUndefinedVariables, resolveVariables, manager);
193                             if (value == null) {
194                                 value = ""; //$NON-NLS-1$
195
}
196                             if (fStack.isEmpty()) {
197                                 // append to result
198
fResult.append(value);
199                                 state = SCAN_FOR_START;
200                             } else {
201                                 // append to previous variable
202
tos = (VariableReference)fStack.peek();
203                                 tos.append(value);
204                             }
205                         }
206                     }
207                     break;
208             }
209         }
210         // process incomplete variable references
211
while (!fStack.isEmpty()) {
212             VariableReference tos = (VariableReference)fStack.pop();
213             if (fStack.isEmpty()) {
214                 fResult.append(VARIABLE_START);
215                 fResult.append(tos.getText());
216             } else {
217                 VariableReference var = (VariableReference)fStack.peek();
218                 var.append(VARIABLE_START);
219                 var.append(tos.getText());
220             }
221         }
222         
223
224         return resolvedVariables;
225     }
226
227     /**
228      * Resolve and return the value of the given variable reference,
229      * possibly <code>null</code>.
230      *
231      * @param var
232      * @param reportUndefinedVariables whether to report undefined variables as
233      * an error
234      * @param resolveVariables whether to resolve the variables value or just to validate that this variable is valid
235      * @param manager variable registry
236      * @return variable value, possibly <code>null</code>
237      * @exception CoreException if unable to resolve a value
238      */

239     private String JavaDoc resolve(VariableReference var, boolean reportUndefinedVariables, boolean resolveVariables, IStringVariableManager manager) throws CoreException {
240         String JavaDoc text = var.getText();
241         int pos = text.indexOf(VARIABLE_ARG);
242         String JavaDoc name = null;
243         String JavaDoc arg = null;
244         if (pos > 0) {
245             name = text.substring(0, pos);
246             pos++;
247             if (pos < text.length()) {
248                 arg = text.substring(pos);
249             }
250         } else {
251             name = text;
252         }
253         IValueVariable valueVariable = manager.getValueVariable(name);
254         if (valueVariable == null) {
255             IDynamicVariable dynamicVariable = manager.getDynamicVariable(name);
256             if (dynamicVariable == null) {
257                 // no variables with the given name
258
if (reportUndefinedVariables) {
259                     throw new CoreException(new Status(IStatus.ERROR, VariablesPlugin.getUniqueIdentifier(), VariablesPlugin.INTERNAL_ERROR, NLS.bind(VariablesMessages.StringSubstitutionEngine_3, new String JavaDoc[]{name}), null));
260                 }
261                 // leave as is
262
return getOriginalVarText(var);
263             }
264             
265             if (resolveVariables) {
266                 fSubs = true;
267                 return dynamicVariable.getValue(arg);
268             }
269             //leave as is
270
return getOriginalVarText(var);
271         }
272         
273         if (arg == null) {
274             if (resolveVariables) {
275                 fSubs = true;
276                 return valueVariable.getValue();
277             }
278             //leave as is
279
return getOriginalVarText(var);
280         }
281         // error - an argument specified for a value variable
282
throw new CoreException(new Status(IStatus.ERROR, VariablesPlugin.getUniqueIdentifier(), VariablesPlugin.INTERNAL_ERROR, NLS.bind(VariablesMessages.StringSubstitutionEngine_4, new String JavaDoc[]{valueVariable.getName()}), null));
283     }
284
285     private String JavaDoc getOriginalVarText(VariableReference var) {
286         StringBuffer JavaDoc res = new StringBuffer JavaDoc(var.getText());
287         res.insert(0, VARIABLE_START);
288         res.append(VARIABLE_END);
289         return res.toString();
290     }
291 }
292
Popular Tags