View Javadoc

1   package net.sf.jpkgmk.util;
2   
3   import java.util.ArrayList;
4   import java.util.Iterator;
5   import java.util.List;
6   import java.util.regex.Matcher;
7   import java.util.regex.Pattern;
8   
9   import net.sf.jpkgmk.DuplicateEntryException;
10  import net.sf.jpkgmk.PackageException;
11  import net.sf.jpkgmk.prototype.PrototypeEntry;
12  import net.sf.jpkgmk.prototype.PrototypeEntryCommandVariable;
13  
14  import org.apache.commons.logging.Log;
15  import org.apache.commons.logging.LogFactory;
16  
17  /**
18   * A variable map that holds key value pairs whereas the key is regarded as variable name.
19   * @author gommma (gommma AT users.sourceforge.net)
20   * @author Last changed by: $Author: gommma $
21   * @version $Revision: 2 $ $Date: 2008-08-20 21:14:19 +0200 (Mi, 20 Aug 2008) $
22   * @since 1.0
23   */
24  public class VariableMap implements VariableResolver
25  {
26  	private Log log = LogFactory.getLog(VariableMap.class);
27  	
28  	private List<PrototypeEntryCommandVariable> entryVariableList = new ArrayList<PrototypeEntryCommandVariable>();
29  	
30  	/**
31  	 * Creates a new, empty variable map
32  	 */
33  	public VariableMap()
34  	{
35  	}
36  	
37  	/**
38  	 * @see net.sf.jpkgmk.util.VariableResolver#expand(java.lang.String)
39  	 */
40  	public String expand(String evaluationString) {
41  		return expand(evaluationString, true);
42  	}
43  	
44  	/**
45  	 * Expands the given string so that all variables are expanded
46  	 * @param evaluationString
47  	 * @param expandInstallTimeVaribles
48  	 * @return
49  	 */
50  	String expand(String evaluationString, boolean expandInstallTimeVaribles) {
51  	
52  		if(evaluationString == null) {
53  			return null;
54  		}
55  		
56  		expandVariables();
57  		return expandString(evaluationString, expandInstallTimeVaribles);
58  	}
59  
60  
61  	
62  	private String expandString(String evaluationString, boolean expandInstallTimeVaribles) 
63  	{
64  		String result = evaluationString;
65  		// Search all variables to be replaced
66  		for (Iterator<PrototypeEntryCommandVariable> iterator = entryVariableList.iterator(); iterator.hasNext();) {
67  			PrototypeEntryCommandVariable entry = iterator.next();
68  			if(!entry.isBuildVariable() && !expandInstallTimeVaribles) {
69  				// skip
70  				log.debug("Skipping variable '" + entry + "' - is not a build variable");
71  				continue;
72  			}
73  			String key = entry.getKey();
74  			// Also expand the variable if necessary
75  			String value = entry.getExpandedValue() != null ? entry.getExpandedValue() : entry.getValue();
76  			
77  			result = replaceVars(result, "\\$" + key, value);
78  			result = replaceVars(result, "\\$\\{" + key + "\\}", value);
79  		}
80  		
81  		// Check if any of the variables could not be expanded - throw an exception if so
82  		return result;
83  	}
84  
85  	private void expandVariables() {
86  		for (Iterator<PrototypeEntryCommandVariable> iterator = entryVariableList.iterator(); iterator.hasNext();) {
87  			PrototypeEntryCommandVariable entry = iterator.next();
88  			String value = entry.getValue();
89  			value = expandString(value, true);
90  			entry.setExpandedValue(value);
91  		}
92  	}
93  
94  	private String replaceVars(String string, String key, String value) {
95  		String groupedRegexBeforeVars = "([.[^\\$]]{1}|^)"; // any character except the dollar sign
96  
97  		String patternString = groupedRegexBeforeVars + "(" + key + ")";
98  		Pattern pattern = Pattern.compile(patternString);
99  		
100 		try {
101 			Matcher matcher = pattern.matcher(string);
102 			// This is important for the case that the first sign of the given string is a '$' or a '^'.
103 			// If useAnchoringBounds=true the matcher would use '$' and '^' as anchors instead of simple strings.
104 			matcher.useAnchoringBounds(false);
105 			
106 			StringBuffer sb = new StringBuffer();
107 			while(matcher.find()) {
108 				String characterBeforeVar = matcher.group(1);
109 				matcher.appendReplacement(sb, characterBeforeVar + Matcher.quoteReplacement(value));
110 			}
111 			
112 			matcher.appendTail(sb);
113 			return sb.toString();
114 		}
115 		catch(Exception e) {
116 			throw new PackageException("Exception while replacing variables in string '" + string + "'. key=" + key + ", value=" + value + ". pattern=" + patternString, e);
117 		}
118 	}
119 
120 
121 	/**
122 	 * @return Returns the current size of this variable map. Effectively the number of variables stored in this map.
123 	 */
124 	public int size() {
125 		return this.entryVariableList.size();
126 	}
127 	
128 	public void registerInVariablesMap(PrototypeEntry entry) {
129 
130 		// Only add the entries of type "variable" type to the variable map
131 		if(entry instanceof PrototypeEntryCommandVariable) {
132 			PrototypeEntryCommandVariable newVarEntry = (PrototypeEntryCommandVariable)entry;
133 			
134 			PrototypeEntryCommandVariable existingEntry = findEntryWithKey(newVarEntry.getKey());
135 			if(existingEntry != null) {
136 				throw new DuplicateEntryException("The VariableMap already contains an entry with the key '" + newVarEntry.getKey() + "' of the given one: existing='" + existingEntry + "', given='" + entry + "'.");
137 			}
138 			else {
139 				boolean success = entryVariableList.add(newVarEntry);
140 				if(!success) {
141 					throw new IllegalStateException("Could not add the variable '" + entry + "' to the variable map");
142 				}
143 			}
144 		}
145 		else {
146 			log.debug("The entry is no variable and will not be added to the variables store. Entry=" + entry);
147 		}
148 	}
149 
150 	private PrototypeEntryCommandVariable findEntryWithKey(String key) {
151 		for (Iterator<PrototypeEntryCommandVariable> iterator = entryVariableList.iterator(); iterator.hasNext();) {
152 			PrototypeEntryCommandVariable varEntry = iterator.next();
153 			if(varEntry.getKey().equals(key)) {
154 				return varEntry;
155 			}
156 		}
157 		return null;
158 	}
159 
160 	public void unregisterFromVariablesMap(PrototypeEntry entry) {
161 		
162 		if(entry instanceof PrototypeEntryCommandVariable) {
163 			PrototypeEntryCommandVariable newVarEntry = (PrototypeEntryCommandVariable)entry;
164 			if(!entryVariableList.contains(newVarEntry)) {
165 				throw new IllegalArgumentException("The entry '" + newVarEntry + "' was not found in the VariableMap.");
166 			}
167 			boolean success = entryVariableList.remove(newVarEntry);
168 			if(!success) {
169 				throw new IllegalStateException("Could not remove entry '" + entry + "' from variable list for a unknown reason.");
170 			}
171 		}
172 		else {
173 			log.debug("The entry is no variable and will not be added to the variables store. Entry=" + entry);
174 		}
175 		
176 	}
177 	
178 	public void addVariable(String key, String value) {
179 		this.entryVariableList.add(new PrototypeEntryCommandVariable(key, value));
180 	}
181 	
182 	
183 	/**
184 	 * @param variableName
185 	 * @return Returns the unexpanded value of the given variable name
186 	 */
187 	public String getVariableValue(String variableName)
188 	{
189 		return getVariableValue(variableName, false);
190 	}
191 	
192 	public String getVariableValue(String variableName, boolean expandVariable)
193 	{
194 		if (variableName == null) {
195 			throw new NullPointerException("The parameter 'variableName' must not be null");
196 		}
197 		for (Iterator<PrototypeEntryCommandVariable> iterator = entryVariableList.iterator(); iterator.hasNext();) {
198 			PrototypeEntryCommandVariable entry = iterator.next();
199 			if(entry.getKey().equals(variableName)) {
200 				String value = entry.getValue();
201 				if(expandVariable) {
202 					value = expand(value);
203 				}
204 				return value;
205 			}
206 		}
207 		// Not found
208 		return null;
209 	}
210 
211 	public static boolean containsVariable(String stringToCheck) {
212 		return stringToCheck.contains("$");
213 	}
214 
215 	
216 }