package org.tldgen.writers; import java.io.File; import java.io.IOException; import java.io.StringWriter; import java.util.Collection; import java.util.Set; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.tldgen.DocletOptions; import org.tldgen.annotations.TldVersion; import org.tldgen.annotations.VariableScope; import org.tldgen.model.Attribute; import org.tldgen.model.Function; import org.tldgen.model.Library; import org.tldgen.model.LibrarySignature; import org.tldgen.model.Listener; import org.tldgen.model.Tag; import org.tldgen.model.Variable; import org.tldgen.util.DirectoryUtils; /** * Create TLD documentation * * @author carlos * @author javier */ public class TldLibraryWriter extends AbstractWriter { private XMLStreamWriter writer; private boolean doNotOverwrite; private static Logger log = LoggerFactory.getLogger(TldLibraryWriter.class); /** * Write the TLD file * * @param library the library to create the TLD documentation * @param folder the folder where the TLD file should be created * @throws XMLStreamException if there is any problem writing the TLD */ public void writeTLD(Library library, String folder) throws XMLStreamException, IOException { String filename = folder + "/" + library.getLibrarySignature().getShortName() + ".tld"; if (warnIfExists(filename) && doNotOverwrite) { return; } log.info("Creating TLD file: " + filename); // write the TLD to memory StringWriter buffer = new StringWriter(); try { writer = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer); startTaglibElement(library); if (library.getTags() != null) { writeTags(library.getTags()); } if (library.getFunctions() != null) { writeFunctions(library.getFunctions()); } if(library.getListeners() != null) { writeListeners(library.getListeners()); } endTaglibElement(); } finally { if (writer != null) { writer.close(); } } DirectoryUtils.createParentFolder(filename); // format the generated XML and write to disk formatAndWriteXml(buffer.toString(), filename); } /** * Logs a warning if the output file/folder already exists * @param filename the file name to check the existence of * @return true if the given file exists, false otherwise */ private boolean warnIfExists(String filename) { if (new File(filename).exists()) { log.warn(filename + " already exists. It will " + (doNotOverwrite ? "NOT" : "") + " be overwritten"); return true; } return false; } /** * Start the <taglib> element and write the TLD file header * * @param library the library to create the TLD taglib element information */ private void startTaglibElement(Library library) throws XMLStreamException, IOException { LibrarySignature signature = library.getLibrarySignature(); TldVersion tldVersion = signature.getVersion(); log.debug("Writing TLD file header"); writer.writeStartDocument("UTF-8", "1.0"); String licenseContent = signature.getLicense().getLicenseHeader(); if (!StringUtils.isEmpty(licenseContent)) { writer.writeComment(licenseContent); } startElement("taglib"); writeAttribute("xmlns", "http://java.sun.com/xml/ns/javaee"); writeAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); writeAttribute("xsi:schemaLocation", tldVersion.getSchemaLocation()); writeAttribute("version", tldVersion.getId()); writeElement("display-name",signature.getDisplayName()); writeElement("tlib-version", tldVersion.getId()); writeElement("short-name", signature.getShortName()); writeElement("uri", signature.getUri()); writeElement("description", signature.getDescription()); if (signature.getSmallIcon() != null || signature.getLargeIcon() != null) { startElement("icon"); writeElement("small-icon", signature.getSmallIcon()); writeElement("large-icon", signature.getLargeIcon()); endElement(); } } /** * Closes the <taglib> element */ private void endTaglibElement() throws XMLStreamException { endElement(); } /** * Write the tags part of the TLD * @param tags the {@link Tag} instances to write to the TLD */ private void writeTags(Collection<Tag> tags) throws XMLStreamException { for (Tag tag : tags) { log.debug("Writing tag '" + tag.getName() + "'"); startElement("tag"); writeCDataElement("description", tag.getDescription()); writeElement("display-name", tag.getDisplayName()); writeElement("icon", tag.getIcon()); writeElement("name", tag.getName()); writeElement("tag-class", tag.getClazz()); writeElement("tei-class", tag.getTeiClass()); writeElement("body-content", tag.getBodyContent().getTldValue()); writeTagVariables(tag.getName(), tag.getVariables()); writeTagAttributes(tag.getName(), tag.getAttributes()); writeElement("dynamic-attributes", tag.isDynamicAttributes()? tag.isDynamicAttributes() : null); writeElement("example", tag.getExample()); endElement(); } } /** * Write the Function's info of the library * * @param functions the {@link Function} instances to write to the TLD * @throws XMLStreamException * if error writing output stream */ private void writeFunctions(Set<Function> functions) throws XMLStreamException { for (Function function : functions) { log.debug("Writing function '" + function.getName() + "'"); startElement("function"); writeCDataElement("description", function.getTldDescription()); writeElement("display-name", function.getDisplayName()); writeElement("icon", function.getIcon()); writeElement("name", function.getName()); writeElement("function-class", function.getClazz()); writeElement("function-signature", function.getSignature()); writeElement("example", function.getExample()); endElement(); } } /** * Write the listeners to the tld file * * @param listeners the listeners to include in the tld file * @throws XMLStreamException on error writing to out stream */ private void writeListeners(Set<Listener> listeners) throws XMLStreamException { for(Listener listener : listeners) { log.debug("writing Listener for '"+listener.getListenerClass() +"'"); startElement("listener"); writeElement("listener-class", listener.getListenerClass()); endElement(); } } /** * Write the Attributes info * * @param attributes {@link Attribute} instances to write to the TLD * @throws XMLStreamException * if error writing output stream */ private void writeTagAttributes(String tagName, Collection<Attribute> attributes) throws XMLStreamException { for (Attribute attr : attributes) { log.debug("Writing attribute '" + tagName + "." + attr.getName() + "'"); startElement("attribute"); writeCDataElement("description", attr.getDescription()); writeElement("name", attr.getName()); writeElement("required", attr.isRequired()? attr.isRequired() : null); writeElement("rtexprvalue", attr.isRtexprvalue()? attr.isRtexprvalue() : null); if(attr.hasType()) { writeElement("type", attr.getType()); } endElement(); } } /** * Write the Variables info * * @param variables {@link Variable} instances to write to the TLD * @throws XMLStreamException * if error writing output stream */ private void writeTagVariables(String tagName, Collection<Variable> variables) throws XMLStreamException { for (Variable var : variables) { log.debug("Writing variable '" + tagName + "." + (var.getNameFromAttribute() == null? var.getNameGiven() : var.getNameFromAttribute()) + "'"); startElement("variable"); writeCDataElement("description", var.getDescription()); writeElement("name-given", var.getNameGiven()); writeElement("name-from-attribute", var.getNameFromAttribute()); if (var.getVariableClass() != null && !String.class.getName().equals(var.getVariableClass().qualifiedName())) { writeElement("variable-class", var.getVariableClass()); } if (!var.isDeclare()) { writeElement("declare", var.isDeclare()); } if (var.getScope() != null && var.getScope() != VariableScope.NESTED) { writeElement("scope", var.getScope()); } endElement(); } } /** * Write a XML tag and its value * @param name the name of the element * @param contents the contents of the tag. If not null, its toString() * representation will be used as the tag contents. If null, * the entire tag will be skipped. */ private void writeElement(String name, Object contents) throws XMLStreamException { if (contents != null) { startElement(name); writer.writeCharacters(contents.toString()); endElement(); } } private void writeCDataElement(String name, String contents) throws XMLStreamException { if (contents != null) { startElement(name); writer.writeCData(contents); endElement(); } } /** * Write an attribute, provided its value is not null */ private void writeAttribute(String name, Object value) throws XMLStreamException { if (value != null) { writer.writeAttribute(name, value.toString()); } } /** * start an XML tag */ private void startElement(String nameTag) throws XMLStreamException { writer.writeStartElement(nameTag); } /** * end an XML tag */ private void endElement() throws XMLStreamException { writer.writeEndElement(); } public void setOptions(DocletOptions options) { setIndentSpaces(options.getIndentSpaces()); setFormatOutput(options.isFormatOutput()); this.doNotOverwrite = options.doNotOverwrite(); } }