0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017: package org.apache.cocoon.components.source.impl;
0018:
0019: import java.io.BufferedReader;
0020: import java.io.ByteArrayInputStream;
0021: import java.io.ByteArrayOutputStream;
0022: import java.io.IOException;
0023: import java.io.InputStream;
0024: import java.io.InputStreamReader;
0025: import java.net.MalformedURLException;
0026: import java.util.ArrayList;
0027: import java.util.HashMap;
0028: import java.util.List;
0029: import java.util.Map;
0030:
0031: import com.thoughtworks.qdox.JavaDocBuilder;
0032: import com.thoughtworks.qdox.model.AbstractJavaEntity;
0033: import com.thoughtworks.qdox.model.DocletTag;
0034: import com.thoughtworks.qdox.model.JavaClass;
0035: import com.thoughtworks.qdox.model.JavaField;
0036: import com.thoughtworks.qdox.model.JavaMethod;
0037: import com.thoughtworks.qdox.model.JavaParameter;
0038: import com.thoughtworks.qdox.model.JavaSource;
0039: import com.thoughtworks.qdox.model.Type;
0040:
0041: import org.apache.avalon.excalibur.pool.Recyclable;
0042: import org.apache.avalon.framework.logger.Logger;
0043: import org.apache.avalon.framework.service.ServiceException;
0044: import org.apache.avalon.framework.service.ServiceManager;
0045: import org.apache.avalon.framework.service.ServiceSelector;
0046: import org.apache.cocoon.serialization.Serializer;
0047: import org.apache.cocoon.xml.XMLUtils;
0048:
0049: import org.apache.commons.lang.StringUtils;
0050: import org.apache.excalibur.source.Source;
0051: import org.apache.excalibur.source.SourceException;
0052: import org.apache.excalibur.source.SourceResolver;
0053: import org.apache.excalibur.source.SourceValidity;
0054: import org.apache.excalibur.source.impl.AbstractSource;
0055: import org.apache.excalibur.xml.sax.XMLizable;
0056: import org.apache.regexp.RE;
0057: import org.apache.regexp.RESyntaxException;
0058: import org.xml.sax.ContentHandler;
0059: import org.xml.sax.SAXException;
0060: import org.xml.sax.helpers.AttributesImpl;
0061:
0062: /**
0063: * Source implementation for XML Javadoc.
0064: *
0065: * @author <a href="mailto:b.guijt1@chello.nl">Bart Guijt</a>
0066: * @version $Id: QDoxSource.java 550582 2007-06-25 19:31:50Z joerg $ $Date: 2004/04/30 22:50:39 $
0067: */
0068: public final class QDoxSource extends AbstractSource implements
0069: XMLizable, Recyclable {
0070:
0071: protected final static String ROOT_CLASSNAME = "java.lang.Object";
0072:
0073: protected final static String PROTOCOL = "qdox:";
0074: protected final static String NS_URI = "http://apache.org/cocoon/javadoc/1.0";
0075: protected final static String NS_PREFIX = "jd";
0076: protected final static String ATTR_TYPE = "NMTOKEN";
0077:
0078: protected final static String CLASS_ELEMENT = "class";
0079: protected final static String CLASSNAME_ATTRIBUTE = "name";
0080: protected final static String PACKAGE_ATTRIBUTE = "package";
0081: protected final static String QNAME_ATTRIBUTE = "qname";
0082: protected final static String INHERIT_ELEMENT = "inherit";
0083: protected final static String INNERCLASSES_ELEMENT = "innerclasses";
0084: protected final static String NESTED_IN_ELEMENT = "nested-in";
0085: protected final static String IMPORTS_ELEMENT = "imports";
0086: protected final static String IMPORT_ELEMENT = "import";
0087: protected final static String IMPORT_ATTRIBUTE = "type";
0088: protected final static String IMPLEMENTS_ELEMENT = "implements";
0089: protected final static String INTERFACE_ELEMENT = "interface";
0090: protected final static String MODIFIERS_ELEMENT = "modifiers";
0091: protected final static String COMMENT_ELEMENT = "comment";
0092: protected final static String LINK_ELEMENT = "link";
0093: protected final static String LINK_CLASS_ATTRIBUTE = "class";
0094: protected final static String LINK_MEMBER_ATTRIBUTE = "member";
0095: protected final static String HREF_ATTRIBUTE = "uri";
0096: protected final static String TAGS_ELEMENT = "tags";
0097: protected final static String FIELDS_ELEMENT = "fields";
0098: protected final static String FIELD_ELEMENT = "field";
0099: protected final static String CONSTRUCTORS_ELEMENT = "constructors";
0100: protected final static String CONSTRUCTOR_ELEMENT = "constructor";
0101: protected final static String METHODS_ELEMENT = "methods";
0102: protected final static String METHOD_ELEMENT = "method";
0103: protected final static String NAME_ATTRIBUTE = "name";
0104: protected final static String TYPE_ATTRIBUTE = "type";
0105: protected final static String DIMENSIONS_ATTRIBUTE = "dimensions";
0106: protected final static String SIGNATURE_ATTRIBUTE = "signature";
0107: protected final static String PARAMETERS_ELEMENT = "parameters";
0108: protected final static String PARAMETER_ELEMENT = "parameter";
0109: protected final static String THROWS_ELEMENT = "throws";
0110: protected final static String EXCEPTION_ELEMENT = "exception";
0111:
0112: protected final static int CONSTRUCTOR_MODE = 1;
0113: protected final static int METHOD_MODE = 2;
0114:
0115: protected final static int CLASS_INHERITANCE = 1;
0116: protected final static int INTERFACE_INHERITANCE = 2;
0117: protected final static int INNERCLASS_INHERITANCE = 3;
0118: protected final static int FIELD_INHERITANCE = 4;
0119: protected final static int CONSTRUCTOR_INHERITANCE = 5;
0120: protected final static int METHOD_INHERITANCE = 6;
0121:
0122: protected ServiceManager manager;
0123: protected Logger logger;
0124:
0125: protected Source javaSource;
0126: protected String javadocUri;
0127: protected String javadocClassName;
0128: protected JavaClass javadocClass;
0129: protected JavaClass containingJavadocClass; // in case javadocClass is an inner class
0130: protected Map classMap;
0131:
0132: /**
0133: * This RegExp matches the <code>{</code><code>@link …}</code> occurrances in
0134: * Javadoc comments.
0135: */
0136: protected RE reLink;
0137:
0138: // TODO: make this actually configurable
0139: private String configuredSerializerName = "xml";
0140:
0141: /**
0142: * Contains a regular expression to match the <code>{</code><code>@link …}</code> occurrances.
0143: *
0144: * <p>The following <code>{</code><code>@link …}</code> literals are recognized:</p>
0145: *
0146: * <ul>
0147: * <li><code>{</code><code>@link HashMap}</code> - returns 'Hashmap' with <code>reLink.getParen(6)</code>;</li>
0148: * <li><code>{</code><code>@link #equals(java.lang.Object) equals(…)}</code> - returns '#equals(java.lang.Object)' with <code>reLink.getParen(2)</code>
0149: * and 'equals(…)' with <code>reLink.getParen(5)</code>;</li>
0150: * <li><code>{</code><code>@link #indexOf(char, int) indexOf(…)}</code> - returns '#indexOf(char, int)' with <code>reLink.getParen(2)</code>
0151: * and 'indexOf(…)' with <code>reLink.getParen(5)</code>.</li>
0152: * </ul>
0153: * <p>The regexp is as follows:</p>
0154: * <code>\{\@link\s+((([\w.#,$&;\s]+)|([\w.#,$&;(\s]+[\w.#,$&;)\s]+))\s+([\w()#.,$&;\s]+)|([\w.#,$&;\s()]+))\s*\}</code>
0155: *
0156: * @see #reLink
0157: */
0158: protected final static String RE_LINK = "\\{@link\\s+((([\\w.#,$&;\\s]+)|([\\w.#,$&;(\\s]+[\\w.#,$&;)\\s]+))\\s+([\\w()#.,$&;\\s]+)|([\\w.#,$&;\\s()]+))\\s*\\}";
0159:
0160: /**
0161: * Constructor for QDoxSource.
0162: *
0163: * @param location
0164: * @param javaSource
0165: * @param logger
0166: * @param manager
0167: */
0168: public QDoxSource(String location, Source javaSource,
0169: Logger logger, ServiceManager manager) {
0170: this .javadocUri = location;
0171: this .javaSource = javaSource;
0172: this .logger = logger;
0173: this .manager = manager;
0174: this .javadocClassName = javadocUri.substring(javadocUri
0175: .indexOf(':') + 1);
0176: try {
0177: createJavadocXml();
0178: } catch (SourceException se) {
0179: logger.error("Error reading source!", se);
0180: } catch (IOException ioe) {
0181: logger.error("Error reading source!", ioe);
0182: }
0183: // Initialize regular expression:
0184: try {
0185: reLink = new RE(RE_LINK);
0186: } catch (RESyntaxException rse) {
0187: logger.error("Regular Expression syntax error!", rse);
0188: }
0189: }
0190:
0191: /**
0192: * Returns the parsed Java class.
0193: *
0194: * @return JavaClass
0195: */
0196: public JavaClass getJavadocClass() {
0197: return javadocClass;
0198: }
0199:
0200: /**
0201: * @see XMLizable#toSAX(org.xml.sax.ContentHandler)
0202: * @throws SAXException if any error occurs during SAX outputting.
0203: */
0204: public void toSAX(ContentHandler handler) throws SAXException {
0205: if (javadocClass == null) {
0206: logger
0207: .error("No classfile loaded! Cannot output SAX events.");
0208: return;
0209: }
0210:
0211: if (logger.isDebugEnabled()) {
0212: logger.debug("Outputting SAX events for class "
0213: + javadocClass.getFullyQualifiedName());
0214: logger.debug(" #fields: "
0215: + javadocClass.getFields().length);
0216: logger.debug(" #methods and constructors: "
0217: + javadocClass.getMethods().length);
0218: }
0219:
0220: // Output SAX 'header':
0221: handler.startDocument();
0222: handler.startPrefixMapping(NS_PREFIX, NS_URI);
0223:
0224: // Output class-level element:
0225: outputClassStartElement(handler, javadocClass);
0226:
0227: // Modifiers:
0228: outputModifiers(handler, javadocClass);
0229:
0230: // Imports:
0231: JavaSource parent = javadocClass.getParentSource();
0232: // Add two implicit imports:
0233: parent.addImport("java.lang.*");
0234: if (parent.getPackage() != null) {
0235: parent.addImport(parent.getPackage() + ".*");
0236: } else {
0237: parent.addImport("*");
0238: }
0239: String[] imports = parent.getImports();
0240:
0241: saxStartElement(handler, IMPORTS_ELEMENT);
0242: for (int i = 0; i < imports.length; i++) {
0243: if (imports[i].endsWith("*")) {
0244: // package import:
0245: saxStartElement(
0246: handler,
0247: IMPORT_ELEMENT,
0248: new String[][] { { IMPORT_ATTRIBUTE, "package" } });
0249: String imp = StringUtils.substringBeforeLast(
0250: imports[i], ".*");
0251: saxCharacters(handler, imp);
0252: } else {
0253: saxStartElement(
0254: handler,
0255: IMPORT_ELEMENT,
0256: new String[][] { { IMPORT_ATTRIBUTE, "class" } });
0257: saxCharacters(handler, imports[i]);
0258: }
0259: saxEndElement(handler, IMPORT_ELEMENT);
0260: }
0261: saxEndElement(handler, IMPORTS_ELEMENT);
0262:
0263: // Superclass:
0264: if (!javadocClass.isInterface()) {
0265: outputSuperClassInheritance(handler, javadocClass,
0266: CLASS_INHERITANCE);
0267: }
0268:
0269: // Implements:
0270: outputImplements(handler, javadocClass, true);
0271:
0272: // Containing class in case this is an inner class:
0273: if (containingJavadocClass != null) {
0274: saxStartElement(handler, NESTED_IN_ELEMENT);
0275: outputClassStartElement(handler, containingJavadocClass);
0276: outputModifiers(handler, containingJavadocClass);
0277: outputComment(handler, containingJavadocClass.getComment());
0278: outputTags(handler, containingJavadocClass);
0279: outputClassEndElement(handler, containingJavadocClass);
0280: saxEndElement(handler, NESTED_IN_ELEMENT);
0281: }
0282:
0283: // Comment:
0284: outputComment(handler, javadocClass.getComment());
0285:
0286: // Tags:
0287: outputTags(handler, javadocClass);
0288:
0289: // Inner classes:
0290: outputInnerClasses(handler, javadocClass, true);
0291:
0292: // Fields:
0293: outputFields(handler, javadocClass, true);
0294:
0295: // Constructors:
0296: outputMethods(handler, javadocClass, CONSTRUCTOR_MODE);
0297:
0298: // Methods:
0299: outputMethods(handler, javadocClass, METHOD_MODE);
0300:
0301: // Close class-level element:
0302: outputClassEndElement(handler, javadocClass);
0303:
0304: // Output SAX 'footer':
0305: handler.endPrefixMapping(NS_PREFIX);
0306: handler.endDocument();
0307: }
0308:
0309: /**
0310: * @see Recyclable#recycle()
0311: */
0312: public void recycle() {
0313: if (logger != null && logger.isDebugEnabled()) {
0314: logger.debug("Recycling QDoxSource '" + javadocClassName
0315: + "'...");
0316: }
0317:
0318: manager = null;
0319: javaSource = null;
0320: javadocUri = null;
0321: javadocClassName = null;
0322: javadocClass = null;
0323: containingJavadocClass = null;
0324: classMap = null;
0325: logger = null;
0326: }
0327:
0328: /**
0329: * Get the content length of the source or -1 if it
0330: * is not possible to determine the length.
0331: */
0332: public long getContentLength() {
0333: return -1L;
0334: }
0335:
0336: /**
0337: * @see org.apache.excalibur.source.Source#getLastModified()
0338: */
0339: public long getLastModified() {
0340: return javaSource.getLastModified();
0341: }
0342:
0343: /**
0344: * @see org.apache.excalibur.source.Source#getMimeType()
0345: */
0346: public String getMimeType() {
0347: return "text/xml";
0348: }
0349:
0350: /**
0351: * Return the unique identifer for this source
0352: */
0353: public String getURI() {
0354: return javadocUri;
0355: }
0356:
0357: /**
0358: * @see org.apache.excalibur.source.Source#getValidity()
0359: */
0360: public SourceValidity getValidity() {
0361: return javaSource.getValidity();
0362: }
0363:
0364: /**
0365: * @see org.apache.excalibur.source.Source#getInputStream()
0366: */
0367: public InputStream getInputStream() throws IOException,
0368: SourceException {
0369: if (this .logger.isDebugEnabled()) {
0370: this .logger.debug("Getting InputStream for class "
0371: + this .javadocClass.getFullyQualifiedName());
0372: }
0373:
0374: // Serialize the SAX events to the XMLSerializer
0375: ByteArrayInputStream inputStream = null;
0376:
0377: ServiceSelector selector = null;
0378: Serializer serializer = null;
0379: try {
0380: selector = (ServiceSelector) this .manager
0381: .lookup(Serializer.ROLE + "Selector");
0382: serializer = (Serializer) selector
0383: .select(this .configuredSerializerName);
0384:
0385: ByteArrayOutputStream outputStream = new ByteArrayOutputStream(
0386: 2048);
0387: serializer.setOutputStream(outputStream);
0388: toSAX(serializer);
0389: inputStream = new ByteArrayInputStream(outputStream
0390: .toByteArray());
0391: } catch (SAXException e) {
0392: throw new SourceException(
0393: "Serializing SAX to a ByteArray failed!", e);
0394: } catch (ServiceException e) {
0395: throw new SourceException("Retrieving serializer failed.",
0396: e);
0397: } finally {
0398: if (selector != null) {
0399: selector.release(serializer);
0400: this .manager.release(selector);
0401: }
0402: }
0403: return inputStream;
0404: }
0405:
0406: protected void createJavadocXml() throws SourceException,
0407: IOException {
0408: if (logger.isDebugEnabled()) {
0409: logger.debug("Reading Java source " + javaSource.getURI());
0410: }
0411: JavaDocBuilder builder = new JavaDocBuilder();
0412: builder.addSource(new BufferedReader(new InputStreamReader(
0413: javaSource.getInputStream())));
0414:
0415: javadocClass = builder.getClassByName(javadocClassName);
0416: if (javadocClass.getPackage() == null) {
0417: // An inner class is specified - let's find it:
0418: int index = javadocClassName.lastIndexOf('.');
0419: String containingClassName = javadocClassName.substring(0,
0420: index);
0421: String innerClassName = javadocClassName
0422: .substring(index + 1);
0423: containingJavadocClass = builder
0424: .getClassByName(containingClassName);
0425: javadocClass = containingJavadocClass
0426: .getInnerClassByName(innerClassName);
0427: }
0428: }
0429:
0430: /**
0431: * Method resolveClassNameFromLink.
0432: *
0433: * @param ref
0434: * @return String
0435: */
0436: private String resolveClassNameFromLink(String ref) {
0437: String classPart = null;
0438: int hashIndex = ref.indexOf('#');
0439: if (hashIndex < 0) {
0440: classPart = ref;
0441: } else {
0442: classPart = ref.substring(0, hashIndex);
0443: }
0444: return getQualifiedClassName(classPart);
0445: }
0446:
0447: private String getQualifiedClassName(String classPart) {
0448: if (classPart.length() == 0) {
0449: // No classname specified:
0450: classPart = javadocClass.getFullyQualifiedName();
0451: } else if (classPart.equals("Object")) {
0452: // Fastest way to identify the root object - otherwise the next, *expensive* 'if' block is executed!
0453: classPart = ROOT_CLASSNAME;
0454: } else if (classPart.indexOf('.') < 0) {
0455: // No qualified name specified:
0456: String[] imports = javadocClass.getParentSource()
0457: .getImports();
0458: List classImports = new ArrayList();
0459: List packageImports = new ArrayList();
0460: packageImports.add(javadocClass.getPackage()); // Most likely to find sources here, I guess...
0461: packageImports.add("java.lang"); // 2nd most likely place to find sources?
0462: for (int i = 0; i < imports.length; i++) {
0463: if (imports[i].endsWith(".*")) {
0464: packageImports.add(imports[i].substring(0,
0465: imports[i].length() - 2));
0466: } else if (imports[i].endsWith("*")) {
0467: packageImports.add(imports[i].substring(0,
0468: imports[i].length() - 1));
0469: } else {
0470: classImports.add(imports[i]);
0471: }
0472: }
0473:
0474: boolean found = false;
0475: for (int i = 0; !found && i < classImports.size(); i++) {
0476: String name = (String) classImports.get(i);
0477: if (name.endsWith(classPart)) {
0478: classPart = name;
0479: found = true;
0480: }
0481: }
0482:
0483: if (!found) {
0484: SourceResolver resolver = null;
0485: try {
0486: resolver = (SourceResolver) manager
0487: .lookup(SourceResolver.ROLE);
0488: for (int i = 0; !found && i < packageImports.size(); i++) {
0489: String name = (String) packageImports.get(i);
0490: if (name.length() == 0) {
0491: name = classPart;
0492: } else {
0493: name += '.' + classPart;
0494: }
0495:
0496: // Test whether the classname 'name' is valid:
0497: Source source = resolver.resolveURI(PROTOCOL
0498: + name);
0499: found = source != null
0500: && source instanceof QDoxSource;
0501: if (found) {
0502: classPart = name;
0503: }
0504:
0505: resolver.release(source);
0506: }
0507: } catch (ServiceException se) {
0508: logger
0509: .error("Could not find a SourceResolver!",
0510: se);
0511: } catch (MalformedURLException e) {
0512: // ignore - invalid URI (is subject of test)
0513: } catch (SourceException e) {
0514: // ignore
0515: } catch (IOException e) {
0516: // ignore
0517: } finally {
0518: if (resolver != null) {
0519: manager.release(resolver);
0520: }
0521: }
0522: }
0523: }
0524: return classPart;
0525: }
0526:
0527: /**
0528: * Method outputClassInheritance.
0529: *
0530: * @param handler
0531: * @param jClass
0532: */
0533: private void outputSuperClassInheritance(ContentHandler handler,
0534: JavaClass jClass, int mode) throws SAXException {
0535: JavaClass super Class = getJavadocSuperClass(jClass);
0536: if (super Class != null && hasInheritance(jClass, mode)) {
0537: outputClassInheritance(handler, super Class, mode);
0538: }
0539: }
0540:
0541: private void outputClassInheritance(ContentHandler handler,
0542: JavaClass jClass, int mode) throws SAXException {
0543: outputInheritStartElement(handler, jClass);
0544:
0545: switch (mode) {
0546: case CLASS_INHERITANCE:
0547: // Already there!
0548: outputSuperClassInheritance(handler, jClass, mode);
0549: break;
0550:
0551: case INTERFACE_INHERITANCE:
0552: // Output interface inheritance summary:
0553: outputImplements(handler, jClass, false);
0554: break;
0555:
0556: case INNERCLASS_INHERITANCE:
0557: // Output nested inheritance summary:
0558: outputInnerClasses(handler, jClass, false);
0559: break;
0560:
0561: case FIELD_INHERITANCE:
0562: // Output field inheritance summary:
0563: outputFields(handler, jClass, false);
0564: break;
0565:
0566: case METHOD_INHERITANCE:
0567: // Output method inheritance summary from implemented interfaces:
0568: Type[] interfaces = jClass.getImplements();
0569: for (int i = 0; i < interfaces.length; i++) {
0570: logger
0571: .debug("inherit from "
0572: + interfaces[i].getValue());
0573: outputClassInheritance(handler,
0574: getJavaClass(interfaces[i].getValue()), mode);
0575: }
0576:
0577: case CONSTRUCTOR_INHERITANCE:
0578: // Output method/constructor inheritance summary from superclass:
0579: if (!(mode == METHOD_INHERITANCE && jClass.isInterface())) {
0580: outputSuperClassInheritance(handler, jClass, mode);
0581: }
0582: JavaMethod[] methods = jClass.getMethods();
0583: for (int i = 0; i < methods.length; i++) {
0584: if ((mode == METHOD_INHERITANCE && methods[i]
0585: .getReturns() != null)
0586: || (mode == CONSTRUCTOR_INHERITANCE && methods[i]
0587: .getReturns() == null)) {
0588: outputMethodStartElement(handler, methods[i]);
0589: outputMethodEndElement(handler, methods[i]);
0590: }
0591: }
0592: break;
0593: default:
0594: break;
0595: }
0596: saxEndElement(handler, INHERIT_ELEMENT);
0597: }
0598:
0599: private boolean hasInheritance(JavaClass jClass, int mode) {
0600: JavaClass super Class = getJavadocSuperClass(jClass);
0601: boolean result = false;
0602:
0603: if (super Class != null) {
0604: switch (mode) {
0605: case CLASS_INHERITANCE:
0606: // Already there!
0607: result = true;
0608: break;
0609:
0610: case INTERFACE_INHERITANCE:
0611: result = super Class.getImplements().length > 0;
0612: break;
0613:
0614: case INNERCLASS_INHERITANCE:
0615: result = super Class.getInnerClasses().length > 0;
0616: break;
0617:
0618: case FIELD_INHERITANCE:
0619: result = super Class.getFields().length > 0;
0620: break;
0621:
0622: case METHOD_INHERITANCE:
0623: Type[] interfaces = jClass.getImplements();
0624: for (int i = 0; i < interfaces.length && !result; i++) {
0625: JavaClass iface = getJavaClass(interfaces[i]
0626: .getValue());
0627: result = iface != null
0628: && iface.getMethods().length > 0;
0629: }
0630:
0631: case CONSTRUCTOR_INHERITANCE:
0632: JavaMethod[] methods = super Class.getMethods();
0633: for (int i = 0; i < methods.length && !result; i++) {
0634: result = ((mode == METHOD_INHERITANCE && methods[i]
0635: .getReturns() != null) || (mode == CONSTRUCTOR_INHERITANCE && methods[i]
0636: .getReturns() == null));
0637: }
0638: break;
0639:
0640: default:
0641: break;
0642: }
0643:
0644: if (!result) {
0645: result = hasInheritance(super Class, mode);
0646: }
0647: }
0648:
0649: return result;
0650: }
0651:
0652: /**
0653: * Method getJavadocSuperClass.
0654: *
0655: * @param jClass
0656: * @return JavaClass
0657: */
0658: private JavaClass getJavadocSuperClass(JavaClass jClass) {
0659: if (jClass == null) {
0660: // May not happen, of course ;-)
0661: throw new IllegalArgumentException(
0662: "Argument 'jClass' must not be <null>!");
0663: }
0664:
0665: if (jClass.getFullyQualifiedName().equals(ROOT_CLASSNAME)) {
0666: // jClass is root class:
0667: return null;
0668: }
0669:
0670: JavaClass super Class = null;
0671:
0672: if (!jClass.isInterface()) {
0673: try {
0674: // Use QDocx operation to retrieve class:
0675: super Class = jClass.getSuperJavaClass();
0676: } catch (UnsupportedOperationException uoe) {
0677: // No Cache built (yet)... ignore!
0678: }
0679: }
0680:
0681: if (super Class == null) {
0682: String super JavadocClassName = null;
0683:
0684: if (jClass.isInterface()) {
0685: Type[] interfaces = jClass.getImplements();
0686: if (interfaces.length == 1) {
0687: super JavadocClassName = interfaces[0].getValue();
0688: }
0689: } else {
0690: super JavadocClassName = jClass.getSuperClass()
0691: .getValue();
0692:
0693: // Is the superClass itself an inner class?
0694: if (super JavadocClassName.indexOf('.') == -1
0695: && containingJavadocClass
0696: .getInnerClassByName(super JavadocClassName) != null) {
0697: super JavadocClassName = containingJavadocClass
0698: .getFullyQualifiedName()
0699: + '.' + super JavadocClassName;
0700: }
0701: }
0702:
0703: if (super JavadocClassName != null) {
0704: super Class = getJavaClass(super JavadocClassName);
0705: }
0706: }
0707:
0708: return super Class;
0709: }
0710:
0711: /**
0712: * Method getInnerClass.
0713: *
0714: * @param jClass
0715: * @param className
0716: * @return JavaClass
0717: */
0718: /* private JavaClass getJavadocInnerClass(JavaClass jClass, String className) {
0719: if (jClass != null) {
0720: JavaClass[] classes = jClass.getInnerClasses();
0721:
0722: for (int i=0; i<classes.length; i++) {
0723: if (classes[i].getName().equals(className)) {
0724: return classes[i];
0725: }
0726: }
0727: }
0728: return null;
0729: }*/
0730:
0731: /**
0732: * Get the meta class for the specified classname. The result is cached internally.
0733: *
0734: * @param className
0735: * @return JavaClass
0736: */
0737: private JavaClass getJavaClass(String className) {
0738: if (classMap != null && classMap.containsKey(className)) {
0739: return (JavaClass) classMap.get(className);
0740: }
0741:
0742: JavaClass jClass = null;
0743: SourceResolver resolver = null;
0744:
0745: try {
0746: resolver = (SourceResolver) manager
0747: .lookup(SourceResolver.ROLE);
0748: Source source = resolver.resolveURI(PROTOCOL + className);
0749: if (source instanceof QDoxSource) {
0750: QDoxSource javadocSource = (QDoxSource) source;
0751: jClass = javadocSource.getJavadocClass();
0752: if (classMap == null) {
0753: classMap = new HashMap();
0754: }
0755: classMap.put(className, jClass);
0756: }
0757: resolver.release(source);
0758: } catch (ServiceException se) {
0759: logger.error("Couldn't return JavaClass!", se);
0760: } catch (MalformedURLException mue) {
0761: logger.error("Couldn't return JavaClass!", mue);
0762: } catch (SourceException se) {
0763: logger.error("Couldn't return JavaClass!", se);
0764: } catch (IOException ioe) {
0765: logger.error("Couldn't return JavaClass!", ioe);
0766: } finally {
0767: if (resolver != null) {
0768: manager.release(resolver);
0769: }
0770: }
0771:
0772: return jClass;
0773: }
0774:
0775: /**
0776: * Method outputModifiers.
0777: *
0778: * @param handler
0779: * @param entity
0780: */
0781: private void outputModifiers(ContentHandler handler,
0782: AbstractJavaEntity entity) throws SAXException {
0783: String[] modifiers = entity.getModifiers();
0784: if (modifiers.length > 0) {
0785: saxStartElement(handler, MODIFIERS_ELEMENT);
0786: for (int i = 0; i < modifiers.length; i++) {
0787: saxStartElement(handler, modifiers[i]);
0788: saxEndElement(handler, modifiers[i]);
0789: }
0790: saxEndElement(handler, MODIFIERS_ELEMENT);
0791: }
0792: }
0793:
0794: /**
0795: * Method outputCommentAndTags.
0796: *
0797: * @param handler
0798: * @param entity
0799: */
0800: private void outputTags(ContentHandler handler,
0801: AbstractJavaEntity entity) throws SAXException {
0802: DocletTag[] tags = entity.getTags();
0803:
0804: boolean tagElementPassed = false;
0805: for (int i = 0; i < tags.length; i++) {
0806: String tagName = tags[i].getName();
0807: String value = tags[i].getValue();
0808: if (!tagElementPassed && !tagName.equals("throws")
0809: && !tagName.equals("param")) {
0810: saxStartElement(handler, TAGS_ELEMENT);
0811: tagElementPassed = true;
0812: }
0813:
0814: if (tagName.equals("see")) {
0815: saxStartElement(handler, tagName);
0816: outputLink(handler, value, null);
0817: saxEndElement(handler, tagName);
0818: } else if (!tagName.equals("throws")
0819: && !tagName.equals("param")) {
0820: // the 'throws' and 'param' tags are handled at method exception and method parameter level:
0821: saxStartElement(handler, tagName);
0822: outputComment(handler, value);
0823: saxEndElement(handler, tagName);
0824: }
0825: }
0826:
0827: if (tagElementPassed) {
0828: saxEndElement(handler, TAGS_ELEMENT);
0829: }
0830: }
0831:
0832: /**
0833: * Outputs a Javadoc comment.
0834: *
0835: * @param handler SAX ContentHandler
0836: * @param comment The Javadoc comment
0837: * @throws SAXException if something goes wrong
0838: */
0839: private void outputComment(ContentHandler handler, String comment)
0840: throws SAXException {
0841: if (comment != null && comment.length() > 0) {
0842: saxStartElement(handler, COMMENT_ELEMENT);
0843: while (reLink.match(comment)) {
0844: String ref = null;
0845: String display = null;
0846: if (reLink.getParen(6) == null) {
0847: // {@link xxx yyy}
0848: ref = reLink.getParen(2);
0849: display = reLink.getParen(5);
0850: } else {
0851: // {@link xxx}
0852: ref = reLink.getParen(6);
0853: display = "";
0854: }
0855: // Output SAX:
0856: saxCharacters(handler, comment.substring(0, reLink
0857: .getParenStart(0)));
0858: outputLink(handler, ref, display);
0859: // Cut from doc:
0860: comment = comment.substring(reLink.getParenEnd(0));
0861: }
0862: saxCharacters(handler, comment);
0863: saxEndElement(handler, COMMENT_ELEMENT);
0864: }
0865: }
0866:
0867: /**
0868: * Method outputLink.
0869: *
0870: * @param handler
0871: * @param ref
0872: * @param display
0873: */
0874: private void outputLink(ContentHandler handler, String ref,
0875: String display) throws SAXException {
0876: String classPart = resolveClassNameFromLink(ref);
0877: String memberPart = StringUtils.substringAfter(ref, "#");
0878: String displayPart = display;
0879:
0880: List attrs = new ArrayList();
0881:
0882: if (StringUtils.isNotEmpty(classPart)) {
0883: attrs.add(new String[] { LINK_CLASS_ATTRIBUTE, classPart });
0884: }
0885:
0886: if (StringUtils.isNotEmpty(memberPart)) {
0887: attrs
0888: .add(new String[] { LINK_MEMBER_ATTRIBUTE,
0889: memberPart });
0890: }
0891:
0892: if (StringUtils.isEmpty(display)
0893: && !ref.equals(classPart + "#" + memberPart)) {
0894: displayPart = ref.replace('#', '.');
0895: }
0896:
0897: saxStartElement(handler, LINK_ELEMENT, (String[][]) attrs
0898: .toArray(new String[][] { {} }));
0899: saxCharacters(handler, displayPart);
0900: saxEndElement(handler, LINK_ELEMENT);
0901: }
0902:
0903: /**
0904: * Method outputInnerClasses.
0905: *
0906: * @param handler
0907: * @param jClass
0908: * @param detailed
0909: */
0910: private void outputInnerClasses(ContentHandler handler,
0911: JavaClass jClass, boolean detailed) throws SAXException {
0912: JavaClass[] innerClasses = jClass.getInnerClasses();
0913: if (innerClasses.length > 0
0914: || hasInheritance(jClass, INNERCLASS_INHERITANCE)) {
0915: if (detailed) {
0916: saxStartElement(handler, INNERCLASSES_ELEMENT);
0917: }
0918:
0919: // Output inheritance:
0920: outputSuperClassInheritance(handler, jClass,
0921: INNERCLASS_INHERITANCE);
0922:
0923: for (int i = 0; i < innerClasses.length; i++) {
0924: outputClassStartElement(handler, innerClasses[i]);
0925: if (detailed) {
0926: outputModifiers(handler, innerClasses[i]);
0927: outputComment(handler, innerClasses[i].getComment());
0928: outputTags(handler, innerClasses[i]);
0929: }
0930: outputClassEndElement(handler, innerClasses[i]);
0931: }
0932:
0933: if (detailed) {
0934: saxEndElement(handler, INNERCLASSES_ELEMENT);
0935: }
0936: }
0937: }
0938:
0939: /**
0940: * Method outputImplements.
0941: *
0942: * @param handler
0943: * @param jClass
0944: */
0945: private void outputImplements(ContentHandler handler,
0946: JavaClass jClass, boolean detailed) throws SAXException {
0947: Type[] interfaces = jClass.getImplements();
0948: if (interfaces.length > 0
0949: || hasInheritance(jClass, INTERFACE_INHERITANCE)) {
0950: if (detailed) {
0951: saxStartElement(handler, IMPLEMENTS_ELEMENT);
0952: }
0953:
0954: // Output inheritance:
0955: outputSuperClassInheritance(handler, jClass,
0956: INTERFACE_INHERITANCE);
0957:
0958: for (int i = 0; i < interfaces.length; i++) {
0959: String name = interfaces[i].getValue();
0960: String pckg = name.substring(0, name.lastIndexOf('.'));
0961: name = name.substring(pckg.length() + 1);
0962:
0963: saxStartElement(
0964: handler,
0965: INTERFACE_ELEMENT,
0966: new String[][] { { CLASSNAME_ATTRIBUTE, name },
0967: { PACKAGE_ATTRIBUTE, pckg },
0968: { QNAME_ATTRIBUTE, pckg + '.' + name } });
0969: saxEndElement(handler, INTERFACE_ELEMENT);
0970: }
0971:
0972: if (detailed) {
0973: saxEndElement(handler, IMPLEMENTS_ELEMENT);
0974: }
0975: }
0976: }
0977:
0978: /**
0979: * Method outputFields.
0980: *
0981: * @param handler
0982: * @param jClass
0983: * @param detailed
0984: */
0985: private void outputFields(ContentHandler handler, JavaClass jClass,
0986: boolean detailed) throws SAXException {
0987: JavaField[] fields = jClass.getFields();
0988:
0989: if (fields.length > 0
0990: || hasInheritance(jClass, FIELD_INHERITANCE)) {
0991: if (detailed) {
0992: saxStartElement(handler, FIELDS_ELEMENT);
0993: }
0994:
0995: // Output inheritance:
0996: outputSuperClassInheritance(handler, jClass,
0997: FIELD_INHERITANCE);
0998:
0999: for (int i = 0; i < fields.length; i++) {
1000: saxStartElement(handler, FIELD_ELEMENT, new String[][] {
1001: { NAME_ATTRIBUTE, fields[i].getName() },
1002: { TYPE_ATTRIBUTE,
1003: fields[i].getType().getValue() },
1004: {
1005: DIMENSIONS_ATTRIBUTE,
1006: Integer.toString(fields[i].getType()
1007: .getDimensions()) } });
1008: if (detailed) {
1009: outputModifiers(handler, fields[i]);
1010: outputComment(handler, fields[i].getComment());
1011: outputTags(handler, fields[i]);
1012: }
1013: saxEndElement(handler, FIELD_ELEMENT);
1014: }
1015:
1016: if (detailed) {
1017: saxEndElement(handler, FIELDS_ELEMENT);
1018: }
1019: }
1020: }
1021:
1022: /**
1023: * Method outputClassStartElement.
1024: *
1025: * @param handler
1026: * @param jClass
1027: */
1028: private void outputInheritStartElement(ContentHandler handler,
1029: JavaClass jClass) throws SAXException {
1030: saxStartElement(handler, INHERIT_ELEMENT, new String[][] {
1031: {
1032: TYPE_ATTRIBUTE,
1033: jClass.isInterface() ? INTERFACE_ELEMENT
1034: : CLASS_ELEMENT },
1035: { CLASSNAME_ATTRIBUTE, jClass.getName() },
1036: { PACKAGE_ATTRIBUTE, jClass.getPackage() },
1037: { QNAME_ATTRIBUTE, jClass.getFullyQualifiedName() } });
1038: }
1039:
1040: /**
1041: * Method outputClassStartElement.
1042: *
1043: * @param handler
1044: * @param jClass
1045: */
1046: private void outputClassStartElement(ContentHandler handler,
1047: JavaClass jClass) throws SAXException {
1048: saxStartElement(handler,
1049: jClass.isInterface() ? INTERFACE_ELEMENT
1050: : CLASS_ELEMENT, new String[][] {
1051: { CLASSNAME_ATTRIBUTE, jClass.getName() },
1052: { PACKAGE_ATTRIBUTE, jClass.getPackage() },
1053: { QNAME_ATTRIBUTE,
1054: jClass.getFullyQualifiedName() } });
1055: }
1056:
1057: /**
1058: * Method outputClassEndElement.
1059: *
1060: * @param handler
1061: * @param jClass
1062: */
1063: private void outputClassEndElement(ContentHandler handler,
1064: JavaClass jClass) throws SAXException {
1065: saxEndElement(handler, jClass.isInterface() ? INTERFACE_ELEMENT
1066: : CLASS_ELEMENT);
1067: }
1068:
1069: /**
1070: * Method outputMethods.
1071: *
1072: * @param handler
1073: * @param jClass
1074: * @param mode
1075: */
1076: private void outputMethods(ContentHandler handler,
1077: JavaClass jClass, int mode) throws SAXException {
1078: // Are there any methods in <mode>?
1079: int size = 0;
1080: String elementGroup, element;
1081: JavaMethod[] methods = jClass.getMethods();
1082:
1083: if (mode == CONSTRUCTOR_MODE) {
1084: elementGroup = CONSTRUCTORS_ELEMENT;
1085: element = CONSTRUCTOR_ELEMENT;
1086: for (int i = 0; i < methods.length; i++) {
1087: if (methods[i].getReturns() == null) {
1088: size++;
1089: }
1090: }
1091: } else {
1092: elementGroup = METHODS_ELEMENT;
1093: element = METHOD_ELEMENT;
1094: for (int i = 0; i < methods.length; i++) {
1095: if (methods[i].getReturns() != null) {
1096: size++;
1097: }
1098: }
1099: }
1100:
1101: if (size > 0
1102: || (mode == METHOD_MODE && hasInheritance(jClass,
1103: METHOD_INHERITANCE))
1104: || (mode == CONSTRUCTOR_MODE && hasInheritance(jClass,
1105: CONSTRUCTOR_INHERITANCE))) {
1106: saxStartElement(handler, elementGroup);
1107:
1108: // Output inheritance:
1109: if (mode == METHOD_MODE) {
1110: outputSuperClassInheritance(handler, jClass,
1111: METHOD_INHERITANCE);
1112: } else {
1113: outputSuperClassInheritance(handler, jClass,
1114: CONSTRUCTOR_INHERITANCE);
1115: }
1116:
1117: for (int i = 0; i < methods.length; i++) {
1118: if (mode == METHOD_MODE
1119: && methods[i].getReturns() != null) {
1120: outputMethodStartElement(handler, methods[i]);
1121: } else if (mode == CONSTRUCTOR_MODE
1122: && methods[i].getReturns() == null) {
1123: saxStartElement(
1124: handler,
1125: CONSTRUCTOR_ELEMENT,
1126: new String[][] {
1127: { NAME_ATTRIBUTE,
1128: methods[i].getName() },
1129: { SIGNATURE_ATTRIBUTE,
1130: getSignature(methods[i]) } });
1131: } else {
1132: // Do not process this method or constructor:
1133: continue;
1134: }
1135:
1136: JavaParameter[] params = methods[i].getParameters();
1137: DocletTag[] paramTags = methods[i]
1138: .getTagsByName("param");
1139: DocletTag[] throwsTags = methods[i]
1140: .getTagsByName("throws");
1141:
1142: // Modifiers, comment, tags:
1143: outputModifiers(handler, methods[i]);
1144: outputComment(handler, methods[i].getComment());
1145: outputTags(handler, methods[i]);
1146:
1147: // Parameters:
1148: if (params.length > 0) {
1149: saxStartElement(handler, PARAMETERS_ELEMENT);
1150: for (int j = 0; j < params.length; j++) {
1151: String paramName = params[j].getName();
1152: saxStartElement(
1153: handler,
1154: PARAMETER_ELEMENT,
1155: new String[][] {
1156: { NAME_ATTRIBUTE, paramName },
1157: {
1158: TYPE_ATTRIBUTE,
1159: params[j].getType()
1160: .getValue() },
1161: {
1162: DIMENSIONS_ATTRIBUTE,
1163: Integer
1164: .toString(params[j]
1165: .getType()
1166: .getDimensions()) } });
1167:
1168: // Is there any doc for this parameter?
1169: for (int k = 0; k < paramTags.length; k++) {
1170: String paramValue = paramTags[k].getValue();
1171: int splitIndex = paramValue.indexOf(' ');
1172: String paramValueName = splitIndex > 0 ? paramValue
1173: .substring(0, splitIndex)
1174: : paramValue;
1175: if (paramName.equals(paramValueName)) {
1176: outputComment(
1177: handler,
1178: splitIndex > 0 ? paramValue
1179: .substring(splitIndex + 1)
1180: : "");
1181: }
1182: }
1183:
1184: saxEndElement(handler, PARAMETER_ELEMENT);
1185: }
1186: saxEndElement(handler, PARAMETERS_ELEMENT);
1187: }
1188:
1189: // Exceptions:
1190: Type[] exceptions = methods[i].getExceptions();
1191: if (exceptions.length + throwsTags.length > 0) {
1192: saxStartElement(handler, THROWS_ELEMENT);
1193: for (int j = 0; j < exceptions.length; j++) {
1194: // Iterate each exception which is declared in the throws clause:
1195: String exceptionName = exceptions[j].getValue();
1196: saxStartElement(handler, EXCEPTION_ELEMENT,
1197: new String[][] { { NAME_ATTRIBUTE,
1198: exceptionName } });
1199:
1200: // Is there any doc for this exception?
1201: if (throwsTags.length > 0) {
1202: String exceptionClassName = exceptionName
1203: .substring(exceptionName
1204: .lastIndexOf('.'));
1205: for (int k = 0; k < throwsTags.length; k++) {
1206: String excValue = throwsTags[k]
1207: .getValue();
1208: int splitIndex = excValue.indexOf(' ');
1209: String excValueName = splitIndex > 0 ? excValue
1210: .substring(0, splitIndex)
1211: : excValue;
1212: if (exceptionClassName
1213: .equals(excValueName)) {
1214: outputComment(
1215: handler,
1216: splitIndex > 0 ? excValue
1217: .substring(splitIndex + 1)
1218: : "");
1219: }
1220: }
1221: }
1222:
1223: saxEndElement(handler, EXCEPTION_ELEMENT);
1224: }
1225:
1226: for (int j = 0; j < throwsTags.length; j++) {
1227: // Iterate each exception which is not declared in the throws clause but documented in javadoc:
1228: String content = throwsTags[j].getValue();
1229: int splitIndex = content.indexOf(' ');
1230: String exceptionName = content.substring(0,
1231: splitIndex);
1232: String qualifiedExceptionName = getQualifiedClassName(exceptionName);
1233:
1234: // Does the exception *not* exist in the throws clause?
1235: boolean found = false;
1236: for (int k = 0; !found && k < exceptions.length; k++) {
1237: found = qualifiedExceptionName
1238: .equals(exceptions[k].getValue());
1239: }
1240:
1241: if (!found) {
1242: saxStartElement(handler, EXCEPTION_ELEMENT,
1243: new String[][] { { NAME_ATTRIBUTE,
1244: qualifiedExceptionName } });
1245: outputComment(handler,
1246: splitIndex > 0 ? content
1247: .substring(splitIndex + 1)
1248: : "");
1249: saxEndElement(handler, EXCEPTION_ELEMENT);
1250: }
1251: }
1252:
1253: saxEndElement(handler, THROWS_ELEMENT);
1254: }
1255:
1256: saxEndElement(handler, element);
1257: }
1258:
1259: saxEndElement(handler, elementGroup);
1260: }
1261: }
1262:
1263: /**
1264: * Method getSignature.
1265: *
1266: * @param javaMethod
1267: * @return String
1268: */
1269: private String getSignature(JavaMethod javaMethod) {
1270: StringBuffer sb = new StringBuffer(javaMethod.getName());
1271: sb.append('(');
1272: JavaParameter[] params = javaMethod.getParameters();
1273: for (int j = 0; j < params.length; j++) {
1274: if (j > 0) {
1275: sb.append(", ");
1276: }
1277: sb.append(params[j].getType().getValue());
1278: int dims = params[j].getType().getDimensions();
1279: for (int k = 0; k < dims; k++) {
1280: sb.append("[]");
1281: }
1282: }
1283: sb.append(')');
1284:
1285: return sb.toString();
1286: }
1287:
1288: /**
1289: * Method outputMethodStartElement.
1290: *
1291: * @param handler
1292: * @param javaMethod
1293: */
1294: private void outputMethodStartElement(ContentHandler handler,
1295: JavaMethod javaMethod) throws SAXException {
1296: if (javaMethod.getReturns() != null) {
1297: saxStartElement(handler, METHOD_ELEMENT, new String[][] {
1298: { NAME_ATTRIBUTE, javaMethod.getName() },
1299: { TYPE_ATTRIBUTE,
1300: javaMethod.getReturns().getValue() },
1301: {
1302: DIMENSIONS_ATTRIBUTE,
1303: Integer.toString(javaMethod.getReturns()
1304: .getDimensions()) },
1305: { SIGNATURE_ATTRIBUTE, getSignature(javaMethod) } });
1306: } else {
1307: saxStartElement(handler, CONSTRUCTOR_ELEMENT,
1308: new String[][] {
1309: { NAME_ATTRIBUTE, javaMethod.getName() },
1310: { SIGNATURE_ATTRIBUTE,
1311: getSignature(javaMethod) } });
1312: }
1313: }
1314:
1315: /**
1316: * Method outputMethodEndElement.
1317: *
1318: * @param handler
1319: */
1320: private void outputMethodEndElement(ContentHandler handler,
1321: JavaMethod javaMethod) throws SAXException {
1322: if (javaMethod.getReturns() != null) {
1323: saxEndElement(handler, METHOD_ELEMENT);
1324: } else {
1325: saxEndElement(handler, CONSTRUCTOR_ELEMENT);
1326: }
1327: }
1328:
1329: /**
1330: * Method saxStartElement.
1331: *
1332: * @param handler
1333: * @param localName
1334: */
1335: private void saxStartElement(ContentHandler handler,
1336: String localName) throws SAXException {
1337: handler.startElement(NS_URI, localName, NS_PREFIX + ':'
1338: + localName, XMLUtils.EMPTY_ATTRIBUTES);
1339: }
1340:
1341: /**
1342: * Method saxStartElement.
1343: *
1344: * @param handler
1345: * @param localName
1346: * @param attrs
1347: */
1348: private void saxStartElement(ContentHandler handler,
1349: String localName, String[][] attrs) throws SAXException {
1350: AttributesImpl saxAttrs = new AttributesImpl();
1351: for (int i = 0; i < attrs.length; i++) {
1352: if (attrs[i].length == 2) {
1353: saxAttrs.addAttribute("", attrs[i][0], attrs[i][0],
1354: ATTR_TYPE, attrs[i][1]);
1355: } else if (attrs[i].length == 5) {
1356: saxAttrs.addAttribute(attrs[i][0], attrs[i][1],
1357: attrs[i][2], attrs[i][3], attrs[i][4]);
1358: }
1359: }
1360:
1361: handler.startElement(NS_URI, localName, NS_PREFIX + ':'
1362: + localName, saxAttrs);
1363: }
1364:
1365: /**
1366: * Method saxEndElement.
1367: *
1368: * @param handler
1369: * @param localName
1370: */
1371: private void saxEndElement(ContentHandler handler, String localName)
1372: throws SAXException {
1373: handler.endElement(NS_URI, localName, NS_PREFIX + ':'
1374: + localName);
1375: }
1376:
1377: /**
1378: * Method saxCharacters.
1379: *
1380: * @param handler
1381: * @param text
1382: */
1383: private void saxCharacters(ContentHandler handler, String text)
1384: throws SAXException {
1385: if (text != null && text.length() > 0) {
1386: handler.characters(text.toCharArray(), 0, text.length());
1387: }
1388: }
1389:
1390: /**
1391: * @see org.apache.excalibur.source.Source#exists()
1392: */
1393: public boolean exists() {
1394: return true;
1395: }
1396: }
|