KickJava   Java API By Example, From Geeks To Geeks.

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


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 org.apache.log4j.Logger;
40 import org.jdom.Attribute;
41 import org.jdom.Element;
42
43 import java.lang.reflect.Method JavaDoc;
44 import java.util.HashMap JavaDoc;
45 import java.util.HashSet JavaDoc;
46 import java.util.Iterator JavaDoc;
47 import java.util.Map JavaDoc;
48 import java.util.Set JavaDoc;
49
50 /**
51  * Helps mapping the XML to object by instanciating and initializing beans.
52  *
53  * Some plugins can be {@link SelfConfiguringPlugin self-configuring}. For the others, the
54  * the {@link #configureObject(org.jdom.Element, Object, boolean)} defines the operations
55  * to be performed.
56  */

57 public class PluginXMLHelper {
58     private static final Logger LOG = Logger.getLogger(PluginXMLHelper.class);
59     private ProjectHelper projectHelper;
60
61     public PluginXMLHelper(ProjectHelper plugins) {
62         projectHelper = plugins;
63     }
64
65     /**
66      * Given a JDOM Element and a class, this method will instantiate an object
67      * of type pluginClass, and {@link #configure(org.jdom.Element, Class, boolean) configure} the element.
68      * <p>
69      * When the plugin is {@link SelfConfiguringPlugin self-configuring} the plugin takes
70      * the responsibility of {@link SelfConfiguringPlugin#configure(org.jdom.Element) configuring itself}
71      *
72      * <p>{@link #configure(org.jdom.Element, Object, boolean)} to use when one already has an instance.
73      *
74      * @param objectElement the JDOM Element defining the plugin configuration
75      * @param pluginClass the class to instanciate
76      * @param skipChildElements <code>false</code> to recurse the configuration, <code>true</code> otherwise
77      * @return fully configured Object
78      * @see #configure(org.jdom.Element, Object, boolean)
79      * @throws CruiseControlException
80      * if the plugin class cannot be instantiated,
81      * if the configuration fails
82      */

83     public Object JavaDoc configure(Element objectElement, Class JavaDoc pluginClass,
84                             boolean skipChildElements)
85             throws CruiseControlException {
86
87         Object JavaDoc pluginInstance = instantiatePlugin(pluginClass);
88         return configure(objectElement, pluginInstance, skipChildElements);
89
90     }
91
92     /**
93      * Instantiate a plugin
94      * @param pluginClass
95      * @return The instantiated plugin
96      * @throws CruiseControlException if the plugin class cannot be instantiated
97      */

98     private Object JavaDoc instantiatePlugin(Class JavaDoc pluginClass) throws CruiseControlException {
99         Object JavaDoc pluginInstance;
100         try {
101             pluginInstance = pluginClass.getConstructor(null).newInstance(null);
102         } catch (Exception JavaDoc e) {
103             LOG.fatal("Could not instantiate class", e);
104             throw new CruiseControlException("Could not instantiate class: "
105                     + pluginClass.getName());
106         }
107         return pluginInstance;
108     }
109
110     /**
111      * Same as {@link #configure(org.jdom.Element, Class, boolean)}, except that
112      * the client already has a pluginInstance.
113      * @throws CruiseControlException if the configuration fails
114      */

115     public Object JavaDoc configure(Element objectElement, Object JavaDoc pluginInstance,
116                             boolean skipChildElements) throws CruiseControlException {
117         
118         LOG.debug("configure " + objectElement.getName() + " instance " + pluginInstance.getClass()
119                   + " self configuring: " + (pluginInstance instanceof SelfConfiguringPlugin)
120                   + " skip:" + skipChildElements);
121         if (pluginInstance instanceof SelfConfiguringPlugin) {
122             ((SelfConfiguringPlugin) pluginInstance).configure(objectElement);
123         } else {
124             configureObject(objectElement, pluginInstance, skipChildElements);
125         }
126         return pluginInstance;
127     }
128
129     /**
130      * Configure the specified plugin object given the JDOM Element defining the plugin configuration.
131      *
132      * <ul>
133      * <li>calls setters that corresponds to element attributes</li>
134      * <li>calls <code>public Yyy createXxx()</code> methods that corresponds to non-plugins child elements
135      * (i.e. known by the instance class). The returned instance must be assignable to the Yyy type</li>
136      * <li>calls <code>public void add(Xxx)</code> methods that corresponds to child elements which are
137      * plugins themselves, e.g. which will require asking the ProjectXMLHelper to
138      * {@link ProjectXMLHelper#configurePlugin(org.jdom.Element, boolean) configure the plugin}</li>
139      * </ul>
140      *
141      * @param objectElement the JDOM Element defining the plugin configuration
142      * @param object the instance to configure to instanciate
143      * @param skipChildElements <code>false</code> to recurse the configuration, <code>true</code> otherwise
144      */

145     protected void configureObject(Element objectElement, Object JavaDoc object, boolean skipChildElements)
146             throws CruiseControlException {
147
148         LOG.debug("configuring object " + objectElement.getName()
149             + " object " + object.getClass() + " skip " + skipChildElements);
150
151         Map JavaDoc setters = new HashMap JavaDoc();
152         Map JavaDoc creators = new HashMap JavaDoc();
153         Set JavaDoc adders = new HashSet JavaDoc();
154
155         Method JavaDoc[] methods = object.getClass().getMethods();
156         for (int i = 0; i < methods.length; i++) {
157             final Method JavaDoc method = methods[i];
158             final String JavaDoc name = method.getName();
159             if (name.startsWith("set")) {
160                 setters.put(name.substring("set".length()).toLowerCase(), method);
161             } else if (name.startsWith("create")) {
162                 creators.put(name.substring("create".length()).toLowerCase(), method);
163             } else if (name.equals("add") && method.getParameterTypes().length == 1) {
164                 adders.add(method);
165             }
166         }
167
168         setFromAttributes(objectElement, setters, object);
169
170         if (!skipChildElements) {
171             Iterator JavaDoc childElementIterator = objectElement.getChildren().iterator();
172             while (childElementIterator.hasNext()) {
173                 Element childElement = (Element) childElementIterator.next();
174                 if (creators.containsKey(childElement.getName().toLowerCase())) {
175                     LOG.debug("treating child with creator " + childElement.getName());
176                     try {
177                         Method JavaDoc method = (Method JavaDoc) creators.get(childElement.getName().toLowerCase());
178                         Object JavaDoc childObject = method.invoke(object, null);
179                         configureObject(childElement, childObject, false);
180                     } catch (Exception JavaDoc e) {
181                         throw new CruiseControlException(e.getMessage());
182                     }
183                 } else {
184                     // instanciate object from element via registry
185
Object JavaDoc childObject = projectHelper.configurePlugin(childElement, false);
186
187                     Method JavaDoc adder = null;
188                     // iterate over adders to find one that will take the object
189
for (Iterator JavaDoc iterator = adders.iterator(); iterator.hasNext();) {
190                         Method JavaDoc method = (Method JavaDoc) iterator.next();
191                         Class JavaDoc type = method.getParameterTypes()[0];
192                         if (type.isAssignableFrom(childObject.getClass())) {
193                             adder = method;
194                             break;
195                         }
196                     }
197
198                     if (adder != null) {
199                         try {
200                             LOG.debug("treating child with adder " + childElement.getName() + " adding " + childObject);
201                             adder.invoke(object, new Object JavaDoc[]{childObject});
202                         } catch (Exception JavaDoc e) {
203                             LOG.fatal("Error configuring plugin.", e);
204                         }
205                     } else {
206                         throw new CruiseControlException("Nested element: '" + childElement.getName()
207                                 + "' is not supported for the <" + objectElement.getName() + "> tag.");
208                     }
209                 }
210             }
211         }
212     }
213
214     private void setFromAttributes(Element objectElement, Map JavaDoc setters, Object JavaDoc object) throws CruiseControlException {
215         for (Iterator JavaDoc iter = objectElement.getAttributes().iterator(); iter.hasNext(); ) {
216             Attribute attribute = (Attribute) iter.next();
217             callSetter(attribute.getName(), attribute.getValue(), setters, object);
218         }
219     }
220     
221     private void callSetter(String JavaDoc propName, String JavaDoc propValue, Map JavaDoc setters, Object JavaDoc object)
222         throws CruiseControlException {
223         
224         if (setters.containsKey(propName.toLowerCase())) {
225             LOG.debug("Setting " + propName.toLowerCase() + " to " + propValue);
226             try {
227                 Method JavaDoc method = (Method JavaDoc) setters.get(propName.toLowerCase());
228                 Class JavaDoc[] parameters = method.getParameterTypes();
229                 if (String JavaDoc.class.isAssignableFrom(parameters[0])) {
230                     method.invoke(object, new Object JavaDoc[]{propValue});
231                 } else if (int.class.isAssignableFrom(parameters[0])) {
232                     method.invoke(object, new Object JavaDoc[]{Integer.valueOf(propValue)});
233                 } else if (long.class.isAssignableFrom(parameters[0])) {
234                     method.invoke(object, new Object JavaDoc[]{Long.valueOf(propValue)});
235                 } else if (boolean.class.isAssignableFrom(parameters[0])) {
236                     method.invoke(object,
237                             new Object JavaDoc[]{Boolean.valueOf(propValue)});
238                 } else {
239                     LOG.error("rCouldn't invoke setter " + propName.toLowerCase());
240                 }
241             } catch (Exception JavaDoc e) {
242                 LOG.fatal("Error configuring plugin.", e);
243             }
244         } else {
245             throw new CruiseControlException("Attribute: '" + propName
246                     + "' is not supported for class: '" + object.getClass().getName() + "'.");
247         }
248     }
249
250 }
251
Popular Tags