1 /*
2 * Copyright (c) 2001, 2002 The XDoclet team
3 * All rights reserved.
4 */
5 package xdoclet;
6
7 import org.apache.commons.logging.LogFactory;
8 import org.apache.commons.collections.CollectionUtils;
9 import org.apache.commons.collections.Predicate;
10
11 import xdoclet.beans.Invocation;
12 import xdoclet.beans.BeanContextSupportEx;
13 import xdoclet.sdk.ant.BuildXmlPlugin;
14 import xdoclet.sdk.ant.BuildXmlMetadataProvider;
15 import xdoclet.util.ClasspathManager;
16
17 import java.util.*;
18 import java.io.File;
19 import java.io.IOException;
20 import java.beans.BeanInfo;
21 import java.beans.Introspector;
22 import java.beans.IntrospectionException;
23 import java.beans.MethodDescriptor;
24 import java.lang.reflect.Method;
25
26 /***
27 * <p>This class as an entry-point for starting XDoclet. Adapter classes for
28 * particular environments such as various IDEs and Ant should be maintained
29 * separately. It's important to keep XDoclet's core environment agnostic.</p>
30 *
31 * <p>This class also extends {@link java.beans.beancontext.BeanContextSupport},
32 * and thereby this is actually a Collection, so we can store the plugins
33 * "in ourself". The main reason for extending BeanContextSupport is to
34 * be a ble to provide IDE integration in a convenient way. See the
35 * <a href="../gui/package.html"></a>xdoclet.gui</p> package.
36 *
37 * @bean.class displayName="Simple XDoclet"
38 * shortDescription="This is a simple XDoclet that can be used as a container by generic Plugins"
39 *
40 * @bean.attribute name="xdoclet.beans.InvocationFactory" value="xdoclet.beans.XDocletInvocationFactory"
41 *
42 * @see Plugin
43 * @see ClasspathManager
44 * @see PluginFactory
45 * @see XDocletException
46 *
47 * @author <a href="mailto:aslak.hellesoy at netcom.no">Aslak Hellesøy</a>
48 * @version $Revision: 1.22 $
49 */
50 public class XDoclet extends BeanContextSupportEx {
51 public static final String XDOCLET_VERSION = "@XDOCLET_VERSION@";
52
53 /*** The PluginFactory registers and creates plugins found on the classpath. */
54 private PluginFactory _pluginFactory;
55
56 /***
57 * To work around the fact that org.apache.commons.jelly.tags.ant.AntTag
58 * swallows BuildException in its createNestedObject method, we keep
59 * a ref here, so we can fail the build ourself.
60 */
61 private transient Throwable _failure;
62
63 /***
64 * If set, a simple build.xml will be generated and dumped here.
65 */
66 private BuildXmlPlugin _buildXmlPlugin = new BuildXmlPlugin();
67
68 /***
69 * Creates a new XDoclet.
70 */
71 public XDoclet() {
72 printVersion();
73 }
74
75 private MetadataProvider getCurrentMetadataProvider() {
76 return (MetadataProvider) CollectionUtils.find(this,
77 new Predicate() {
78 public boolean evaluate(Object o) {
79 return o instanceof MetadataProvider;
80 }
81 });
82 }
83
84 private Collection getPlugins() {
85 return CollectionUtils.select(this,
86 new Predicate() {
87 public boolean evaluate(Object o) {
88 return o instanceof Plugin;
89 }
90 });
91 }
92
93 /***
94 * If this is set, a build.xml file will be written out to the
95 * specified file.
96 *
97 * @bean.property
98 * shortDescription="Location of generated Ant script (build.xml)."
99 * displayName="build.xml"
100 * @param buildXmlDir the file where build.xml should be written.
101 *
102 * @todo this isn't an elegant way to do it. fixme.
103 */
104 public final void setBuildXmlDir(File buildXmlDir) {
105 _buildXmlPlugin.setDestinationDir( buildXmlDir );
106 }
107
108 public final File getBuildXmlDir() {
109 return _buildXmlPlugin.getDestinationDir();
110 }
111
112 public MetadataProvider createMetadataProvider( String name ) throws XDocletException {
113 if( getCurrentMetadataProvider() != null ) {
114 throw new XDocletException("A " + getCurrentMetadataProvider().getClass().getName() +
115 "MetaDataProvider has already been created. Shouldn't create a " + name + " now.");
116 }
117
118 MetadataProvider result = _pluginFactory.createMetadataProvider( name, this );
119
120 setClasspathOnMetadataProviderMaybe();
121 return result;
122 }
123
124 public void setFailure(Throwable failure) {
125 _failure = failure;
126 }
127
128 /***
129 * Sets the classpath under which XDoclet is run.
130 * @param classpath the classpath under which XDoclet is run
131 * @bean.ignore
132 */
133 public void setClasspath(String classpath) throws XDocletException {
134 ClasspathManager classpathManager = new ClasspathManager(classpath);
135
136 _pluginFactory = new PluginFactory(classpathManager);
137
138 setClasspathOnMetadataProviderMaybe();
139 }
140
141 /***
142 * If the current matadata provider is xjavadoc, set classpath on it.
143 * This is done via reflection, to keep
144 */
145 private void setClasspathOnMetadataProviderMaybe() throws XDocletException {
146 if( getCurrentMetadataProvider() != null ) {
147 getCurrentMetadataProvider().setClasspath( _pluginFactory.getClasspathManager().getClasspath() );
148 }
149 }
150
151 /***
152 * Gets that ClasspathManager.
153 * @return the ClasspathManager.
154 */
155 public ClasspathManager getClasspathManager() {
156 return _pluginFactory.getClasspathManager();
157 }
158
159 /***
160 * Executes all the plugins.
161 *
162 * @throws XDocletException if execution fails.
163 */
164 public void execute() throws IOException, XDocletException {
165 failIfFailureSet();
166
167 if (isEmpty()) {
168 throw new XDocletException("At least one plugin must be specified.");
169 }
170
171 long start = System.currentTimeMillis();
172
173 for (Iterator i = getPlugins().iterator(); i.hasNext();) {
174 Plugin plugin = (Plugin) i.next();
175 // Let the plugin use our MetadataProvider.
176 plugin.setMetadataProvider( getCurrentMetadataProvider() );
177 plugin.execute();
178 }
179
180 long end = System.currentTimeMillis();
181
182 LogFactory.getLog(getClass()).debug("XDoclet ran in " + (end - start) + " ms.");
183
184 generateBuildXmlMaybe();
185 }
186
187 public void generateBuildXmlMaybe() throws IOException, XDocletException {
188 // Add the special build.xml plugin if a build.xml dir is set.
189 if( getBuildXmlDir() != null ) {
190 XDoclet buildXmlDoclet = new XDoclet();
191 // Activate the BuildXmlMetadataProvider
192 BuildXmlMetadataProvider buildXmlMetadataProvider =
193 (BuildXmlMetadataProvider) buildXmlDoclet.createMetadataProvider("ant");
194 buildXmlMetadataProvider.setXDoclet( this );
195 buildXmlDoclet.add(_buildXmlPlugin);
196 _buildXmlPlugin.execute();
197 remove(_buildXmlPlugin);
198 }
199 }
200
201 /***
202 * Called by {@link xdoclet.ant.AntProxy#createDynamicElement} when a dynamic element is added
203 * to the XDoclet task. This method will route the call to {@link #createPlugin}.
204 *
205 * @param name the name of the plugin to create.
206 * @return a {@link Plugin} object mapped to name.
207 * @throws XDocletException
208 */
209 public Object createElement(String name)
210 throws XDocletException {
211 LogFactory.getLog(XDoclet.class).debug("createElement(" + name + ")");
212
213 Object result = null;
214 try {
215 // First try to create a plugin
216 result = createPlugin(name);
217 } catch (XDocletException e) {
218 // It wasn't a plugin. Try MetadataProvider instead.
219 result = createMetadataProvider(name);
220 }
221 if( result == null ) {
222 throw new XDocletException("Don't know what to instantiate for " + name + ".");
223 }
224 return result;
225 }
226
227 private static final void printVersion() {
228 // This should really be a System.out.print[ln], as we want this to be printed
229 // every time XDoclet is run. The version string will be substituted by maven.xml
230 System.out.print(".");
231
232 for (int i = 0; i < (XDOCLET_VERSION.length() + 2); i++) {
233 System.out.print("-");
234 }
235
236 System.out.println(".");
237 System.out.println("| " + XDOCLET_VERSION + " |");
238 System.out.print("`");
239
240 for (int i = 0; i < (XDOCLET_VERSION.length() + 2); i++) {
241 System.out.print("-");
242 }
243
244 System.out.println("'");
245 }
246
247 private void failIfFailureSet()
248 throws XDocletException {
249 if (_failure != null) {
250 if (_failure instanceof XDocletException) {
251 throw (XDocletException) _failure;
252 } else {
253 throw new XDocletException(_failure.getMessage(), _failure);
254 }
255 }
256 }
257
258 /***
259 * Adds a new Plugin.
260 *
261 * @bean.method shortDescription="Add a new plugin"
262 * displayName="New Plugin"
263 *
264 * @param name Plugin name
265 * @return a Plugin instance
266 * @throws XDocletException plugin creation fails.
267 * @see PluginFactory#createPlugin(java.lang.String, xdoclet.XDoclet)
268 */
269 public Plugin createPlugin(String name)
270 throws XDocletException {
271 return _pluginFactory.createPlugin(name, this);
272 }
273
274 protected Collection createInvocations() {
275 Collection result = new ArrayList();
276
277 BeanInfo beanInfo = null;
278
279 try {
280 beanInfo = Introspector.getBeanInfo(getClass());
281 } catch (IntrospectionException e) {
282 LogFactory.getLog(XDoclet.class).error(e.getMessage(), e);
283 throw new IllegalStateException("Couldn't get BeanInfo for " + getClass() + ":" + e.getMessage());
284 }
285
286 Method createPlugin = null;
287
288 try {
289 createPlugin = getClass().getMethod("createPlugin", new Class[] { String.class });
290 } catch (NoSuchMethodException e) {
291 LogFactory.getLog(XDoclet.class).error(e.getMessage(), e);
292 throw new IllegalStateException("Couldn't find createPlugin(String) in " + getClass() + ":"
293 + e.getMessage());
294 } catch (SecurityException e) {
295 LogFactory.getLog(XDoclet.class).error(e.getMessage(), e);
296 throw new IllegalStateException("Couldn't find createPlugin(String) in " + getClass() + ":"
297 + e.getMessage());
298 }
299
300 MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors();
301
302 for (int m = 0; m < methodDescriptors.length; m++) {
303 if (createPlugin.equals(methodDescriptors[m].getMethod())) {
304 // See Xdoclet.updateBeanInfo
305 List pluginNames = (List) methodDescriptors[m].getValue("pluginNames");
306
307 for (Iterator i = pluginNames.iterator(); i.hasNext();) {
308 String pluginName = (String) i.next();
309 Object[] args = new Object[] { pluginName };
310 Invocation invocation = new Invocation(methodDescriptors[m], this, args);
311
312 result.add(invocation);
313 }
314 }
315 }
316
317 return result;
318 }
319 }
This page was automatically generated by Maven