KickJava   Java API By Example, From Geeks To Geeks.

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


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.util.ArrayList JavaDoc;
40 import java.util.Collection JavaDoc;
41 import java.util.HashMap JavaDoc;
42 import java.util.HashSet JavaDoc;
43 import java.util.Iterator JavaDoc;
44 import java.util.Map JavaDoc;
45 import java.util.Properties JavaDoc;
46 import java.util.Set JavaDoc;
47 import java.util.TreeMap JavaDoc;
48
49 import net.sourceforge.cruisecontrol.labelincrementers.DefaultLabelIncrementer;
50
51 import org.apache.log4j.Logger;
52 import org.jdom.Element;
53
54 /**
55  * A plugin that represents the whole XML config file.
56  * @author <a HREF="mailto:jerome@coffeebreaks.org">Jerome Lacoste</a>
57  */

58 public class CruiseControlConfig implements SelfConfiguringPlugin {
59     private static final Logger LOG = Logger.getLogger(CruiseControlConfig.class);
60
61     public static final String JavaDoc LABEL_INCREMENTER = "labelincrementer";
62
63     public static final boolean FAIL_UPON_MISSING_PROPERTY = false;
64     
65     private static final Set JavaDoc KNOWN_ROOT_CHILD_NAMES = new HashSet JavaDoc();
66     static {
67         KNOWN_ROOT_CHILD_NAMES.add("property");
68         KNOWN_ROOT_CHILD_NAMES.add("plugin");
69         KNOWN_ROOT_CHILD_NAMES.add("system");
70     }
71
72     // Unfortunately it seems like the commons-collection CompositeMap doesn't fit that role
73
// at least size is not implemented the way I want it.
74
// TODO is there a clean way to do without this?
75
static class MapWithParent implements Map JavaDoc {
76         private Map JavaDoc parent;
77         private Map JavaDoc thisMap;
78
79         MapWithParent(Map JavaDoc parent) {
80             this.parent = parent;
81             this.thisMap = new HashMap JavaDoc();
82         }
83
84         public int size() {
85             int size = thisMap.size();
86             if (parent != null) {
87                 Set JavaDoc keys = parent.keySet();
88                 for (Iterator JavaDoc iterator = keys.iterator(); iterator.hasNext();) {
89                     String JavaDoc key = (String JavaDoc) iterator.next();
90                     if (!thisMap.containsKey(key)) {
91                         size++;
92                     }
93                 }
94             }
95             return size;
96         }
97
98         public boolean isEmpty() {
99             boolean parentIsEmpty = parent == null || parent.isEmpty();
100             return parentIsEmpty && thisMap.isEmpty();
101         }
102
103         public boolean containsKey(Object JavaDoc key) {
104             return thisMap.containsKey(key)
105                 || (parent != null && parent.containsKey(key));
106         }
107
108         public boolean containsValue(Object JavaDoc value) {
109             return thisMap.containsValue(value)
110                 || (parent != null && parent.containsValue(value));
111         }
112
113         public Object JavaDoc get(Object JavaDoc key) {
114             Object JavaDoc value = thisMap.get(key);
115             if (value == null && parent != null) {
116                 value = parent.get(key);
117             }
118             return value;
119         }
120
121         public Object JavaDoc put(Object JavaDoc o, Object JavaDoc o1) {
122             return thisMap.put(o, o1);
123         }
124
125         public Object JavaDoc remove(Object JavaDoc key) {
126             throw new UnsupportedOperationException JavaDoc("'remove' not supported on MapWithParent");
127         }
128
129         public void putAll(Map JavaDoc map) {
130             thisMap.putAll(map);
131         }
132
133         public void clear() {
134             throw new UnsupportedOperationException JavaDoc("'clear' not supported on MapWithParent");
135         }
136
137         public Set JavaDoc keySet() {
138             Set JavaDoc keys = new HashSet JavaDoc(thisMap.keySet());
139             if (parent != null) {
140                 keys.addAll(parent.keySet());
141             }
142             return keys;
143         }
144
145         public Collection JavaDoc values() {
146             throw new UnsupportedOperationException JavaDoc("not implemented");
147             /* we have to support the Map contract. Back the returned values. Mmmmm */
148             /*
149             Collection values = thisMap.values();
150             if (parent != null) {
151                 Set keys = parent.keySet();
152                 List parentValues = new ArrayList();
153                 for (Iterator iterator = keys.iterator(); iterator.hasNext();) {
154                     String key = (String) iterator.next();
155                     if (! thisMap.containsKey(key)) {
156                         parentValues.add(parent.get(key));
157                     }
158                 }
159             }
160             return values;
161             */

162         }
163
164         public Set JavaDoc entrySet() {
165             Set JavaDoc entries = new HashSet JavaDoc(thisMap.entrySet());
166             if (parent != null) {
167                 entries.addAll(parent.entrySet());
168             }
169             return entries;
170         }
171     }
172
173     private Map JavaDoc rootProperties = new HashMap JavaDoc();
174     private PluginRegistry rootPlugins = PluginRegistry.createRegistry();
175     private Map JavaDoc projectConfigs = new TreeMap JavaDoc(); // TODO: replace with LinkedHashMap when we drop 1.3 support
176
private ProjectNameSet projectNames = new ProjectNameSet(); // TODO: remove when we can use LinkedHashMap
177
// for test purposes only
178
private Map JavaDoc projectPluginRegistries = new TreeMap JavaDoc();
179
180     public CruiseControlConfig() {
181     }
182
183     // for testing... Could be used if we had an external property file.
184
CruiseControlConfig(Properties JavaDoc globalProperties) {
185         this.rootProperties.putAll(globalProperties);
186     }
187
188     public void configure(Element rootElement) throws CruiseControlException {
189         // parse properties and plugins first, so their order in the config file doesn't matter
190
for (Iterator JavaDoc i = rootElement.getChildren("property").iterator(); i.hasNext(); ) {
191             handleRootProperty((Element) i.next());
192         }
193         for (Iterator JavaDoc i = rootElement.getChildren("plugin").iterator(); i.hasNext(); ) {
194             handleRootPlugin((Element) i.next());
195         }
196         
197         // other childNodes must be projects or the <system> node
198
for (Iterator JavaDoc i = rootElement.getChildren().iterator(); i.hasNext(); ) {
199             Element childElement = (Element) i.next();
200             final String JavaDoc nodeName = childElement.getName();
201             if (isProject(nodeName)) {
202                 handleProject(childElement);
203             } else if (!KNOWN_ROOT_CHILD_NAMES.contains(nodeName)) {
204                 throw new CruiseControlException("cannot handle child of <" + nodeName + ">");
205             }
206         }
207     }
208
209     private boolean isProject(String JavaDoc nodeName) throws CruiseControlException {
210         return rootPlugins.isPluginRegistered(nodeName)
211             && ProjectConfig.class.isAssignableFrom(rootPlugins.getPluginClass(nodeName));
212     }
213
214     private void handleRootPlugin(Element pluginElement) throws CruiseControlException {
215         String JavaDoc pluginName = pluginElement.getAttributeValue("name");
216         if (pluginName == null) {
217             LOG.warn("Config contains plugin without a name-attribute, ignoring it");
218             return;
219         }
220         rootPlugins.register(pluginElement);
221     }
222
223     private void handleRootProperty(Element childElement) throws CruiseControlException {
224         ProjectXMLHelper.registerProperty(rootProperties, childElement, FAIL_UPON_MISSING_PROPERTY);
225     }
226
227     private void handleProject(Element projectElement) throws CruiseControlException {
228
229         String JavaDoc projectName = getProjectName(projectElement);
230
231         if (projectConfigs.containsKey(projectName)) {
232             final String JavaDoc duplicateEntriesMessage = "Duplicate entries in config file for project name " + projectName;
233             throw new CruiseControlException(duplicateEntriesMessage);
234         }
235
236         // property handling is a little bit dirty here.
237
// we have a set of properties mostly resolved in the rootProperties
238
// and a child set of properties
239
// it is possible that the rootProperties contain references to child properties
240
// in particular the project.name one
241
MapWithParent nonFullyResolvedProjectProperties = new MapWithParent(rootProperties);
242         // Register the project's name as a built-in property
243
LOG.debug("Setting property \"project.name\" to \"" + projectName + "\".");
244         nonFullyResolvedProjectProperties.put("project.name", projectName);
245         // Register any project specific properties
246
for (Iterator JavaDoc projProps = projectElement.getChildren("property").iterator(); projProps.hasNext(); ) {
247             final Element propertyElement = (Element) projProps.next();
248             ProjectXMLHelper.registerProperty(nonFullyResolvedProjectProperties,
249                 propertyElement, FAIL_UPON_MISSING_PROPERTY);
250         }
251         // add the resolved rootProperties to the project's properties
252
Map JavaDoc thisProperties = nonFullyResolvedProjectProperties.thisMap;
253         for (Iterator JavaDoc iterator = rootProperties.keySet().iterator(); iterator.hasNext();) {
254             String JavaDoc key = (String JavaDoc) iterator.next();
255             if (!thisProperties.containsKey(key)) {
256                 String JavaDoc value = (String JavaDoc) rootProperties.get(key);
257                 thisProperties.put(key, ProjectXMLHelper.parsePropertiesInString(thisProperties, value, false));
258             }
259         }
260
261         // Parse the entire element tree, expanding all property macros
262
ProjectXMLHelper.parsePropertiesInElement(projectElement, thisProperties, FAIL_UPON_MISSING_PROPERTY);
263
264         // Register any custom plugins
265
PluginRegistry projectPlugins = PluginRegistry.createRegistry(rootPlugins);
266         for (Iterator JavaDoc pluginIter = projectElement.getChildren("plugin").iterator(); pluginIter.hasNext(); ) {
267             projectPlugins.register((Element) pluginIter.next());
268         }
269
270         projectElement.removeChildren("property");
271         projectElement.removeChildren("plugin");
272
273         LOG.debug("**************** configuring project" + projectName + " *******************");
274         ProjectHelper projectHelper = new ProjectXMLHelper(thisProperties, projectPlugins);
275         ProjectConfig projectConfig = (ProjectConfig) projectHelper.configurePlugin(projectElement, false);
276
277         projectConfig.setProperties(thisProperties);
278
279         if (projectConfig.getLabelIncrementer() == null) {
280             LabelIncrementer labelIncrementer;
281             Class JavaDoc labelIncrClass = projectPlugins.getPluginClass(LABEL_INCREMENTER);
282             try {
283                 labelIncrementer = (LabelIncrementer) labelIncrClass.newInstance();
284             } catch (Exception JavaDoc e) {
285                 LOG.error("Error instantiating label incrementer named "
286                     + labelIncrClass.getName()
287                     + "in project "
288                     + projectName
289                     + ". Using DefaultLabelIncrementer instead.",
290                     e);
291                 labelIncrementer = new DefaultLabelIncrementer();
292             }
293             projectConfig.add(labelIncrementer);
294         }
295
296         Log log = projectConfig.getLog();
297         if (log == null) {
298             log = new Log();
299         }
300
301         log.setProjectName(projectName);
302         log.validate();
303         projectConfig.add(log);
304
305         projectConfig.validate();
306         LOG.debug("**************** end configuring project" + projectName + " *******************");
307
308         this.projectConfigs.put(projectName, projectConfig);
309         projectNames.add(projectName);
310         this.projectPluginRegistries.put(projectName, projectPlugins);
311     }
312
313     private String JavaDoc getProjectName(Element childElement) throws CruiseControlException {
314         if (!isProject(childElement.getName())) {
315             throw new IllegalStateException JavaDoc("Invalid Node <" + childElement.getName() + "> (not a project)");
316         }
317         String JavaDoc rawName = childElement.getAttribute("name").getValue();
318         return ProjectXMLHelper.parsePropertiesInString(rootProperties, rawName, false);
319     }
320
321     public ProjectConfig getConfig(String JavaDoc name) {
322         return (ProjectConfig) this.projectConfigs.get(name);
323     }
324
325     public Set JavaDoc getProjectNames() {
326 // TODO: can go to old implmentation when we drop 1.3 and can use LinkedHashMap
327
// return this.projectConfigs.keySet();
328
return projectNames;
329     }
330
331     PluginRegistry getRootPlugins() {
332         return rootPlugins;
333     }
334
335     PluginRegistry getProjectPlugins(String JavaDoc name) {
336         return (PluginRegistry) this.projectPluginRegistries.get(name);
337     }
338
339     /*
340      * Allows CC to build projects in the order they are added, which is the
341      * order they appear in the config file.
342      *
343      * TODO: remove when we can drop 1.3 and use LinkedHashMap for projectConfigs
344      */

345     private class ProjectNameSet implements Set JavaDoc {
346         private ArrayList JavaDoc list = new ArrayList JavaDoc();
347
348         public int size() {
349             return list.size();
350         }
351
352         public void clear() {
353             list.clear();
354         }
355
356         public boolean isEmpty() {
357             return list.isEmpty();
358         }
359
360         public Object JavaDoc[] toArray() {
361             return list.toArray();
362         }
363
364         public boolean add(Object JavaDoc o) {
365             if (o == null) {
366                 throw new IllegalArgumentException JavaDoc("null not a valid project name");
367             }
368             if (!(o instanceof String JavaDoc)) {
369                 throw new IllegalArgumentException JavaDoc("project names must be strings");
370             }
371             if (list.contains(o)) {
372                 return false;
373             }
374             list.add(o);
375             return true;
376         }
377
378         public boolean contains(Object JavaDoc o) {
379             return list.contains(o);
380         }
381
382         public boolean remove(Object JavaDoc o) {
383             return list.remove(o);
384         }
385
386         public boolean addAll(Collection JavaDoc c) {
387             return list.addAll(c);
388         }
389
390         public boolean containsAll(Collection JavaDoc c) {
391             return list.containsAll(c);
392         }
393
394         public boolean removeAll(Collection JavaDoc c) {
395             return list.removeAll(c);
396         }
397
398         public boolean retainAll(Collection JavaDoc c) {
399             return list.retainAll(c);
400         }
401
402         public Iterator JavaDoc iterator() {
403             return list.iterator();
404         }
405
406         public Object JavaDoc[] toArray(Object JavaDoc[] a) {
407             return list.toArray(a);
408         }
409
410     }
411
412 }
413
Popular Tags