KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > cruisecontrol > ProjectXMLHelper


1 /********************************************************************************
2  * CruiseControl, a Continuous Integration Toolkit
3  * Copyright (c) 2001, ThoughtWorks, Inc.
4  * 651 W Washington Ave. Suite 600
5  * Chicago, IL 60661 USA
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * + Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * + Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  *
20  * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
21  * names of its contributors may be used to endorse or promote
22  * products derived from this software without specific prior
23  * written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
29  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  ********************************************************************************/

37 package net.sourceforge.cruisecontrol;
38
39 import java.io.BufferedReader JavaDoc;
40 import java.io.File JavaDoc;
41 import java.io.FileNotFoundException JavaDoc;
42 import java.io.FileReader JavaDoc;
43 import java.io.IOException JavaDoc;
44 import java.util.HashMap JavaDoc;
45 import java.util.Iterator JavaDoc;
46 import java.util.Map JavaDoc;
47
48 import net.sourceforge.cruisecontrol.util.OSEnvironment;
49
50 import org.apache.log4j.Logger;
51 import org.jdom.Attribute;
52 import org.jdom.Element;
53 import org.jdom.output.XMLOutputter;
54
55 /**
56  * Instantiates a project from a JDOM Element. Supports the use of Ant-like patterns in
57  * attribute values that look like this: <code>${propertyname}</code>
58  */

