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 anttasks;
018:
019: import java.io.File;
020: import java.io.FileWriter;
021: import java.io.IOException;
022: import java.net.MalformedURLException;
023: import java.util.ArrayList;
024: import java.util.HashMap;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Map;
028:
029: import javax.xml.transform.TransformerException;
030:
031: import org.apache.tools.ant.BuildException;
032: import org.apache.tools.ant.Project;
033: import org.apache.tools.ant.types.FileSet;
034: import org.apache.xpath.XPathAPI;
035: import org.w3c.dom.Document;
036: import org.w3c.dom.Element;
037: import org.w3c.dom.Node;
038: import org.w3c.dom.NodeList;
039:
040: import com.thoughtworks.qdox.ant.AbstractQdoxTask;
041: import com.thoughtworks.qdox.model.DocletTag;
042: import com.thoughtworks.qdox.model.JavaClass;
043: import com.thoughtworks.qdox.parser.ParseException;
044:
045: /**
046: * Generate documentation for sitemap components based on javadoc tags
047: * in the source of the component.
048: *
049: * This is the first, experimental version - the code is a little bit
050: * hacky but straight forward :)
051: *
052: * @since 2.1.5
053: * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
054: * @version CVS $Id: SitemapTask.java 433543 2006-08-22 06:22:54Z crossley $
055: */
056: public final class SitemapTask extends AbstractQdoxTask {
057:
058: /** The name of the component in the sitemap (required) */
059: public static final String NAME_TAG = "cocoon.sitemap.component.name";
060: /** The logger category (optional) */
061: public static final String LOGGER_TAG = "cocoon.sitemap.component.logger";
062: /** The label for views (optional) */
063: public static final String LABEL_TAG = "cocoon.sitemap.component.label";
064: /** The mime type for serializers and readers (optional) */
065: public static final String MIMETYPE_TAG = "cocoon.sitemap.component.mimetype";
066: /** If this tag is specified, the component is not added to the sitemap (optional) */
067: public static final String HIDDEN_TAG = "cocoon.sitemap.component.hide";
068: /** If this tag is specified no documentation is generated (optional) */
069: public static final String NO_DOC_TAG = "cocoon.sitemap.component.documentation.disabled";
070: /** The documentation (optional) */
071: public static final String DOC_TAG = "cocoon.sitemap.component.documentation";
072: /** Configuration (optional) */
073: public static final String CONF_TAG = "cocoon.sitemap.component.configuration";
074: /** Caching info (optional) */
075: public static final String CACHING_INFO_TAG = "cocoon.sitemap.component.documentation.caching";
076:
077: /** Pooling max (optional) */
078: public static final String POOL_MAX_TAG = "cocoon.sitemap.component.pooling.max";
079:
080: private static final String LINE_SEPARATOR = "\n";
081:
082: /** The sitemap */
083: private File sitemap;
084:
085: /** The doc dir */
086: private File docDir;
087:
088: /** Cache for classes */
089: private static Map cache = new HashMap();
090:
091: /** The directory containing the sources*/
092: private String directory;
093:
094: /** The name of the block */
095: protected String blockName;
096:
097: /** Is this block deprecated? */
098: protected boolean deprecated = false;
099:
100: /** Is this block stable? */
101: protected boolean stable = true;
102:
103: /**
104: * Set the directory containing the source files.
105: * Only .java files will be scanned
106: */
107: public void setSource(File dir) {
108: try {
109: this .directory = dir.toURL().toExternalForm();
110: if (!dir.isDirectory()) {
111: throw new BuildException("Source is not a directory.");
112: }
113: } catch (IOException ioe) {
114: throw new BuildException(ioe);
115: }
116: FileSet set = new FileSet();
117: set.setDir(dir);
118: set.setIncludes("**/*.java");
119: super .addFileset(set);
120: }
121:
122: /**
123: * The location of the sitemap
124: */
125: public void setSitemap(final File sitemap) {
126: this .sitemap = sitemap;
127: }
128:
129: /**
130: * The location of the documentation files
131: */
132: public void setDocDir(final File dir) {
133: this .docDir = dir;
134: }
135:
136: /**
137: * Set the block name
138: */
139: public void setBlock(String value) {
140: this .blockName = value;
141: }
142:
143: /**
144: * Is the block deprecated?
145: */
146: public void setDeprecated(boolean value) {
147: this .deprecated = value;
148: }
149:
150: /**
151: * Is the block stable?
152: */
153: public void setStable(boolean value) {
154: this .stable = value;
155: }
156:
157: /**
158: * Determine the type of the class
159: */
160: private String classType(JavaClass clazz) {
161: if (clazz.isA(GENERATOR)) {
162: return "generator";
163: } else if (clazz.isA(TRANSFORMER)) {
164: return "transformer";
165: } else if (clazz.isA(READER)) {
166: return "reader";
167: } else if (clazz.isA(SERIALIZER)) {
168: return "serializer";
169: } else if (clazz.isA(ACTION)) {
170: return "action";
171: } else if (clazz.isA(MATCHER)) {
172: return "matcher";
173: } else if (clazz.isA(SELECTOR)) {
174: return "selector";
175: } else if (clazz.isA(PIPELINE)) {
176: return "pipe";
177: // Should qdox resolve recursively? ie: HTMLGenerator isA ServiceableGenerator isA AbstractGenerator isA Generator
178: } else if (clazz.getPackage().equals(
179: "org.apache.cocoon.generation")
180: && (clazz.isA("Generator") || clazz
181: .isA("ServiceableGenerator"))) {
182: return "generator";
183: } else if (clazz
184: .isA("org.apache.cocoon.generation.ServiceableGenerator")) {
185: return "generator";
186: } else if (clazz.getPackage().equals(
187: "org.apache.cocoon.transformation")
188: && clazz.isA("Transformer")) {
189: return "transformer";
190: } else if (clazz.getPackage().equals(
191: "org.apache.cocoon.reading")
192: && clazz.isA("Reader")) {
193: return "reader";
194: } else if (clazz.getPackage().equals(
195: "org.apache.cocoon.serialization")
196: && clazz.isA("Serializer")) {
197: return "serializer";
198: } else if (clazz.getPackage()
199: .equals("org.apache.cocoon.acting")
200: && clazz.isA("Action")) {
201: return "action";
202: } else if (clazz.getPackage().equals(
203: "org.apache.cocoon.matching")
204: && clazz.isA("Matcher")) {
205: return "matcher";
206: } else if (clazz.getPackage().equals(
207: "org.apache.cocoon.selection")
208: && clazz.isA("Selector")) {
209: return "selector";
210: } else if (clazz.getPackage().equals(
211: "org.apache.cocoon.components.pipeline")
212: && clazz.isA("ProcessingPipeline")) {
213: return "pipe";
214: } else {
215: return null;
216: }
217: }
218:
219: /**
220: * Execute generator task.
221: *
222: * @throws BuildException if there was a problem collecting the info
223: */
224: public void execute() throws BuildException {
225: validate();
226:
227: List components = (List) cache.get(this .directory);
228: if (components == null) {
229: // this does the hard work :)
230: try {
231: super .execute();
232: } catch (ParseException pe) {
233: log("ParseException: " + pe);
234: }
235: components = this .collectInfo();
236: cache.put(this .directory, components);
237: }
238:
239: try {
240:
241: if (this .sitemap != null) {
242: this .processSitemap(components);
243: }
244: if (this .docDir != null) {
245: this .processDocDir(components);
246: }
247:
248: } catch (final BuildException e) {
249: throw e;
250: } catch (final Exception e) {
251: throw new BuildException(e.toString(), e);
252: }
253: }
254:
255: /**
256: * Validate that the parameters are valid.
257: */
258: private void validate() {
259: if (this .directory == null) {
260: throw new BuildException("Source is not specified.");
261: }
262: if (this .sitemap == null && this .docDir == null) {
263: throw new BuildException(
264: "Sitemap or DocDir is not specified.");
265: }
266:
267: if (this .sitemap != null && this .sitemap.isDirectory()) {
268: throw new BuildException("Sitemap (" + this .sitemap
269: + ") is not a file.");
270: }
271: if (this .docDir != null && !this .docDir.isDirectory()) {
272: throw new BuildException("DocDir (" + this .docDir
273: + ") is not a directory.");
274: }
275: }
276:
277: /**
278: * Collect the component information
279: */
280: private List collectInfo() {
281: log("Collecting sitemap components info");
282: final List components = new ArrayList();
283: final List allComponentNames = new ArrayList();
284:
285: final Iterator it = super .allClasses.iterator();
286:
287: while (it.hasNext()) {
288: final JavaClass javaClass = (JavaClass) it.next();
289:
290: final DocletTag tag = javaClass.getTagByName(NAME_TAG);
291: if (classType(javaClass) != null) {
292: allComponentNames
293: .add(javaClass.getFullyQualifiedName());
294: }
295:
296: if (null != tag) {
297: final SitemapComponent comp = new SitemapComponent(
298: javaClass);
299:
300: log("Found component: " + comp, Project.MSG_DEBUG);
301: components.add(comp);
302: }
303: }
304:
305: // Generate a list of all sitemap components
306: final String fileSeparator = System.getProperty(
307: "file.separator", "/");
308: final String matchString = "blocks" + fileSeparator;
309: final String outputFname = "build" + fileSeparator
310: + "all-sitemap-components"
311: + (directory.endsWith(matchString) ? "-blocks" : "")
312: + ".txt";
313: log("Listing all sitemap components to " + outputFname);
314: try {
315: File outputFile = new File(outputFname);
316: FileWriter out = new FileWriter(outputFile);
317: final String lineSeparator = System.getProperty(
318: "line.separator", "\n");
319: final Iterator iter = allComponentNames.iterator();
320: while (iter.hasNext()) {
321: out.write((String) iter.next());
322: out.write(lineSeparator);
323: }
324: out.close();
325: } catch (IOException ioe) {
326: log("IOException: " + ioe);
327: }
328:
329: return components;
330: }
331:
332: /**
333: * Add components to sitemap
334: */
335: private void processSitemap(List components) throws Exception {
336: log("Adding sitemap components");
337: Document document;
338:
339: document = DocumentCache.getDocument(this .sitemap, this );
340:
341: boolean changed = false;
342:
343: Iterator iter = components.iterator();
344: while (iter.hasNext()) {
345: SitemapComponent component = (SitemapComponent) iter.next();
346: final String type = component.getType();
347: final String section = type + 's';
348:
349: NodeList nodes = XPathAPI.selectNodeList(document,
350: "/sitemap/components/" + section);
351:
352: if (nodes.getLength() != 1) {
353: throw new BuildException(
354: "Unable to find section for component type "
355: + type);
356: }
357: // remove old node!
358: NodeList oldNodes = XPathAPI.selectNodeList(document,
359: "/sitemap/components/" + section + '/' + type
360: + "[@name='" + component.getName() + "']");
361: for (int i = 0; i < oldNodes.getLength(); i++) {
362: final Node node = oldNodes.item(i);
363: node.getParentNode().removeChild(node);
364: }
365:
366: // and add it again
367: if (component.append(nodes.item(0))) {
368: changed = true;
369: }
370:
371: }
372:
373: if (changed) {
374: DocumentCache.writeDocument(this .sitemap, document, this );
375: }
376: DocumentCache.storeDocument(this .sitemap, document, this );
377: }
378:
379: /**
380: * Add components to sitemap
381: */
382: private void processDocDir(List components) throws Exception {
383: log("Generating documentation");
384:
385: Iterator iter = components.iterator();
386: while (iter.hasNext()) {
387: final SitemapComponent component = (SitemapComponent) iter
388: .next();
389:
390: // Read template
391: final File templateFile = this
392: .getProject()
393: .resolveFile(
394: "src/documentation/templates/sitemap-component.xml");
395: Document template = DocumentCache.getDocument(templateFile,
396: this );
397:
398: // create directory - if required
399: final File componentsDir = new File(this .docDir, component
400: .getType() + 's');
401: componentsDir.mkdir();
402:
403: // get file name
404: String fileName = component.getName() + "-"
405: + component.getType() + ".xml";
406: if (this .blockName != null) {
407: fileName = this .blockName + "-" + fileName;
408: }
409: final File docFile = new File(componentsDir, fileName);
410:
411: // generate the doc
412: component
413: .generateDocs(template, docFile, this .getProject());
414:
415: // generate the index
416: final File indexFile = new File(componentsDir, "book.xml");
417: final Document indexDoc = DocumentCache.getDocument(
418: indexFile, this );
419: final String section;
420: if (this .blockName == null) {
421: section = "Core";
422: } else {
423: section = this .blockName + " Block";
424: }
425: Node sectionNode = XPathAPI.selectSingleNode(indexDoc,
426: "/book/menu[@label='" + section + "']");
427: if (sectionNode == null) {
428: sectionNode = indexDoc.createElement("menu");
429: ((Element) sectionNode).setAttribute("label", section);
430: indexDoc.getDocumentElement().appendChild(sectionNode);
431: }
432: final String htmlName = docFile.getName().substring(0,
433: docFile.getName().length() - 3)
434: + "html";
435: Node oldEntry = XPathAPI.selectSingleNode(sectionNode,
436: "menu-item[@href='" + htmlName + "']");
437: Node newEntry = indexDoc.createElement("menu-item");
438: ((Element) newEntry).setAttribute("href", htmlName);
439: final String label = capitalize(component.getName()) + " "
440: + capitalize(component.getType());
441: ((Element) newEntry).setAttribute("label", label);
442: if (oldEntry != null) {
443: oldEntry.getParentNode().replaceChild(newEntry,
444: oldEntry);
445: } else {
446: Node nextLabel = null;
447: final NodeList childs = sectionNode.getChildNodes();
448: int i = 0;
449: while (nextLabel == null && i < childs.getLength()) {
450: final Node current = childs.item(i);
451: if (current instanceof Element) {
452: final String currentLabel = ((Element) current)
453: .getAttribute("label");
454: if (label.compareTo(currentLabel) < 0) {
455: nextLabel = current;
456: }
457: }
458: i++;
459: }
460: if (nextLabel == null) {
461: sectionNode.appendChild(newEntry);
462: } else {
463: sectionNode.insertBefore(newEntry, nextLabel);
464: }
465: }
466: DocumentCache.writeDocument(indexFile, indexDoc, this );
467: }
468:
469: }
470:
471: /**
472: * Helper method to capitalize a string.
473: * This is taken from commons-lang, but we don't want the dependency
474: * right now!
475: */
476: public static String capitalize(String str) {
477: int strLen;
478: if (str == null || (strLen = str.length()) == 0) {
479: return str;
480: }
481: return new StringBuffer(strLen).append(
482: Character.toTitleCase(str.charAt(0))).append(
483: str.substring(1)).toString();
484: }
485:
486: final class SitemapComponent {
487:
488: final protected JavaClass javaClass;
489: final String name;
490: final String type;
491:
492: public SitemapComponent(JavaClass javaClass) {
493: this .javaClass = javaClass;
494:
495: this .name = this .javaClass.getTagByName(NAME_TAG)
496: .getValue();
497: // TEST CODE
498: System.out.println("Name: " + this .name);
499: System.out
500: .println("className: " + this .javaClass.getName());
501: System.out.println();
502:
503: JavaClass[] jc = this .javaClass.getImplementedInterfaces();
504: if (jc.length > 0) {
505: System.out.println("Implemented interfaces:");
506: }
507: for (int i = 0; i < jc.length; i++) {
508: System.out.println(jc[i].getName() + ". Full name: "
509: + jc[i].getFullyQualifiedName());
510: }
511: System.out.println("==== END of implements ===");
512: // END TEST CODE
513: this .type = classType(this .javaClass);
514: }
515:
516: /* (non-Javadoc)
517: * @see java.lang.Object#toString()
518: */
519: public String toString() {
520: return "Sitemap component: " + this .javaClass.getName();
521: }
522:
523: public String getType() {
524: return this .type;
525: }
526:
527: public String getName() {
528: return this .name;
529: }
530:
531: public boolean append(Node parent) {
532: if (this .getTagValue(HIDDEN_TAG, null) != null) {
533: return false;
534: }
535: Document doc = parent.getOwnerDocument();
536: Node node;
537:
538: // first check: deprecated?
539: if (SitemapTask.this .deprecated
540: || this .getTagValue("deprecated", null) != null) {
541: indent(parent, 3);
542: StringBuffer buffer = new StringBuffer("The ");
543: buffer.append(this .type).append(" ").append(this .name)
544: .append(" is deprecated");
545: node = doc.createComment(buffer.toString());
546: parent.appendChild(node);
547: newLine(parent);
548: }
549: // unstable block?
550: if (!SitemapTask.this .stable) {
551: indent(parent, 3);
552: StringBuffer buffer = new StringBuffer("The ");
553: buffer.append(this .type).append(" ").append(this .name)
554: .append(" is in an unstable block");
555: node = doc.createComment(buffer.toString());
556: parent.appendChild(node);
557: newLine(parent);
558: }
559:
560: indent(parent, 3);
561: node = doc.createElement("map:" + this .type);
562: ((Element) node).setAttribute("name", this .name);
563: ((Element) node).setAttribute("src", this .javaClass
564: .getFullyQualifiedName());
565:
566: // test for logger
567: // TODO Default logger?
568: if (this .javaClass.isA(LOG_ENABLED)) {
569: this .addAttribute(node, LOGGER_TAG, "logger", null);
570: }
571:
572: // test for label
573: this .addAttribute(node, LABEL_TAG, "label", null);
574:
575: // pooling?
576: if (this .javaClass.isA(POOLABLE)) {
577: // TODO - Think about default values
578: this .addAttribute(node, POOL_MAX_TAG, "pool-max", null);
579: }
580:
581: // mime-type
582: if (this .javaClass.isA(OUTPUT_COMPONENT)) {
583: this
584: .addAttribute(node, MIMETYPE_TAG, "mime-type",
585: null);
586: }
587:
588: // append node
589: parent.appendChild(node);
590: newLine(parent);
591:
592: // add configuration
593: String configuration = this .getTagValue(CONF_TAG, null);
594: if (configuration != null) {
595: configuration = "<root>" + configuration + "</root>";
596: final Document confDoc = DocumentCache.getDocument(
597: configuration, null);
598: setValue(node, null, confDoc.getDocumentElement()
599: .getChildNodes());
600: }
601:
602: return true;
603: }
604:
605: private void addAttribute(Node node, String tag,
606: String attributeName, String defaultValue) {
607: final String tagValue = this .getTagValue(tag, defaultValue);
608: if (tagValue != null) {
609: ((Element) node).setAttribute(attributeName, tagValue);
610: }
611: }
612:
613: private void newLine(Node node) {
614: final Node n = node.getOwnerDocument().createTextNode(
615: LINE_SEPARATOR);
616: node.appendChild(n);
617: }
618:
619: private void indent(Node node, int depth) {
620: final StringBuffer buffer = new StringBuffer();
621: for (int i = 0; i < depth * 2; i++) {
622: buffer.append(' ');
623: }
624: final Node n = node.getOwnerDocument().createTextNode(
625: buffer.toString());
626: node.appendChild(n);
627: }
628:
629: public void generateDocs(Document template, File docFile,
630: Project project) throws TransformerException {
631:
632: final String doc = this .getDocumentation();
633: if (doc == null) {
634: if (docFile.exists()) {
635: docFile.delete();
636: }
637: return;
638: }
639: // get body from template
640: final Node body = XPathAPI.selectSingleNode(template,
641: "/document/body");
642:
643: // append root element and surrounding paragraph
644: final String description = "<root><p>" + doc
645: + "</p></root>";
646: String systemURI = null;
647: try {
648: systemURI = docFile.toURL().toExternalForm();
649: } catch (MalformedURLException mue) {
650: // we ignore this
651: }
652: final Document descriptionDoc = DocumentCache.getDocument(
653: description, systemURI);
654:
655: // Title
656: setValue(template, "/document/header/title",
657: "Description of the " + this .name + " " + this .type);
658:
659: // Version
660: setValue(template, "/document/header/version", project
661: .getProperty("version"));
662:
663: // Description
664: setValue(body, "s1[@title='Description']", descriptionDoc
665: .getDocumentElement().getChildNodes());
666:
667: // check: deprecated?
668: if (SitemapTask.this .deprecated
669: || this .getTagValue("deprecated", null) != null) {
670: Node node = XPathAPI.selectSingleNode(body,
671: "s1[@title='Description']");
672: // node is never null - this is ensured by the test above
673: Element e = node.getOwnerDocument().createElement(
674: "note");
675: node.appendChild(e);
676: e.appendChild(node.getOwnerDocument().createTextNode(
677: "This component is deprecated."));
678: final String info = this
679: .getTagValue("deprecated", null);
680: if (info != null) {
681: e.appendChild(node.getOwnerDocument()
682: .createTextNode(info));
683: }
684: }
685: // check: stable?
686: if (!SitemapTask.this .stable) {
687: Node node = XPathAPI.selectSingleNode(body,
688: "s1[@title='Description']");
689: // node is never null - this is ensured by the test above
690: Element e = node.getOwnerDocument().createElement(
691: "note");
692: node.appendChild(e);
693: e.appendChild(node.getOwnerDocument().createTextNode(
694: "This component is in an unstable block."));
695: }
696:
697: // Info Table
698: final Node tableNode = XPathAPI.selectSingleNode(body,
699: "s1[@title='Info']/table");
700:
701: // Info - Name
702: this .addRow(tableNode, "Name", this .name);
703:
704: // Info - Block
705: if (SitemapTask.this .blockName != null) {
706: this .addRow(tableNode, "Block",
707: SitemapTask.this .blockName);
708: }
709:
710: // Info - Cacheable
711: if (this .javaClass.isA(GENERATOR)
712: || this .javaClass.isA(TRANSFORMER)
713: || this .javaClass.isA(SERIALIZER)
714: || this .javaClass.isA(READER)) {
715:
716: String cacheInfo;
717: if (this .javaClass.isA(CACHEABLE)) {
718: cacheInfo = this
719: .getTagValue(CACHING_INFO_TAG, null);
720: if (cacheInfo != null) {
721: cacheInfo = "Yes - " + cacheInfo;
722: } else {
723: cacheInfo = "Yes";
724: }
725: } else if (this .javaClass.isA(DEPRECATED_CACHEABLE)) {
726: cacheInfo = this
727: .getTagValue(CACHING_INFO_TAG, null);
728: if (cacheInfo != null) {
729: cacheInfo = "Yes (2.0 Caching) - " + cacheInfo;
730: } else {
731: cacheInfo = "Yes (2.0 Caching)";
732: }
733: } else {
734: cacheInfo = "No";
735: }
736: this .addRow(tableNode, "Cacheable", cacheInfo);
737: }
738:
739: // Info - mime-type
740: if (this .javaClass.isA(OUTPUT_COMPONENT)) {
741: final String value = this
742: .getTagValue(MIMETYPE_TAG, "-");
743: this .addRow(tableNode, "Mime-Type", value);
744: }
745:
746: // Info - Class
747: this .addRow(tableNode, "Class", this .javaClass
748: .getFullyQualifiedName());
749:
750: // merge with old doc
751: this .merge(body, docFile);
752:
753: // finally write the doc
754: DocumentCache.writeDocument(docFile, template,
755: SitemapTask.this );
756: }
757:
758: /**
759: * Merge the sections of the old document with the new generated one.
760: * All sections (s1) of the old document are added to the generated one
761: * if not a section with the same title exists.
762: */
763: private void merge(Node body, File docFile)
764: throws TransformerException {
765: final Document mergeDocument;
766: try {
767: mergeDocument = DocumentCache.getDocument(docFile,
768: SitemapTask.this );
769: } catch (Exception ignore) {
770: return;
771: }
772: NodeList sections = XPathAPI.selectNodeList(mergeDocument,
773: "/document/body/s1");
774: if (sections != null) {
775: for (int i = 0; i < sections.getLength(); i++) {
776: final Element current = (Element) sections.item(i);
777: final String title = current.getAttribute("title");
778:
779: // is this section not in the template?
780: if (XPathAPI.selectSingleNode(body, "s1[@title='"
781: + title + "']") == null) {
782: body.appendChild(body.getOwnerDocument()
783: .importNode(current, true));
784: }
785: }
786: }
787: }
788:
789: /**
790: * Return the documentation or null
791: * @return
792: */
793: private String getDocumentation() {
794: if (this .getTagValue(NO_DOC_TAG, null) != null) {
795: return null;
796: }
797: return this .getTagValue(DOC_TAG, null);
798: }
799:
800: private String getTagValue(String tagName, String defaultValue) {
801: final DocletTag tag = this .javaClass.getTagByName(tagName);
802: if (tag != null) {
803: return tag.getValue();
804: }
805: return defaultValue;
806: }
807:
808: private void addRow(Node table, String title, String value) {
809: final Element row = table.getOwnerDocument().createElement(
810: "tr");
811: final Element firstColumn = table.getOwnerDocument()
812: .createElement("td");
813: firstColumn.appendChild(table.getOwnerDocument()
814: .createTextNode(title));
815: final Element secondColumn = table.getOwnerDocument()
816: .createElement("td");
817: secondColumn.appendChild(table.getOwnerDocument()
818: .createTextNode(value));
819: row.appendChild(firstColumn);
820: row.appendChild(secondColumn);
821: table.appendChild(row);
822: }
823:
824: private void setValue(Node node, String xpath, String value) {
825: try {
826: final Node insertNode = (xpath == null ? node
827: : XPathAPI.selectSingleNode(node, xpath));
828: if (insertNode == null) {
829: throw new BuildException("Node (" + xpath
830: + ") not found.");
831: }
832: Node text = insertNode.getOwnerDocument()
833: .createTextNode(value);
834: while (insertNode.hasChildNodes()) {
835: insertNode.removeChild(insertNode.getFirstChild());
836: }
837: insertNode.appendChild(text);
838: } catch (TransformerException e) {
839: throw new BuildException(e);
840: }
841: }
842:
843: private void setValue(Node node, String xpath, NodeList nodes) {
844: try {
845: final Node insertNode = (xpath == null ? node
846: : XPathAPI.selectSingleNode(node, xpath));
847: if (insertNode == null) {
848: throw new BuildException("Node (" + xpath
849: + ") not found.");
850: }
851: while (insertNode.hasChildNodes()) {
852: insertNode.removeChild(insertNode.getFirstChild());
853: }
854: for (int i = 0; i < nodes.getLength(); i++) {
855: final Node current = nodes.item(i);
856: insertNode.appendChild(insertNode
857: .getOwnerDocument().importNode(current,
858: true));
859: }
860: } catch (TransformerException e) {
861: throw new BuildException(e);
862: }
863: }
864: }
865:
866: // Class Constants
867: private static final String LOG_ENABLED = "org.apache.avalon.framework.logger.LogEnabled";
868: private static final String POOLABLE = "org.apache.avalon.excalibur.pool.Poolable";
869:
870: private static final String CACHEABLE = "org.apache.cocoon.caching.CacheableProcessingComponent";
871: private static final String DEPRECATED_CACHEABLE = "org.apache.cocoon.caching.Cacheable";
872:
873: private static final String OUTPUT_COMPONENT = "org.apache.cocoon.sitemap.SitemapOutputComponent";
874:
875: private static final String GENERATOR = "org.apache.cocoon.generation.Generator";
876: private static final String TRANSFORMER = "org.apache.cocoon.transformation.Transformer";
877: private static final String SERIALIZER = "org.apache.cocoon.serialization.Serializer";
878: private static final String READER = "org.apache.cocoon.reading.Reader";
879: private static final String MATCHER = "org.apache.cocoon.matching.Matcher";
880: private static final String SELECTOR = "org.apache.cocoon.selection.Selector";
881: private static final String ACTION = "org.apache.cocoon.acting.Action";
882: private static final String PIPELINE = "org.apache.cocoon.components.pipeline.ProcessingPipeline";
883: }
|