/* * RHQ Management Platform * Copyright (C) 2005-2012 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.core.tool.plugindoc; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.TreeSet; import javax.xml.XMLConstants; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import javax.xml.bind.ValidationEvent; import javax.xml.bind.util.ValidationEventCollector; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.codehaus.swizzle.confluence.Confluence; import org.codehaus.swizzle.confluence.Page; import org.codehaus.swizzle.confluence.PageSummary; import org.codehaus.swizzle.confluence.SwizzleException; import org.rhq.core.clientapi.agent.metadata.InvalidPluginDescriptorException; import org.rhq.core.clientapi.descriptor.plugin.PluginDescriptor; import org.rhq.core.domain.plugin.Plugin; import org.rhq.core.domain.resource.ResourceType; /** * @author Ian Springer */ public class PluginDocGenerator { private final Log log = LogFactory.getLog(this.getClass()); private static final String PLUGIN_DESCRIPTOR_PATH = "src/main/resources/META-INF/rhq-plugin.xml"; private static final String OUTPUT_DIR_PATH = "target/plugindoc"; private static final String PLUGIN_DESCRIPTOR_JAXB_CONTEXT_PATH = "org.rhq.core.clientapi.descriptor.plugin"; private static final String CONFLUENCE_PLUGIN_TEMPLATE_RESOURCE_PATH = "plugin-doc-confluence.vm"; private static final String CONFLUENCE_RESOURCE_TYPE_TEMPLATE_RESOURCE_PATH = "resource-type-doc-confluence.vm"; private static final String DOCBOOK_PLUGIN_TEMPLATE_RESOURCE_PATH = "plugin-doc-docbook.vm"; private static final String DOCBOOK_RESOURCE_TYPE_TEMPLATE_RESOURCE_PATH = "resource-type-doc-docbook.vm"; private static final String CONFLUENCE_MACRO_LIBRARY_RESOURCE_PATH = "confluence-macros.vm"; private static final String DOCBOOK_MACRO_LIBRARY_RESOURCE_PATH = "docbook-macros.vm"; private static final String RHQ_VERSION = "4.4.0"; private String confluenceUrl; // The main Confluence URL (e.g. "http://rhq-project.org/"). private String confluenceSpace; // The Confluence space (e.g. "JOPR2"). private String confluenceParentPageTitle; // The Confluence parent page name (e.g. "Management Plugins"). private String confluenceUserName; private String confluencePassword; private static final Comparator<ResourceType> CHILD_RESOURCE_TYPES_SORTER = new Comparator<ResourceType>() { public int compare(ResourceType first, ResourceType second) { // platforms before servers, and servers before services int result = first.getCategory().compareTo(second.getCategory()); if (result == 0) { result = first.getName().toLowerCase().compareTo(second.getName().toLowerCase()); } return result; } }; public void loadProperties(String propertiesFileName) { if (propertiesFileName == null) { throw new IllegalArgumentException("Argument to loadProperties must not be null"); } Properties props = new Properties(); try { File f = new File(propertiesFileName); InputStream fileInputStream = new FileInputStream(f); try { props.load(fileInputStream); } finally { fileInputStream.close(); } } catch (FileNotFoundException fnfe) { throw new IllegalArgumentException(propertiesFileName + " file does not exist"); } catch (IOException ioe) { throw new IllegalStateException("Error loading properties from " + propertiesFileName + ": " + ioe.getMessage()); } loadProperties(props); } public void loadProperties(Properties props) { this.confluenceUrl = props.getProperty("confluenceUrl", "https://docs.jboss.org/author/display/"); this.confluenceSpace = props.getProperty("confluenceSpace", "RHQ"); this.confluenceParentPageTitle = props.getProperty("confluenceParentPageTitle", "Management Plugins"); this.confluenceUserName = props.getProperty("confluenceUserName"); this.confluencePassword = props.getProperty("confluencePassword"); } public void execute(String projectBaseDirName) throws PluginDocGeneratorException { File projectBaseDir = new File(projectBaseDirName); File pluginXmlFile = new File(projectBaseDir, PLUGIN_DESCRIPTOR_PATH); if (!pluginXmlFile.exists()) { log.info("'" + pluginXmlFile + "' does not exist - nothing to do."); return; } PluginDescriptor pluginDescriptor = parsePluginDescriptor(pluginXmlFile); PluginDescriptorProcessor descriptorProcessor = new PluginDescriptorProcessor(pluginDescriptor); Set<ResourceType> resourceTypes; try { resourceTypes = descriptorProcessor.processPluginDescriptor(); } catch (InvalidPluginDescriptorException e) { throw new PluginDocGeneratorException("Failed to process plugin descriptor.", e); } String pluginName = pluginDescriptor.getName(); log.info("Generating plugin docs for " + pluginName + " plugin..."); File baseOutputDir = new File(projectBaseDir.getParentFile(), OUTPUT_DIR_PATH); generateConfluenceContent(descriptorProcessor, resourceTypes, baseOutputDir); generateDocbookContent(descriptorProcessor, resourceTypes, baseOutputDir); } private static Set<ResourceType> sortResourceTypes(Set<ResourceType> resourceTypes) { Set<ResourceType> orderedChildTypes = new TreeSet<ResourceType>(CHILD_RESOURCE_TYPES_SORTER); orderedChildTypes.addAll(resourceTypes); return orderedChildTypes; } private void generateConfluenceContent(PluginDescriptorProcessor descriptorProcessor, Set<ResourceType> resourceTypes, File baseOutputDir) throws PluginDocGeneratorException { String pluginName = descriptorProcessor.getPluginDescriptor().getName(); System.out.println("Generating Confluence content for " + pluginName + " plugin..."); File confluenceBaseOutputDir = new File(baseOutputDir, "confluence"); File confluenceOutputDir = new File(confluenceBaseOutputDir, pluginName); confluenceOutputDir.mkdirs(); Plugin plugin = descriptorProcessor.getPlugin(); File confluencePluginOutputFile = generateConfluencePluginPage(resourceTypes, confluenceOutputDir, plugin); generateConfluenceResourceTypePages(null, resourceTypes, confluenceOutputDir, plugin); boolean publishConfluencePages = (this.confluenceUserName != null) && (this.confluencePassword != null); Confluence confluence; if (publishConfluencePages) { String endpointURL = this.confluenceUrl + "/rpc/xmlrpc"; log.debug("Publishing plugin docs to Confluence endpoint [" + endpointURL + "]..."); try { confluence = createConfluenceEndpoint(endpointURL); } catch (Exception e) { throw new RuntimeException("Failed to connect to Confluence endpoint [" + endpointURL + "].", e); } try { Page basePage = publishConfluenceBasePage(confluence); //removeDescendantPages(confluence, basePage); publishPluginPage(plugin, confluencePluginOutputFile, confluence, basePage); publishConfluenceResourceTypePages(null, resourceTypes, plugin, confluenceOutputDir, confluence); } catch (Exception e) { throw new RuntimeException("Failed to publish plugin docs to Confluence endpoint [" + endpointURL + "].", e); } finally { try { confluence.logout(); } catch (SwizzleException e) { log.error("Failed to logout from Confluence endpoint.", e); } } } } private void removeDescendantPages(Confluence confluence, Page basePage) throws Exception { List<PageSummary> descendantPages = confluence.getDescendents(basePage.getId()); Page trashbin = getPage(confluence, "TRASHBIN"); for (PageSummary descendantPage : descendantPages) { Page page = confluence.getPage(descendantPage); page.setParentId(trashbin.getId()); page = storePage(confluence, page); confluence.removePage(page.getId()); } } private File generateConfluencePluginPage(Set<ResourceType> resourceTypes, File confluenceOutputDir, Plugin plugin) { if (plugin.getHelp() != null) { String confluenceHelp = getConfluenceHelp(plugin.getHelpContentType(), plugin.getHelp()); plugin.setHelpContentType("confluence"); plugin.setHelp(confluenceHelp); } VelocityTemplateProcessor confluencePluginTemplateProcessor = new VelocityTemplateProcessor( CONFLUENCE_PLUGIN_TEMPLATE_RESOURCE_PATH, CONFLUENCE_MACRO_LIBRARY_RESOURCE_PATH, EscapeConfluenceReference.class); confluencePluginTemplateProcessor.getContext().put("rhqVersion", RHQ_VERSION); confluencePluginTemplateProcessor.getContext().put("plugin", plugin); confluencePluginTemplateProcessor.getContext().put("resourceTypes", resourceTypes); String confluenceOutputFileName = escapeFileName(getPageTitle(plugin) + ".wiki"); File confluencePluginOutputFile = new File(confluenceOutputDir, confluenceOutputFileName); confluencePluginTemplateProcessor.processTemplate(confluencePluginOutputFile); return confluencePluginOutputFile; } private static String getConfluenceHelp(String helpContentType, String help) { String confluenceHelp; if (helpContentType.equals("confluence")) { confluenceHelp = help; } else if (helpContentType.endsWith("html")) { confluenceHelp = DocConverter.htmlToConfluence(help); } else { confluenceHelp = null; } if (confluenceHelp != null) { confluenceHelp = confluenceHelp.replaceAll(" [ ]+", " "); confluenceHelp = confluenceHelp.replaceAll("\n ", "\n"); confluenceHelp = confluenceHelp.replaceAll(" \n", "\n"); confluenceHelp = confluenceHelp.replaceAll("\n\n[\n]+", "\n\n"); // TODO: Fix the below, which is supposed to replace single newlines with spaces. //confluenceHelp = confluenceHelp.replaceAll("\n([^\n\\*h])", " $1"); } return confluenceHelp; } private static String getDocbookHelp(String helpContentType, String help) { String docbookHelp; if (helpContentType.contains("docbook")) { docbookHelp = help; } else if (helpContentType.endsWith("html")) { docbookHelp = DocConverter.htmlToDocBook(help); } else { docbookHelp = null; } return docbookHelp; } private void generateConfluenceResourceTypePages(ResourceType parentType, Set<ResourceType> resourceTypes, File confluenceOutputDir, Plugin plugin) { VelocityTemplateProcessor confluenceResourceTypeTemplateProcessor = new VelocityTemplateProcessor( CONFLUENCE_RESOURCE_TYPE_TEMPLATE_RESOURCE_PATH, CONFLUENCE_MACRO_LIBRARY_RESOURCE_PATH, EscapeConfluenceReference.class); // Traverse the type tree depth first. for (ResourceType resourceType : resourceTypes) { System.out.println("Generating Confluence content for " + resourceType + " Resource type..."); Set<ResourceType> originalChildTypes = resourceType.getChildResourceTypes(); Set<ResourceType> sortedChildTypes = sortResourceTypes(originalChildTypes); resourceType.setChildResourceTypes(sortedChildTypes); if (resourceType.getHelpText() != null) { String confluenceHelp = getConfluenceHelp(resourceType.getHelpTextContentType(), resourceType.getHelpText()); resourceType.setHelpTextContentType("confluence"); resourceType.setHelpText(confluenceHelp); } String pageTitle = getPageTitle(resourceType, parentType); confluenceResourceTypeTemplateProcessor.getContext().put("pageTitle", pageTitle); confluenceResourceTypeTemplateProcessor.getContext().put("resourceType", resourceType); File confluenceResourceTypeOutputFile = getConfluenceResourceTypeOutputFile(confluenceOutputDir, plugin, resourceType); confluenceResourceTypeTemplateProcessor.processTemplate(confluenceResourceTypeOutputFile); resourceType.setChildResourceTypes(originalChildTypes); // Recurse on child types. generateConfluenceResourceTypePages(resourceType, resourceType.getChildResourceTypes(), confluenceOutputDir, plugin); } } private File getConfluenceResourceTypeOutputFile(File confluenceOutputDir, Plugin plugin, ResourceType resourceType) { String pageTitle = getPageTitle(resourceType, null); String confluenceOutputFileName = escapeFileName(pageTitle + ".wiki"); return new File(confluenceOutputDir, confluenceOutputFileName); } private void publishConfluenceResourceTypePages(ResourceType parentType, Set<ResourceType> resourceTypes, Plugin plugin, File confluenceOutputDir, Confluence confluence) throws PluginDocGeneratorException { // Traverse the type tree depth first. for (ResourceType resourceType : resourceTypes) { publishConfluenceResourceTypePage(confluenceOutputDir, plugin, resourceType, parentType, confluence); // Recurse on child types. publishConfluenceResourceTypePages(resourceType, resourceType.getChildResourceTypes(), plugin, confluenceOutputDir, confluence); } } private void publishPluginPage(Plugin plugin, File confluencePluginOutputFile, Confluence confluence, Page basePage) throws Exception { String pluginPageTitle = getPageTitle(plugin); Page pluginPage = getPage(confluence, pluginPageTitle); if (pluginPage == null) { pluginPage = createPage(pluginPageTitle); } else { log.warn("Page with title '" + pluginPageTitle + "' already exists - overwriting it..."); } pluginPage.setContent(getContentAsString(confluencePluginOutputFile)); pluginPage.setParentId(basePage.getId()); storePage(confluence, pluginPage); } private void generateDocbookContent(PluginDescriptorProcessor descriptorProcessor, Set<ResourceType> resourceTypes, File baseOutputDir) { String pluginName = descriptorProcessor.getPluginDescriptor().getName(); System.out.println("Generating DocBook content for " + pluginName + " plugin..."); File docbookBaseOutputDir = new File(baseOutputDir, "docbook"); File docbookOutputDir = new File(docbookBaseOutputDir, descriptorProcessor.getPlugin().getName()); docbookOutputDir.mkdirs(); Plugin plugin = descriptorProcessor.getPlugin(); generateDocbookPluginPage(resourceTypes, docbookOutputDir, plugin); generateDocbookResourceTypePages(new ArrayList<ResourceType>(), resourceTypes, docbookOutputDir, plugin); } private File generateDocbookPluginPage(Set<ResourceType> resourceTypes, File docBookOutputDir, Plugin plugin) { if (plugin.getHelp() != null) { String docBookHelp = getDocbookHelp(plugin.getHelpContentType(), plugin.getHelp()); plugin.setHelpContentType("docbook"); plugin.setHelp(docBookHelp); } VelocityTemplateProcessor docbookPluginTemplateProcessor = new VelocityTemplateProcessor( DOCBOOK_PLUGIN_TEMPLATE_RESOURCE_PATH, DOCBOOK_MACRO_LIBRARY_RESOURCE_PATH, EscapeDocBookReference.class); docbookPluginTemplateProcessor.getContext().put("rhqVersion", RHQ_VERSION); docbookPluginTemplateProcessor.getContext().put("plugin", plugin); String pluginId = getPluginId(plugin); docbookPluginTemplateProcessor.getContext().put("pluginId", pluginId); List<String> typeIds = new ArrayList<String>(resourceTypes.size()); for (ResourceType type : resourceTypes) { String typeId = getTypeId(type, new ArrayList<ResourceType>()); typeIds.add(typeId); } docbookPluginTemplateProcessor.getContext().put("typeIds", typeIds); String docbookOutputFileName = escapeFileName(pluginId + ".xml"); File docbookPluginOutputFile = new File(docBookOutputDir, docbookOutputFileName); docbookPluginTemplateProcessor.processTemplate(docbookPluginOutputFile); return docbookPluginOutputFile; } private void generateDocbookResourceTypePages(List<ResourceType> ancestorTypes, Set<ResourceType> resourceTypes, File docbookOutputDir, Plugin plugin) { VelocityTemplateProcessor docbookTemplateProcessor = new VelocityTemplateProcessor( DOCBOOK_RESOURCE_TYPE_TEMPLATE_RESOURCE_PATH, DOCBOOK_MACRO_LIBRARY_RESOURCE_PATH, EscapeDocBookReference.class); // Traverse the type tree depth first. for (ResourceType resourceType : resourceTypes) { String htmlHelpText = resourceType.getHelpText(); String docBookHelpText = DocConverter.htmlToDocBook(htmlHelpText); resourceType.setHelpText(docBookHelpText); System.out.println("Generating DocBook content for " + resourceType + " Resource type..."); docbookTemplateProcessor.getContext().put("resourceType", resourceType); String typeId = getTypeId(resourceType, ancestorTypes); docbookTemplateProcessor.getContext().put("typeId", typeId); List<String> childTypeIds = new ArrayList<String>(resourceType.getChildResourceTypes().size()); for (ResourceType childType : resourceType.getChildResourceTypes()) { String childTypeId = typeId + ":" + escapeXmlId(childType.getName()); childTypeIds.add(childTypeId); } docbookTemplateProcessor.getContext().put("childTypeIds", childTypeIds); String docbookOutputFileName = escapeFileName(typeId) + ".xml"; File docbookOutputFile = new File(docbookOutputDir, docbookOutputFileName); docbookTemplateProcessor.processTemplate(docbookOutputFile); // Recurse on child types. List<ResourceType> childAncestorTypes = new ArrayList<ResourceType>(ancestorTypes); childAncestorTypes.add(resourceType); generateDocbookResourceTypePages(childAncestorTypes, resourceType.getChildResourceTypes(), docbookOutputDir, plugin); } } private PluginDescriptor parsePluginDescriptor(File pluginXmlFile) throws PluginDocGeneratorException { JAXBContext jaxbContext; try { jaxbContext = JAXBContext.newInstance(PLUGIN_DESCRIPTOR_JAXB_CONTEXT_PATH); } catch (JAXBException e) { throw new PluginDocGeneratorException("Failed to instantiate JAXB context for context path '" + PLUGIN_DESCRIPTOR_JAXB_CONTEXT_PATH + "'.", e); } InputStream is = null; try { is = new FileInputStream(pluginXmlFile); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); // Enable schema validation. (see http://jira.jboss.com/jira/browse/JBNADM-1539) URL pluginSchemaURL = getClass().getClassLoader().getResource("rhq-plugin.xsd"); Schema pluginSchema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema( pluginSchemaURL); unmarshaller.setSchema(pluginSchema); ValidationEventCollector validationEventCollector = new ValidationEventCollector(); unmarshaller.setEventHandler(validationEventCollector); PluginDescriptor pluginDescriptor = (PluginDescriptor) unmarshaller.unmarshal(is); for (ValidationEvent event : validationEventCollector.getEvents()) { log.debug("Plugin [" + pluginDescriptor.getName() + "] descriptor messages {Severity: " + event.getSeverity() + ", Message: " + event.getMessage() + ", Exception: " + event.getLinkedException() + "}"); } return pluginDescriptor; } catch (Exception e) { throw new PluginDocGeneratorException("Could not successfully parse plugin descriptor '" + pluginXmlFile + "'.", e); } finally { if (is != null) { try { is.close(); } catch (IOException e) { // Nothing more we can do here } } } } private void publishConfluenceResourceTypePage(File outputDir, Plugin plugin, ResourceType resourceType, ResourceType parentType, Confluence confluence) throws PluginDocGeneratorException { System.out.println("*** Publishing plugin doc page for " + resourceType + " Resource type to Confluence..."); String pageTitle = getPageTitle(resourceType, parentType); try { Page page = getPage(confluence, pageTitle); if (page == null) { page = createPage(pageTitle); } else { log.warn("Page with title '" + pageTitle + "' already exists - overwriting it..."); } String parentPageTitle; if (resourceType.getParentResourceTypes().isEmpty()) { // root platform or server parentPageTitle = getPageTitle(plugin); } else { if (parentType == null) { parentType = resourceType.getParentResourceTypes().iterator().next(); } parentPageTitle = getPageTitle(parentType, null); } Page parentPage = getPage(confluence, parentPageTitle); if (parentPage != null) { page.setParentId(parentPage.getId()); } else { log.warn("Parent page [" + parentPageTitle + "] for page [" + pageTitle + "] not found - page will have no parent for now."); } File contentFile = getConfluenceResourceTypeOutputFile(outputDir, plugin, resourceType); page.setContent(getContentAsString(contentFile)); page = storePage(confluence, page); } catch (Exception e) { throw new PluginDocGeneratorException("Failed to publish page [" + pageTitle + "] to Confluence.", e); } } private Page publishConfluenceBasePage(Confluence confluence) throws Exception { Page baseParentPage = getPage(confluence, this.confluenceParentPageTitle); if (baseParentPage == null) { baseParentPage = createPage(this.confluenceParentPageTitle); } else { log.warn("Page with title '" + this.confluenceParentPageTitle + "' already exists - overwriting it..."); } baseParentPage.setContent("{children}\n"); Page homePage = getPage(confluence, "Home"); baseParentPage.setParentId(homePage.getId()); baseParentPage = storePage(confluence, baseParentPage); return baseParentPage; } private Confluence createConfluenceEndpoint(String endpoint) throws MalformedURLException, SwizzleException { Confluence confluence = new Confluence(endpoint); confluence.login(this.confluenceUserName, this.confluencePassword); return confluence; } private Page storePage(Confluence confluence, Page page) throws Exception { Page parentPage = getParentPage(confluence, page); String parentPageTitle = (parentPage != null) ? parentPage.getTitle() : null; System.out.println("Storing page [" + page.getTitle() + "] with parent page [" + parentPageTitle + "]..."); Page storedPage; try { storedPage = confluence.storePage(page); } catch (SwizzleException e) { throw new Exception("Failed to publish page [" + page.getTitle() + "] with parent page [" + parentPageTitle + "]: " + e.getMessage()); } parentPage = getParentPage(confluence, storedPage); parentPageTitle = (parentPage != null) ? parentPage.getTitle() : null; System.out.println("Stored page [" + storedPage.getTitle() + "] with ID [" + storedPage.getId() + "] and parent page [" + parentPageTitle + "]."); return storedPage; } private Page getParentPage(Confluence confluence, Page page) throws SwizzleException { return (page.getParentId() != null) ? getPage(confluence, page.getParentId()) : null; } private Page createPage(String pageTitle) { System.out.println("Creating page [" + pageTitle + "]..."); Page page = new Page(); page.setSpace(this.confluenceSpace); page.setTitle(pageTitle); page.setContent("{children}\n"); return page; } private Page getPage(Confluence confluence, String pageTitle) throws SwizzleException { try { return confluence.getPage(this.confluenceSpace, pageTitle); } catch (SwizzleException e) { // This either means the page doesn't exist or that we don't have access to view it. return null; } } private static String getPageTitle(Plugin plugin) { String title = (plugin.getDisplayName() != null) ? plugin.getDisplayName() : plugin.getName(); if (!title.endsWith(" Plugin")) { title += " Plugin"; } return escapePageTitle(title); } private static String getPluginId(Plugin plugin) { return escapeXmlId(plugin.getName()); } private static String getPageTitle(ResourceType resourceType, ResourceType parentType) { StringBuilder buffer = new StringBuilder(); String pluginName = resourceType.getPlugin(); buffer.append(pluginName).append(" - "); Set<ResourceType> parentTypes = resourceType.getParentResourceTypes(); if ((parentType != null) && (parentTypes != null) && (parentTypes.size() > 1)) { // it has multiple parent types, so we'll need to include the parent type in the title String parentTypeName = parentType.getName(); if (parentTypeName.startsWith(pluginName + " ")) { buffer.append(parentTypeName.substring(pluginName.length() + 1)); } else { buffer.append(parentTypeName); } buffer.append(" - "); } String typeName = resourceType.getName(); if (typeName.startsWith(pluginName + " ")) { buffer.append(typeName.substring(pluginName.length() + 1)); } else { buffer.append(typeName); } if (!typeName.endsWith(" " + resourceType.getCategory())) { buffer.append(' ').append(resourceType.getCategory()); } return escapePageTitle(buffer.toString()); } private static String getTypeId(ResourceType resourceType, List<ResourceType> ancestorTypes) { StringBuilder buffer = new StringBuilder(); String pluginName = resourceType.getPlugin(); buffer.append(pluginName).append(':'); for (ResourceType ancestorType : ancestorTypes) { buffer.append(ancestorType.getName()).append(':'); } buffer.append(resourceType.getName()); return escapeXmlId(buffer.toString()); } private static String getContentAsString(File contentFile) throws IOException { StringBuilder content = new StringBuilder(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(contentFile))); String line; try { while ((line = bufferedReader.readLine()) != null) { content.append(line).append("\n"); } } finally { bufferedReader.close(); } return content.toString(); } private static String escapeFileName(String fileName) { // Remove characters that are generally undesirable in filenames. return fileName.replace(' ', '_').replaceAll("[\\\\/\\(\\)\\[\\]\\?\\*]", "-"); } private static String escapePageTitle(String fileName) { return fileName.replace('/', '-'); } private static String escapeXmlId(String id) { return id.replace(' ', '_').replaceAll("[^-\\._:A-Za-z0-9]", "-"); } public static void main(String[] args) throws PluginDocGeneratorException { if (args.length < 1 || args.length > 2) { System.out.println("Usage: " + PluginDocGenerator.class.getSimpleName() + " projectBaseDirName [propertiesFile]"); return; } PluginDocGenerator generator = new PluginDocGenerator(); if (args.length == 2) { String propertiesFile = args[1]; generator.loadProperties(propertiesFile); } String projectBaseDir = args[0]; generator.execute(projectBaseDir); } }