59 public class ProjectXMLHelper implements ProjectHelper {
60     // TODO: extract out generic Helper methods
61
private static final Logger LOG = Logger.getLogger(ProjectXMLHelper.class);
62
63     private Map JavaDoc projectProperties;
64     private PluginRegistry projectPlugins;
65
66     public ProjectXMLHelper() {
67         this.projectProperties = new HashMap JavaDoc();
68         this.projectPlugins = PluginRegistry.createRegistry(PluginRegistry.loadDefaultPluginRegistry());
69     }
70
71     public ProjectXMLHelper(Map JavaDoc projectProperties, PluginRegistry projectPlugins) {
72         this.projectProperties = projectProperties;
73         this.projectPlugins = projectPlugins;
74     }
75
76     /**
77      * TODO: also check that instantiated class implements/extends correct interface/class
78      */

79     public Object JavaDoc configurePlugin(Element pluginElement, boolean skipChildElements)
80             throws CruiseControlException {
81         String JavaDoc name = pluginElement.getName();
82         PluginXMLHelper pluginHelper = new PluginXMLHelper(this);
83         String JavaDoc pluginName = pluginElement.getName();
84
85         LOG.debug("configuring plugin " + pluginElement.getName() + " skip " + skipChildElements);
86
87         if (projectPlugins.isPluginRegistered(pluginName)) {
88             Object JavaDoc pluginInstance = getConfiguredPlugin(pluginHelper, pluginElement.getName());
89             if (pluginInstance != null) { // preconfigured
90
return pluginHelper.configure(pluginElement, pluginInstance, skipChildElements);
91             }
92             return pluginHelper.configure(pluginElement, projectPlugins.getPluginClass(pluginName), skipChildElements);
93         } else {
94             throw new CruiseControlException("Unknown plugin for: <" + name + ">");
95         }
96     }
97
98
99     /**
100      * Get a [partially] configured plugin instance given its plugin name.
101      * @param pluginName
102      * @return <code>null</code> if the plugin was never configured.
103      * @throws CruiseControlException
104      * if the registered class cannot be loaded,
105      * if a property cannot be resolved,
106      * if the plugin configuration fails
107      */

108     Object JavaDoc getConfiguredPlugin(PluginXMLHelper pluginHelper, String JavaDoc pluginName) throws CruiseControlException {
109         final Class JavaDoc pluginClass = projectPlugins.getPluginClass(pluginName);
110         if (pluginClass == null) {
111             return null;
112         }
113         Object JavaDoc configuredPlugin = null;
114         Element pluginElement = projectPlugins.getPluginConfig(pluginName);
115         if (pluginElement != null) {
116             // FIXME
117
// the only reason we have to do this here
118
// is because the plugins registered in the ROOT registry have not had their properties parsed.
119
// See CruiseControlController.addPluginsToRootRegistry
120
parsePropertiesInElement(pluginElement);
121             configuredPlugin = pluginHelper.configure(pluginElement, pluginClass, false);
122         }
123         return configuredPlugin;
124     }
125
126     /**
127      * Recurses through an Element tree, substituting resolved values
128      * for any property macros.
129      *
130      * @param element The Element to parse
131      *
132      * @throws CruiseControlException if a property cannot be resolved
133      */

134     private void parsePropertiesInElement(Element element) throws CruiseControlException {
135         parsePropertiesInElement(element, this.projectProperties, CruiseControlConfig.FAIL_UPON_MISSING_PROPERTY);
136     }
137
138
139
140     /**
141      * Registers one or more properties as defined in a property element.
142      *
143      * @param propertyElement The element from which we will register properties
144      * @throws CruiseControlException
145      */

146     public static void registerProperty(Map JavaDoc props, Element propertyElement,
147                                          boolean failIfMissing) throws CruiseControlException {
148         // Determine which attributes were set in the element
149
String JavaDoc fileName = parsePropertiesInString(props, propertyElement.getAttributeValue("file"),
150                                                   failIfMissing);
151         String JavaDoc environment = parsePropertiesInString(props,
152                                                      propertyElement.getAttributeValue("environment"),
153                                                      failIfMissing);
154         String JavaDoc propName = parsePropertiesInString(props, propertyElement.getAttributeValue("name"),
155                                                   failIfMissing);
156         String JavaDoc propValue = propertyElement.getAttributeValue("value");
157         String JavaDoc toUpperValue = parsePropertiesInString(props,
158                                                       propertyElement.getAttributeValue("toupper"),
159                                                       failIfMissing);
160         boolean toupper = "true".equalsIgnoreCase(toUpperValue);
161
162         // If the file attribute was set, try to read properties
163
// from the given filename.
164
if (fileName != null && fileName.trim().length() > 0) {
165             File JavaDoc file = new File JavaDoc(fileName);
166             // FIXME add exists check.
167
try {
168                 BufferedReader JavaDoc reader = new BufferedReader JavaDoc(new FileReader JavaDoc(file));
169                 // Read the file line by line, expanding macros
170
// as we go. We must do this manually to preserve the
171
// order of the properties.
172
String JavaDoc line;
173                 while ((line = reader.readLine()) != null) {
174                     line = line.trim();
175                     if (line.length() == 0 || line.charAt(0) == '#') {
176                         continue;
177                     }
178                     int index = line.indexOf('=');
179                     if (index < 0) {
180                         continue;
181                     }
182                     String JavaDoc parsedName
183                         = parsePropertiesInString(props, line.substring(0, index).trim(), failIfMissing);
184                     String JavaDoc parsedValue
185                         = parsePropertiesInString(props, line.substring(index + 1).trim(), failIfMissing);
186                     setProperty(props, parsedName, parsedValue);
187                 }
188                 reader.close();
189             } catch (FileNotFoundException JavaDoc e) {
190                 throw new CruiseControlException(
191                         "Could not load properties from file \"" + fileName
192                                 + "\". The file does not exist", e);
193             } catch (IOException JavaDoc e) {
194                 throw new CruiseControlException(
195                         "Could not load properties from file \"" + fileName
196                                 + "\".", e);
197             }
198         } else if (environment != null) {
199             // Load the environment into the project's properties
200
Iterator JavaDoc variables = new OSEnvironment().getEnvironment().iterator();
201             while (variables.hasNext()) {
202                 String JavaDoc line = (String JavaDoc) variables.next();
203                 int index = line.indexOf('=');
204                 if (index < 0) {
205                     continue;
206                 }
207                 // If the toupper attribute was set, upcase the variables
208
StringBuffer JavaDoc name = new StringBuffer JavaDoc(environment);
209                 name.append(".");
210                 if (toupper) {
211                     name.append(line.substring(0, index).toUpperCase());
212                 } else {
213                     name.append(line.substring(0, index));
214                 }
215                 String JavaDoc parsedValue = parsePropertiesInString(props, line.substring(index + 1), failIfMissing);
216                 setProperty(props, name.toString(), parsedValue);
217             }
218         } else {
219             // Try to get a name value pair
220
if (propName == null) {
221                 throw new CruiseControlException("Bad property definition - "
222                         + new XMLOutputter().outputString(propertyElement));
223             }
224             if (propValue == null) {
225                 throw new CruiseControlException(
226                         "No value provided for property \"" + propName + "\" - "
227                         + new XMLOutputter().outputString(propertyElement));
228             }
229             String JavaDoc parsedValue = parsePropertiesInString(props, propValue, failIfMissing);
230             setProperty(props, propName, parsedValue);
231         }
232     }
233
234     // FIXME Helper extract ?
235
private static void setProperty(Map JavaDoc props, String JavaDoc name, String JavaDoc parsedValue) {
236         LOG.debug("Setting property \"" + name + "\" to \"" + parsedValue + "\".");
237         props.put(name, parsedValue);
238     }
239
240
241     // FIXME Helper extract ?
242
/**
243      * Parses a string by replacing all occurences of a property macro with
244      * the resolved value of the property. Nested macros are allowed - the
245      * inner most macro will be resolved first, moving out from there.
246      *
247      * @param string The string to be parsed
248      * @return The parsed string
249      * @throws CruiseControlException if a property cannot be resolved
250      */

251     static String JavaDoc parsePropertiesInString(Map JavaDoc props, String JavaDoc string,
252                                           boolean failIfMissing) throws CruiseControlException {
253         if (string != null) {
254             int startIndex = string.indexOf("${");
255             if (startIndex != -1) {
256                 int openedBrackets = 1;
257                 int lastStartIndex = startIndex + 2;
258                 int endIndex;
259                 do {
260                     endIndex = string.indexOf("}", lastStartIndex);
261                     int otherStartIndex = string.indexOf("${", lastStartIndex);
262                     if (otherStartIndex != -1 && otherStartIndex < endIndex) {
263                         openedBrackets++;
264                         lastStartIndex = otherStartIndex + 2;
265                     } else {
266                         openedBrackets--;
267                         if (openedBrackets == 0) {
268                             break;
269                         }
270                         lastStartIndex = endIndex + 1;
271                     }
272                 } while (true);
273                 if (endIndex < startIndex + 2) {
274                     throw new CruiseControlException("Unclosed brackets in " + string);
275                 }
276                 String JavaDoc property = string.substring(startIndex + 2, endIndex);
277                 // not necessarily resolved
278
String JavaDoc propertyName = parsePropertiesInString(props, property, failIfMissing);
279                 String JavaDoc value = "".equals(propertyName) ? "" : (String JavaDoc) props.get(propertyName);
280                 if (value == null) {
281                     if (failIfMissing) {
282                         throw new CruiseControlException("Property \"" + propertyName
283                                 + "\" is not defined. Please check the order in which you have used your properties.");
284                     } else {
285                         // we don't resolve missing properties
286
value = "${" + propertyName + "}";
287                     }
288                 }
289                 LOG.debug("Replacing the string \"" + propertyName + "\" with \"" + value + "\".");
290                 string = string.substring(0, startIndex) + value
291                     + parsePropertiesInString(props, string.substring(endIndex + 1), failIfMissing);
292             }
293         }
294         return string;
295
296     }
297
298     // FIXME Helper extract ?
299
public static void parsePropertiesInElement(Element element,
300                                                 Map JavaDoc props,
301                                                 boolean failIfMissing)
302         throws CruiseControlException {
303
304         // Recurse through the element tree - depth first
305
for (Iterator JavaDoc children = element.getChildren().iterator(); children.hasNext(); ) {
306             parsePropertiesInElement((Element) children.next(), props, failIfMissing);
307         }
308
309         // Parse the attribute value strings
310
for (Iterator JavaDoc attributes = element.getAttributes().iterator(); attributes.hasNext(); ) {
311             Attribute attribute = (Attribute) attributes.next();
312             attribute.setValue(parsePropertiesInString(props, attribute.getValue(), failIfMissing));
313         }
314
315         // Parse the element's text
316
String JavaDoc text = element.getTextTrim();
317         if (text.length() > 0) {
318             element.setText(parsePropertiesInString(props, text, failIfMissing));
319         }
320     }
321 }
322
Popular Tags