/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.nifi.registry.service.extension.docs; import org.apache.commons.lang3.StringUtils; import org.apache.nifi.registry.extension.bundle.BundleInfo; import org.apache.nifi.registry.extension.component.ExtensionMetadata; import org.apache.nifi.registry.extension.component.manifest.AllowableValue; import org.apache.nifi.registry.extension.component.manifest.ControllerServiceDefinition; import org.apache.nifi.registry.extension.component.manifest.DeprecationNotice; import org.apache.nifi.registry.extension.component.manifest.DynamicProperty; import org.apache.nifi.registry.extension.component.manifest.ExpressionLanguageScope; import org.apache.nifi.registry.extension.component.manifest.Extension; import org.apache.nifi.registry.extension.component.manifest.InputRequirement; import org.apache.nifi.registry.extension.component.manifest.Property; import org.apache.nifi.registry.extension.component.manifest.ProvidedServiceAPI; import org.apache.nifi.registry.extension.component.manifest.Restricted; import org.apache.nifi.registry.extension.component.manifest.Restriction; import org.apache.nifi.registry.extension.component.manifest.Stateful; import org.apache.nifi.registry.extension.component.manifest.SystemResourceConsideration; import org.springframework.stereotype.Service; import javax.xml.stream.FactoryConfigurationError; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import java.io.IOException; import java.io.OutputStream; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; import static org.apache.nifi.registry.service.extension.docs.DocumentationConstants.CSS_PATH; @Service public class HtmlExtensionDocWriter implements ExtensionDocWriter { @Override public void write(final ExtensionMetadata extensionMetadata, final Extension extension, final OutputStream outputStream) throws IOException { try { final XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(outputStream, "UTF-8"); xmlStreamWriter.writeDTD("<!DOCTYPE html>"); xmlStreamWriter.writeStartElement("html"); xmlStreamWriter.writeAttribute("lang", "en"); writeHead(extensionMetadata, xmlStreamWriter); writeBody(extensionMetadata, extension, xmlStreamWriter); xmlStreamWriter.writeEndElement(); xmlStreamWriter.close(); outputStream.flush(); } catch (XMLStreamException | FactoryConfigurationError e) { throw new IOException("Unable to create XMLOutputStream", e); } } private void writeHead(final ExtensionMetadata extensionMetadata, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { xmlStreamWriter.writeStartElement("head"); xmlStreamWriter.writeStartElement("meta"); xmlStreamWriter.writeAttribute("charset", "utf-8"); xmlStreamWriter.writeEndElement(); writeSimpleElement(xmlStreamWriter, "title", extensionMetadata.getDisplayName()); final String componentUsageCss = CSS_PATH + "component-usage.css"; xmlStreamWriter.writeStartElement("link"); xmlStreamWriter.writeAttribute("rel", "stylesheet"); xmlStreamWriter.writeAttribute("href", componentUsageCss); xmlStreamWriter.writeAttribute("type", "text/css"); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeStartElement("script"); xmlStreamWriter.writeAttribute("type", "text/javascript"); xmlStreamWriter.writeCharacters("window.onload = function(){if(self==top) { " + "document.getElementById('nameHeader').style.display = \"inherit\"; } }" ); xmlStreamWriter.writeEndElement(); } private void writeBody(final ExtensionMetadata extensionMetadata, final Extension extension, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { xmlStreamWriter.writeStartElement("body"); writeHeader(extensionMetadata, extension, xmlStreamWriter); writeBundleInfo(extensionMetadata, xmlStreamWriter); writeDeprecationWarning(extension, xmlStreamWriter); writeDescription(extensionMetadata, extension, xmlStreamWriter); writeTags(extension, xmlStreamWriter); writeProperties(extension, xmlStreamWriter); writeDynamicProperties(extension, xmlStreamWriter); writeAdditionalBodyInfo(extension, xmlStreamWriter); writeStatefulInfo(extension, xmlStreamWriter); writeRestrictedInfo(extension, xmlStreamWriter); writeInputRequirementInfo(extension, xmlStreamWriter); writeSystemResourceConsiderationInfo(extension, xmlStreamWriter); writeProvidedServiceApis(extension, xmlStreamWriter); writeSeeAlso(extension, xmlStreamWriter); // end body xmlStreamWriter.writeEndElement(); } /** * This method may be overridden by sub classes to write additional * information to the body of the documentation. * * @param extension the component to describe * @param xmlStreamWriter the stream writer * @throws XMLStreamException thrown if there was a problem writing to the XML stream */ protected void writeAdditionalBodyInfo(final Extension extension, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { } private void writeHeader(final ExtensionMetadata extensionMetadata, final Extension extension, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { xmlStreamWriter.writeStartElement("h1"); xmlStreamWriter.writeAttribute("id", "nameHeader"); xmlStreamWriter.writeAttribute("style", "display: none;"); xmlStreamWriter.writeCharacters(extensionMetadata.getDisplayName()); xmlStreamWriter.writeEndElement(); } private void writeBundleInfoString(final ExtensionMetadata extensionMetadata, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { final BundleInfo bundleInfo = extensionMetadata.getBundleInfo(); final String bundleInfoText = bundleInfo.getGroupId() + "-" + bundleInfo.getArtifactId() + "-" + bundleInfo.getVersion(); xmlStreamWriter.writeStartElement("p"); xmlStreamWriter.writeStartElement("i"); xmlStreamWriter.writeCharacters(bundleInfoText); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeEndElement(); } private void writeBundleInfo(final ExtensionMetadata extensionMetadata, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { final BundleInfo bundleInfo = extensionMetadata.getBundleInfo(); final String extenstionType; switch (extensionMetadata.getType()) { case PROCESSOR: extenstionType = "Processor"; break; case CONTROLLER_SERVICE: extenstionType = "Controller Service"; break; case REPORTING_TASK: extenstionType = "Reporting Task"; break; default: throw new IllegalArgumentException("Unknown extension type: " + extensionMetadata.getType()); } xmlStreamWriter.writeStartElement("table"); xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "th", "Extension Info"); writeSimpleElement(xmlStreamWriter, "th", "Value"); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "td", "Full Name", true, "bundle-info"); writeSimpleElement(xmlStreamWriter, "td", extensionMetadata.getName()); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "td", "Type", true, "bundle-info"); writeSimpleElement(xmlStreamWriter, "td", extenstionType); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "td", "Bundle Group", true, "bundle-info"); writeSimpleElement(xmlStreamWriter, "td", bundleInfo.getGroupId()); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "td", "Bundle Artifact", true, "bundle-info"); writeSimpleElement(xmlStreamWriter, "td", bundleInfo.getArtifactId()); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "td", "Bundle Version", true, "bundle-info"); writeSimpleElement(xmlStreamWriter, "td", bundleInfo.getVersion()); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "td", "Bundle Type", true, "bundle-info"); writeSimpleElement(xmlStreamWriter, "td", bundleInfo.getBundleType().toString()); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "td", "System API Version", true, "bundle-info"); writeSimpleElement(xmlStreamWriter, "td", bundleInfo.getSystemApiVersion()); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeEndElement(); // end table } private void writeDeprecationWarning(final Extension extension, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { final DeprecationNotice deprecationNotice = extension.getDeprecationNotice(); if (deprecationNotice != null) { xmlStreamWriter.writeStartElement("h2"); xmlStreamWriter.writeCharacters("Deprecation notice: "); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeStartElement("p"); xmlStreamWriter.writeCharacters(""); if (!StringUtils.isEmpty(deprecationNotice.getReason())) { xmlStreamWriter.writeCharacters(deprecationNotice.getReason()); } else { xmlStreamWriter.writeCharacters("Please be aware this processor is deprecated and may be removed in the near future."); } xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeStartElement("p"); xmlStreamWriter.writeCharacters("Please consider using one the following alternatives: "); final List<String> alternatives = deprecationNotice.getAlternatives(); if (alternatives != null && alternatives.size() > 0) { xmlStreamWriter.writeStartElement("ul"); for (final String alternative : alternatives) { xmlStreamWriter.writeStartElement("li"); xmlStreamWriter.writeCharacters(alternative); xmlStreamWriter.writeEndElement(); } xmlStreamWriter.writeEndElement(); } else { xmlStreamWriter.writeCharacters("No alternative components suggested."); } xmlStreamWriter.writeEndElement(); } } private void writeDescription(final ExtensionMetadata extensionMetadata, final Extension extension, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { final String description = StringUtils.isBlank(extension.getDescription()) ? "No description provided." : extension.getDescription(); writeSimpleElement(xmlStreamWriter, "h2", "Description: "); writeSimpleElement(xmlStreamWriter, "p", description); if (extensionMetadata.getHasAdditionalDetails()) { xmlStreamWriter.writeStartElement("p"); final BundleInfo bundleInfo = extensionMetadata.getBundleInfo(); final String bucketName = bundleInfo.getBucketName(); final String groupId = bundleInfo.getGroupId(); final String artifactId = bundleInfo.getArtifactId(); final String version = bundleInfo.getVersion(); final String extensionName = extensionMetadata.getName(); final String additionalDetailsPath = "/nifi-registry-api/extension-repository/" + bucketName + "/" + groupId + "/" + artifactId + "/" + version + "/extensions/" + extensionName + "/docs/additional-details"; writeLink(xmlStreamWriter, "Additional Details...", additionalDetailsPath); xmlStreamWriter.writeEndElement(); } } private void writeTags(final Extension extension, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { final List<String> tags = extension.getTags(); xmlStreamWriter.writeStartElement("h3"); xmlStreamWriter.writeCharacters("Tags: "); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeStartElement("p"); if (tags != null) { final String tagString = StringUtils.join(tags, ", "); xmlStreamWriter.writeCharacters(tagString); } else { xmlStreamWriter.writeCharacters("No tags provided."); } xmlStreamWriter.writeEndElement(); } protected void writeProperties(final Extension extension, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { final List<Property> properties = extension.getProperties(); writeSimpleElement(xmlStreamWriter, "h3", "Properties: "); if (properties != null && properties.size() > 0) { final boolean containsExpressionLanguage = containsExpressionLanguage(extension); final boolean containsSensitiveProperties = containsSensitiveProperties(extension); xmlStreamWriter.writeStartElement("p"); xmlStreamWriter.writeCharacters("In the list below, the names of required properties appear in "); writeSimpleElement(xmlStreamWriter, "strong", "bold"); xmlStreamWriter.writeCharacters(". Any other properties (not in bold) are considered optional. " + "The table also indicates any default values"); if (containsExpressionLanguage) { if (!containsSensitiveProperties) { xmlStreamWriter.writeCharacters(", and "); } else { xmlStreamWriter.writeCharacters(", "); } xmlStreamWriter.writeCharacters("whether a property supports the NiFi Expression Language"); } if (containsSensitiveProperties) { xmlStreamWriter.writeCharacters(", and whether a property is considered " + "\"sensitive\", meaning that its value will be encrypted"); } xmlStreamWriter.writeCharacters("."); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeStartElement("table"); xmlStreamWriter.writeAttribute("id", "properties"); // write the header row xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "th", "Name"); writeSimpleElement(xmlStreamWriter, "th", "Default Value"); writeSimpleElement(xmlStreamWriter, "th", "Allowable Values"); writeSimpleElement(xmlStreamWriter, "th", "Description"); xmlStreamWriter.writeEndElement(); // write the individual properties for (Property property : properties) { xmlStreamWriter.writeStartElement("tr"); xmlStreamWriter.writeStartElement("td"); xmlStreamWriter.writeAttribute("id", "name"); if (property.isRequired()) { writeSimpleElement(xmlStreamWriter, "strong", property.getDisplayName()); } else { xmlStreamWriter.writeCharacters(property.getDisplayName()); } xmlStreamWriter.writeEndElement(); writeSimpleElement(xmlStreamWriter, "td", property.getDefaultValue(), false, "default-value"); xmlStreamWriter.writeStartElement("td"); xmlStreamWriter.writeAttribute("id", "allowable-values"); writeValidValues(xmlStreamWriter, property); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeStartElement("td"); xmlStreamWriter.writeAttribute("id", "description"); if (property.getDescription() != null && property.getDescription().trim().length() > 0) { xmlStreamWriter.writeCharacters(property.getDescription()); } else { xmlStreamWriter.writeCharacters("No Description Provided."); } if (property.isSensitive()) { xmlStreamWriter.writeEmptyElement("br"); writeSimpleElement(xmlStreamWriter, "strong", "Sensitive Property: true"); } if (property.isExpressionLanguageSupported()) { xmlStreamWriter.writeEmptyElement("br"); String text = "Supports Expression Language: true"; final String perFF = " (will be evaluated using flow file attributes and variable registry)"; final String registry = " (will be evaluated using variable registry only)"; final InputRequirement inputRequirement = extension.getInputRequirement(); switch(property.getExpressionLanguageScope()) { case FLOWFILE_ATTRIBUTES: if(inputRequirement != null && inputRequirement.equals(InputRequirement.INPUT_FORBIDDEN)) { text += registry; } else { text += perFF; } break; case VARIABLE_REGISTRY: text += registry; break; case NONE: default: // in case legacy/deprecated method has been used to specify EL support text += " (undefined scope)"; break; } writeSimpleElement(xmlStreamWriter, "strong", text); } xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeEndElement(); } xmlStreamWriter.writeEndElement(); } else { writeSimpleElement(xmlStreamWriter, "p", "This component has no required or optional properties."); } } private boolean containsExpressionLanguage(final Extension extension) { for (Property property : extension.getProperties()) { if (property.isExpressionLanguageSupported()) { return true; } } return false; } private boolean containsSensitiveProperties(final Extension extension) { for (Property property : extension.getProperties()) { if (property.isSensitive()) { return true; } } return false; } protected void writeValidValues(final XMLStreamWriter xmlStreamWriter, final Property property) throws XMLStreamException { if (property.getAllowableValues() != null && property.getAllowableValues().size() > 0) { xmlStreamWriter.writeStartElement("ul"); for (AllowableValue value : property.getAllowableValues()) { xmlStreamWriter.writeStartElement("li"); xmlStreamWriter.writeCharacters(value.getDisplayName()); if (!StringUtils.isBlank(value.getDescription())) { writeValidValueDescription(xmlStreamWriter, value.getDescription()); } xmlStreamWriter.writeEndElement(); } xmlStreamWriter.writeEndElement(); } else if (property.getControllerServiceDefinition() != null) { final ControllerServiceDefinition serviceDefinition = property.getControllerServiceDefinition(); final String controllerServiceClass = getSimpleName(serviceDefinition.getClassName()); final String group = serviceDefinition.getGroupId() == null ? "unknown" : serviceDefinition.getGroupId(); final String artifact = serviceDefinition.getArtifactId() == null ? "unknown" : serviceDefinition.getArtifactId(); final String version = serviceDefinition.getVersion() == null ? "unknown" : serviceDefinition.getVersion(); writeSimpleElement(xmlStreamWriter, "strong", "Controller Service API: "); xmlStreamWriter.writeEmptyElement("br"); xmlStreamWriter.writeCharacters(controllerServiceClass); writeValidValueDescription(xmlStreamWriter, group + "-" + artifact + "-" + version); // xmlStreamWriter.writeEmptyElement("br"); // xmlStreamWriter.writeCharacters(group); // xmlStreamWriter.writeEmptyElement("br"); // xmlStreamWriter.writeCharacters(artifact); // xmlStreamWriter.writeEmptyElement("br"); // xmlStreamWriter.writeCharacters(version); } } private String getSimpleName(final String extensionName) { int index = extensionName.lastIndexOf('.'); if (index > 0 && (index < (extensionName.length() - 1))) { return extensionName.substring(index + 1); } else { return extensionName; } } private void writeValidValueDescription(final XMLStreamWriter xmlStreamWriter, final String description) throws XMLStreamException { xmlStreamWriter.writeCharacters(" "); xmlStreamWriter.writeStartElement("img"); xmlStreamWriter.writeAttribute("src", "/nifi-registry-docs/images/iconInfo.png"); xmlStreamWriter.writeAttribute("alt", description); xmlStreamWriter.writeAttribute("title", description); xmlStreamWriter.writeEndElement(); } private void writeDynamicProperties(final Extension extension, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { final List<DynamicProperty> dynamicProperties = extension.getDynamicProperties(); if (dynamicProperties != null && dynamicProperties.size() > 0) { writeSimpleElement(xmlStreamWriter, "h3", "Dynamic Properties: "); xmlStreamWriter.writeStartElement("p"); xmlStreamWriter.writeCharacters("Dynamic Properties allow the user to specify both the name and value of a property."); xmlStreamWriter.writeStartElement("table"); xmlStreamWriter.writeAttribute("id", "dynamic-properties"); xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "th", "Name"); writeSimpleElement(xmlStreamWriter, "th", "Value"); writeSimpleElement(xmlStreamWriter, "th", "Description"); xmlStreamWriter.writeEndElement(); for (final DynamicProperty dynamicProperty : dynamicProperties) { final String name = StringUtils.isBlank(dynamicProperty.getName()) ? "Not Specified" : dynamicProperty.getName(); final String value = StringUtils.isBlank(dynamicProperty.getValue()) ? "Not Specified" : dynamicProperty.getValue(); final String description = StringUtils.isBlank(dynamicProperty.getDescription()) ? "Not Specified" : dynamicProperty.getDescription(); xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "td", name, false, "name"); writeSimpleElement(xmlStreamWriter, "td", value, false, "value"); xmlStreamWriter.writeStartElement("td"); xmlStreamWriter.writeCharacters(description); xmlStreamWriter.writeEmptyElement("br"); final ExpressionLanguageScope elScope = dynamicProperty.getExpressionLanguageScope() == null ? ExpressionLanguageScope.NONE : dynamicProperty.getExpressionLanguageScope(); String text; if(elScope.equals(ExpressionLanguageScope.NONE)) { if(dynamicProperty.isExpressionLanguageSupported()) { text = "Supports Expression Language: true (undefined scope)"; } else { text = "Supports Expression Language: false"; } } else { switch(elScope) { case FLOWFILE_ATTRIBUTES: text = "Supports Expression Language: true (will be evaluated using flow file attributes and variable registry)"; break; case VARIABLE_REGISTRY: text = "Supports Expression Language: true (will be evaluated using variable registry only)"; break; case NONE: default: text = "Supports Expression Language: false"; break; } } writeSimpleElement(xmlStreamWriter, "strong", text); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeEndElement(); } xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeEndElement(); } } private void writeStatefulInfo(final Extension extension, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { final Stateful stateful = extension.getStateful(); writeSimpleElement(xmlStreamWriter, "h3", "State management: "); if(stateful != null) { final List<String> scopes = Optional.ofNullable(stateful.getScopes()) .map(List::stream) .orElseGet(Stream::empty) .map(s -> s.toString()) .collect(Collectors.toList()); final String description = StringUtils.isBlank(stateful.getDescription()) ? "Not Specified" : stateful.getDescription(); xmlStreamWriter.writeStartElement("table"); xmlStreamWriter.writeAttribute("id", "stateful"); xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "th", "Scope"); writeSimpleElement(xmlStreamWriter, "th", "Description"); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "td", StringUtils.join(scopes, ", ")); writeSimpleElement(xmlStreamWriter, "td", description); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeEndElement(); } else { xmlStreamWriter.writeCharacters("This component does not store state."); } } private void writeRestrictedInfo(final Extension extension, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { final Restricted restricted = extension.getRestricted(); writeSimpleElement(xmlStreamWriter, "h3", "Restricted: "); if(restricted != null) { final String generalRestrictionExplanation = restricted.getGeneralRestrictionExplanation(); if (!StringUtils.isBlank(generalRestrictionExplanation)) { xmlStreamWriter.writeCharacters(generalRestrictionExplanation); } final List<Restriction> restrictions = restricted.getRestrictions(); if (restrictions != null && restrictions.size() > 0) { xmlStreamWriter.writeStartElement("table"); xmlStreamWriter.writeAttribute("id", "restrictions"); xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "th", "Required Permission"); writeSimpleElement(xmlStreamWriter, "th", "Explanation"); xmlStreamWriter.writeEndElement(); for (Restriction restriction : restrictions) { final String permission = StringUtils.isBlank(restriction.getRequiredPermission()) ? "Not Specified" : restriction.getRequiredPermission(); final String explanation = StringUtils.isBlank(restriction.getExplanation()) ? "Not Specified" : restriction.getExplanation(); xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "td", permission); writeSimpleElement(xmlStreamWriter, "td", explanation); xmlStreamWriter.writeEndElement(); } xmlStreamWriter.writeEndElement(); } else { xmlStreamWriter.writeCharacters("This component requires access to restricted components regardless of restriction."); } } else { xmlStreamWriter.writeCharacters("This component is not restricted."); } } private void writeInputRequirementInfo(final Extension extension, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { final InputRequirement inputRequirement = extension.getInputRequirement(); if(inputRequirement != null) { writeSimpleElement(xmlStreamWriter, "h3", "Input requirement: "); switch (inputRequirement) { case INPUT_FORBIDDEN: xmlStreamWriter.writeCharacters("This component does not allow an incoming relationship."); break; case INPUT_ALLOWED: xmlStreamWriter.writeCharacters("This component allows an incoming relationship."); break; case INPUT_REQUIRED: xmlStreamWriter.writeCharacters("This component requires an incoming relationship."); break; default: xmlStreamWriter.writeCharacters("This component does not have input requirement."); break; } } } private void writeSystemResourceConsiderationInfo(final Extension extension, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { List<SystemResourceConsideration> systemResourceConsiderations = extension.getSystemResourceConsiderations(); writeSimpleElement(xmlStreamWriter, "h3", "System Resource Considerations:"); if (systemResourceConsiderations != null && systemResourceConsiderations.size() > 0) { xmlStreamWriter.writeStartElement("table"); xmlStreamWriter.writeAttribute("id", "system-resource-considerations"); xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "th", "Resource"); writeSimpleElement(xmlStreamWriter, "th", "Description"); xmlStreamWriter.writeEndElement(); for (SystemResourceConsideration systemResourceConsideration : systemResourceConsiderations) { final String resource = StringUtils.isBlank(systemResourceConsideration.getResource()) ? "Not Specified" : systemResourceConsideration.getResource(); final String description = StringUtils.isBlank(systemResourceConsideration.getDescription()) ? "Not Specified" : systemResourceConsideration.getDescription(); xmlStreamWriter.writeStartElement("tr"); writeSimpleElement(xmlStreamWriter, "td", resource); writeSimpleElement(xmlStreamWriter, "td", description); xmlStreamWriter.writeEndElement(); } xmlStreamWriter.writeEndElement(); } else { xmlStreamWriter.writeCharacters("None specified."); } } private void writeProvidedServiceApis(final Extension extension, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { final List<ProvidedServiceAPI> serviceAPIS = extension.getProvidedServiceAPIs(); if (serviceAPIS != null && serviceAPIS.size() > 0) { writeSimpleElement(xmlStreamWriter, "h3", "Provided Service APIs:"); xmlStreamWriter.writeStartElement("ul"); for (final ProvidedServiceAPI serviceAPI : serviceAPIS) { final String name = getSimpleName(serviceAPI.getClassName()); final String bundleInfo = " (" + serviceAPI.getGroupId() + "-" + serviceAPI.getArtifactId() + "-" + serviceAPI.getVersion() + ")"; xmlStreamWriter.writeStartElement("li"); xmlStreamWriter.writeCharacters(name); xmlStreamWriter.writeStartElement("i"); xmlStreamWriter.writeCharacters(bundleInfo); xmlStreamWriter.writeEndElement(); xmlStreamWriter.writeEndElement(); } xmlStreamWriter.writeEndElement(); } } private void writeSeeAlso(final Extension extension, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException { final List<String> seeAlsos = extension.getSeeAlso(); if (seeAlsos != null && seeAlsos.size() > 0) { writeSimpleElement(xmlStreamWriter, "h3", "See Also:"); xmlStreamWriter.writeStartElement("ul"); for (final String seeAlso : seeAlsos) { writeSimpleElement(xmlStreamWriter, "li", seeAlso); } xmlStreamWriter.writeEndElement(); } } /** * Writes a begin element, then text, then end element for the element of a * users choosing. Example: <p>text</p> * * @param writer the stream writer to use * @param elementName the name of the element * @param characters the characters to insert into the element * @throws XMLStreamException thrown if there was a problem writing to the * stream */ protected final static void writeSimpleElement(final XMLStreamWriter writer, final String elementName, final String characters) throws XMLStreamException { writeSimpleElement(writer, elementName, characters, false); } /** * Writes a begin element, then text, then end element for the element of a * users choosing. Example: <p>text</p> * * @param writer the stream writer to use * @param elementName the name of the element * @param characters the characters to insert into the element * @param strong whether the characters should be strong or not. * @throws XMLStreamException thrown if there was a problem writing to the * stream. */ protected final static void writeSimpleElement(final XMLStreamWriter writer, final String elementName, final String characters, boolean strong) throws XMLStreamException { writeSimpleElement(writer, elementName, characters, strong, null); } /** * Writes a begin element, an id attribute(if specified), then text, then * end element for element of the users choosing. Example: <p * id="p-id">text</p> * * @param writer the stream writer to use * @param elementName the name of the element * @param characters the text of the element * @param strong whether to bold the text of the element or not * @param id the id of the element. specifying null will cause no element to * be written. * @throws XMLStreamException xse */ protected final static void writeSimpleElement(final XMLStreamWriter writer, final String elementName, final String characters, boolean strong, String id) throws XMLStreamException { writer.writeStartElement(elementName); if (id != null) { writer.writeAttribute("id", id); } if (strong) { writer.writeStartElement("strong"); } writer.writeCharacters(characters); if (strong) { writer.writeEndElement(); } writer.writeEndElement(); } /** * A helper method to write a link * * @param xmlStreamWriter the stream to write to * @param text the text of the link * @param location the location of the link * @throws XMLStreamException thrown if there was a problem writing to the * stream */ protected void writeLink(final XMLStreamWriter xmlStreamWriter, final String text, final String location) throws XMLStreamException { xmlStreamWriter.writeStartElement("a"); xmlStreamWriter.writeAttribute("href", location); xmlStreamWriter.writeCharacters(text); xmlStreamWriter.writeEndElement(); } }