001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon;
018:
019: import java.io.File;
020: import java.lang.reflect.InvocationTargetException;
021: import java.lang.reflect.Method;
022:
023: import javax.xml.parsers.DocumentBuilder;
024: import javax.xml.parsers.DocumentBuilderFactory;
025: import javax.xml.parsers.ParserConfigurationException;
026:
027: import org.apache.tools.ant.AntClassLoader;
028: import org.apache.tools.ant.BuildException;
029: import org.apache.tools.ant.DynamicConfigurator;
030: import org.apache.tools.ant.ExitException;
031: import org.apache.tools.ant.Project;
032: import org.apache.tools.ant.Task;
033: import org.apache.tools.ant.types.CommandlineJava;
034: import org.apache.tools.ant.types.Path;
035: import org.apache.tools.ant.types.Reference;
036:
037: import org.w3c.dom.Document;
038: import org.w3c.dom.Element;
039: import org.w3c.dom.NamedNodeMap;
040: import org.w3c.dom.Node;
041:
042: /**
043: * Ant task for running Cocoon. Allows for the embedding of Cocoon into
044: *
045: * @author <a href="mailto:uv@upaya.co.uk">Upayavira</a>
046: * @version CVS $Id: CocoonTask.java 433543 2006-08-22 06:22:54Z crossley $
047: */
048: public class CocoonTask extends Task implements DynamicConfigurator {
049:
050: private CommandlineJava cmdl = new CommandlineJava();
051: private boolean failOnError = false;
052: private Throwable caught = null;
053:
054: private String uriGroup = null;
055: private Document xconf;
056: private Element root;
057: private ElementWrapper _wrapper;
058:
059: private static final String CLASS_DELEGATE = "org.apache.cocoon.bean.helpers.AntDelegate";
060:
061: public CocoonTask() {
062: try {
063: DocumentBuilder builder = DocumentBuilderFactory
064: .newInstance().newDocumentBuilder();
065: xconf = builder.newDocument();
066: root = xconf.createElement("cocoon");
067: xconf.appendChild(root);
068: _wrapper = new ElementWrapper(root);
069: cmdl.setClassname(CLASS_DELEGATE);
070: } catch (ParserConfigurationException e) {
071: throw new BuildException(e);
072: }
073: }
074:
075: /**
076: * Adds a path to the classpath.
077: *
078: * @return created classpath
079: */
080: public Path createClasspath() {
081: return cmdl.createClasspath(getProject()).createPath();
082: }
083:
084: /**
085: * Classpath to use, by reference.
086: *
087: * @param r a reference to an existing classpath
088: */
089: public void setClasspathRef(Reference r) {
090: createClasspath().setRefid(r);
091: }
092:
093: /**
094: * Set the classpath to be used when running the Java class
095: *
096: * @param s an Ant Path object containing the classpath.
097: */
098: public void setClasspath(Path s) {
099: createClasspath().append(s);
100: }
101:
102: public void setUrigroup(String group) {
103: this .uriGroup = group;
104: }
105:
106: /**
107: * A dynamic configurator for each element.
108: */
109: private static class ElementWrapper implements DynamicConfigurator {
110:
111: private Node node;
112:
113: /** Instantiate a root wrapper */
114: private ElementWrapper(Node node) {
115: this .node = node;
116: }
117:
118: /** Instantiate a child wrapper */
119: private ElementWrapper(Node parent, String childName) {
120: Document document = parent.getOwnerDocument();
121: if (document == null) {
122: document = (Document) parent; // Node is the document!
123: }
124: node = document.createElement(childName);
125: parent.appendChild(node);
126: }
127:
128: //
129: // interface DynamicConfigurator
130: public void setDynamicAttribute(String name, String value)
131: throws BuildException {
132: // Never called for anything by Element wrappers
133: Element element = (Element) node;
134: element.setAttribute(name, value);
135: }
136:
137: public Object createDynamicElement(String name)
138: throws BuildException {
139: return new ElementWrapper(node, name);
140: }
141: }
142:
143: public File getLibDir() throws BuildException {
144: Element root = xconf.getDocumentElement();
145: String contextDir = null;
146: if (root != null) {
147: if (hasAttribute(root, "context-dir")) {
148: contextDir = getAttributeValue(root, "context-dir");
149: }
150: }
151: if (contextDir != null) {
152: return new File(contextDir + "/WEB-INF/lib");
153: } else {
154: throw new BuildException(
155: "No context directory specified. Cannot find Cocoon");
156: }
157: }
158:
159: private static String getAttributeValue(Node node, String attr)
160: throws IllegalArgumentException {
161: NamedNodeMap nodes = node.getAttributes();
162: if (nodes != null) {
163: Node attribute = nodes.getNamedItem(attr);
164: if (attribute != null && attribute.getNodeValue() != null) {
165: return attribute.getNodeValue();
166: }
167: }
168: throw new IllegalArgumentException("Missing " + attr
169: + " attribute on <" + node.getNodeName() + "> node");
170: }
171:
172: private static boolean hasAttribute(Node node, String attr) {
173: NamedNodeMap nodes = node.getAttributes();
174: if (nodes != null) {
175: Node attribute = nodes.getNamedItem(attr);
176: return (attribute != null);
177: }
178: return false;
179: }
180:
181: //
182: // interface DynamicConfigurator
183: public void setDynamicAttribute(String name, String value)
184: throws BuildException {
185: root.setAttribute(name, value);
186: }
187:
188: public Object createDynamicElement(String name)
189: throws BuildException {
190: return _wrapper.createDynamicElement(name);
191: }
192:
193: /**
194: * Do the execution and return a return code.
195: *
196: * @throws BuildException if required parameters are missing
197: */
198: public void execute() throws BuildException {
199: if (cmdl.getClasspath() == null) {
200: throw new BuildException(
201: "Could not find a classpath that points to the Cocoon classes");
202: }
203: try {
204: try {
205: execute(cmdl);
206: } catch (ExitException ex) {
207: // ignore
208: }
209: } catch (BuildException e) {
210: if (failOnError) {
211: throw e;
212: } else {
213: log(e.getMessage(), Project.MSG_ERR);
214: }
215: } catch (Throwable t) {
216: if (failOnError) {
217: throw new BuildException(t);
218: } else {
219: log(t.getMessage(), Project.MSG_ERR);
220: }
221: }
222: }
223:
224: public void execute(CommandlineJava command) throws BuildException {
225: final String classname = command.getJavaCommand()
226: .getExecutable();
227:
228: AntClassLoader loader = null;
229: try {
230: if (command.getSystemProperties() != null) {
231: command.getSystemProperties().setSystem();
232: }
233:
234: final Class[] param = {
235: Class.forName("org.w3c.dom.Document"),
236: Class.forName("java.lang.String") };
237: Class target = null;
238: if (command.getClasspath() == null) {
239: target = Class.forName(classname);
240: } else {
241: loader = new AntClassLoader(getProject()
242: .getCoreLoader(), getProject(), command
243: .getClasspath(), false);
244: loader.setIsolated(true);
245: loader.setThreadContextLoader();
246: target = loader.forceLoadClass(classname);
247: Class.forName(classname, true, loader);
248: }
249: Method method = target.getMethod("process", param);
250: if (method == null) {
251: throw new BuildException(
252: "Could not find process() method in "
253: + classname);
254: }
255:
256: run(method);
257:
258: if (caught != null) {
259: throw caught;
260: }
261:
262: } catch (ClassNotFoundException e) {
263: throw new BuildException("Could not find " + classname
264: + "." + " Make sure you have it in your"
265: + " classpath");
266: } catch (SecurityException e) {
267: throw e;
268: } catch (Throwable e) {
269: throw new BuildException(e);
270: } finally {
271: if (loader != null) {
272: loader.resetThreadContextLoader();
273: loader.cleanup();
274: }
275: if (command.getSystemProperties() != null) {
276: command.getSystemProperties().restoreSystem();
277: }
278: }
279: }
280:
281: public void run(Method method) {
282: final Object[] argument = { xconf, uriGroup };
283: try {
284: method.invoke(null, argument);
285: } catch (InvocationTargetException e) {
286: Throwable t = e.getTargetException();
287: if (!(t instanceof InterruptedException)) {
288: caught = t;
289: } /* else { swallow, probably due to timeout } */
290: } catch (Throwable t) {
291: caught = t;
292: } finally {
293: synchronized (this) {
294: notifyAll();
295: }
296: }
297: }
298: }
|