All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.smartics.maven.plugin.buildmetadata.io.SdocBuilder Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2006-2019 smartics, Kronseder & Reiner GmbH
 *
 * Licensed 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 de.smartics.maven.plugin.buildmetadata.io;

import de.smartics.maven.plugin.buildmetadata.common.Constant;
import de.smartics.maven.plugin.buildmetadata.common.Property;
import de.smartics.maven.plugin.buildmetadata.common.SortedProperties;
import de.smartics.maven.plugin.buildmetadata.util.FilePathNormalizer;

import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.plexus.util.StringUtils;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

/**
 * Creates an XML report with the build meta data. The report contains the same
 * information as the build.properties file. It is useful for use
 * cases where the build meta data information will be further processed by XSL
 * transformations which require XML documents as input.
 */
public final class SdocBuilder {
  // ********************************* Fields *********************************

  // --- constants ------------------------------------------------------------

  /**
   * The URI of the XML schema instance.
   * 

* The value of this constant is {@value}. *

*/ private static final String XML_SCHEMA_INSTANCE = "http://www.w3.org/2001/XMLSchema-instance"; /** * The URI of the code doctype. *

* The value of this constant is {@value}. *

*/ private static final String CODE_URI = "http://www.smartics.de/project/process/implementation/buildmetadata"; /** * The generic identifier of the element name containing a version * information. *

* The value of this constant is {@value}. *

*/ private static final String GI_VERSION = "version"; /** * The generic identifier of the element name containing a name information. *

* The value of this constant is {@value}. *

*/ private static final String GI_NAME = "name"; /** * Reference to the logger for this class. */ private static final Log LOG = LogFactory.getLog(SdocBuilder.class); // --- members -------------------------------------------------------------- /** * The normalizer to be applied to file name value to remove the base dir * prefix. */ private final FilePathNormalizer filePathNormalizer; /** * The empty document to write to. */ private final Document document; /** * The properties to write to the XML report. */ private final Properties buildMetaDataProperties; /** * The list of a system properties or environment variables to be selected by * the user to include into the build meta data properties. *

* The name is the name of the property, the section is relevant for placing * the property in one of the following sections: *

*
    *
  • build.scm
  • *
  • build.dateAndVersion
  • *
  • build.runtime
  • *
  • build.java
  • *
  • build.maven
  • *
  • build.misc
  • *
*

* If no valid section is given, the property is silently rendered in the * build.misc section. *

*/ private final List selectedProperties; // ****************************** Initializer ******************************* // ****************************** Constructors ****************************** /** * Default constructor. * * @param filePathNormalizer the normalizer to be applied to file name value * to remove the base dir prefix. * @param document the empty document to write to. * @param buildMetaDataProperties the properties to write to the XML report. * @param selectedProperties the list of a system properties or environment * variables to be selected by the user to include into the build meta * data properties. */ public SdocBuilder(final FilePathNormalizer filePathNormalizer, final Document document, final Properties buildMetaDataProperties, final List selectedProperties) { this.filePathNormalizer = filePathNormalizer; this.document = document; this.buildMetaDataProperties = buildMetaDataProperties; this.selectedProperties = selectedProperties; } // ****************************** Inner Classes ***************************** // ********************************* Methods ******************************** // --- init ----------------------------------------------------------------- // --- get&set -------------------------------------------------------------- // --- business ------------------------------------------------------------- /** * Writes the content to the document. * * @return the written XML document. * @throws IOException on any problem writing to the XML document. */ public Document writeDocumentContent() throws IOException { final Element docRoot = createDocRoot(); createContentElement(GI_NAME, Constant.PROP_NAME_FULL_VERSION, docRoot); createContentElement("category", Constant.PROP_NAME_PROJECT_CATEGORY, docRoot); createContentElement("subcategory", Constant.PROP_NAME_PROJECT_SUBCATEGORY, docRoot); createContentElement(GI_VERSION, Constant.PROP_NAME_VERSION, docRoot); createContentElement("groupId", Constant.PROP_NAME_GROUP_ID, docRoot); createContentElement("artifactId", Constant.PROP_NAME_ARTIFACT_ID, docRoot); final String date = formatDate(Constant.PROP_NAME_BUILD_DATE); createValueElement("date", date, docRoot); createContentElement("timestamp", Constant.PROP_NAME_BUILD_TIMESTAMP, docRoot); createTagsElement(docRoot); createContentElement("build-year", Constant.PROP_NAME_BUILD_YEAR, docRoot); createProjectElement(docRoot); createScmElement(docRoot); createRuntimeElement(docRoot); createMiscElement(docRoot); return document; } private void createTagsElement(final Element docRoot) { final Element tags = document.createElement("tags"); final String tagsString = buildMetaDataProperties.getProperty(Constant.PROP_NAME_PROJECT_TAGS); renderList(tags, "tag", tagsString); if (tags.hasChildNodes()) { docRoot.appendChild(tags); } } private String formatDate(final String datePropertyKey) { final String originalDateString = buildMetaDataProperties.getProperty(datePropertyKey); if (StringUtils.isNotBlank(originalDateString)) { try { final String originalPattern = buildMetaDataProperties .getProperty(Constant.PROP_NAME_BUILD_DATE_PATTERN); final DateFormat format = new SimpleDateFormat(originalPattern, Locale.ENGLISH); final Date date = format.parse(originalDateString); final String dateString = DateFormatUtils.ISO_DATETIME_FORMAT.format(date); return dateString; } catch (final ParseException e) { if (LOG.isDebugEnabled()) { LOG.debug("Cannot parse date of property '" + datePropertyKey + "': " + originalDateString + ". Skipping..."); } return null; } } return null; } private void createScmElement(final Element docRoot) { final Element parent = document.createElement("scm"); createContentElement("revision", Constant.PROP_NAME_SCM_REVISION_ID, parent); final String date = formatDate(Constant.PROP_NAME_SCM_REVISION_DATE); createValueElement("revision-date", date, parent); createContentElement("url", Constant.PROP_NAME_SCM_URL, parent); createLocallyModifiedFiles(parent); docRoot.appendChild(parent); } private void createLocallyModifiedFiles(final Element scm) { final String value = buildMetaDataProperties .getProperty(Constant.PROP_NAME_SCM_LOCALLY_MODIFIED_FILES); if (StringUtils.isNotBlank(value)) { final Element parent = document.createElement("locally-modified-files"); final String filesValue = Constant.prettifyFilesValue(value); renderFiles(parent, filesValue); scm.appendChild(parent); } } private void renderFiles(final Element lmf, final String value) { final String stringValue = Constant.prettify(value); final StringTokenizer tokenizer = new StringTokenizer(stringValue, ","); while (tokenizer.hasMoreTokens()) { final String subValue = tokenizer.nextToken(); final int colonIndex = subValue.indexOf(':'); if (colonIndex > -1) { final String filePath = subValue.substring(0, colonIndex); final Element file = createValueElement("file", filePath, lmf); if (file != null && colonIndex < subValue.length() - 1) { final String modType = subValue.substring(colonIndex + 1).trim(); file.setAttribute("modtype", modType); } } } } private void renderFiles(final Element parent, final String itemTag, final String value) { if (StringUtils.isNotBlank(value)) { final String stringValue = Constant.prettify(value); final StringTokenizer tokenizer = new StringTokenizer(stringValue, ","); while (tokenizer.hasMoreTokens()) { final String item = tokenizer.nextToken(); final String itemTrimmed = item.trim(); final String itemNorm = filePathNormalizer.normalize(itemTrimmed); createValueElement(itemTag, itemNorm, parent); } } } private void createProjectElement(final Element docRoot) { final Element parent = document.createElement("project"); createContentElement("copyright-year", Constant.PROP_NAME_COPYRIGHT_YEAR, parent); createContentElement("home-page-url", Constant.PROP_NAME_PROJECT_HOMEPAGE, parent); createContentElement("ops-home-page-url", Constant.PROP_NAME_PROJECT_OPS, parent); if (parent.hasChildNodes()) { docRoot.appendChild(parent); } } private void renderList(final Element tags, final String itemTag, final String value) { if (StringUtils.isNotBlank(value)) { final String stringValue = Constant.prettify(value); final StringTokenizer tokenizer = new StringTokenizer(stringValue, ","); while (tokenizer.hasMoreTokens()) { final String item = tokenizer.nextToken(); createValueElement(itemTag, item.trim(), tags); } } } private void createRuntimeElement(final Element docRoot) { final Element parent = document.createElement("runtime"); createContentElement("build-server", Constant.PROP_NAME_HOSTNAME, parent); createContentElement("build-user", Constant.PROP_NAME_BUILD_USER, parent); createOsElement(parent); createJavaElement(parent); createMavenElement(parent); createEnvElement(parent); docRoot.appendChild(parent); } private void createOsElement(final Element runtime) { final Element parent = document.createElement("os"); createContentElement("arch", Constant.PROP_NAME_OS_ARCH, parent); createContentElement(GI_NAME, Constant.PROP_NAME_OS_NAME, parent); createContentElement(GI_VERSION, Constant.PROP_NAME_OS_VERSION, parent); if (parent.hasChildNodes()) { runtime.appendChild(parent); } } private void createJavaElement(final Element runtime) { final Element parent = document.createElement("java"); createContentElement(GI_NAME, Constant.PROP_NAME_JAVA_RUNTIME_NAME, parent); createContentElement(GI_VERSION, Constant.PROP_NAME_JAVA_RUNTIME_VERSION, parent); createContentElement("vendor", Constant.PROP_NAME_JAVA_VENDOR, parent); createContentElement("vm", Constant.PROP_NAME_JAVA_VM, parent); createContentElement("compiler", Constant.PROP_NAME_JAVA_COMPILER, parent); createContentElement("options", Constant.PROP_NAME_JAVA_OPTS, parent); for (final String key : buildMetaDataProperties.stringPropertyNames()) { final String prefix = "build.runtime.java."; if (key.startsWith(prefix)) { final String shortenedKey = key.substring(prefix.length()); createContentElement(shortenedKey, key, parent); } } if (parent.hasChildNodes()) { runtime.appendChild(parent); } } private void createMavenElement(final Element runtime) { final Element parent = document.createElement("maven"); createContentElement(GI_VERSION, Constant.PROP_NAME_MAVEN_VERSION, parent); createContentElement("commandline", Constant.PROP_NAME_MAVEN_CMDLINE, parent); createContentElement("execution-project", Constant.PROP_NAME_MAVEN_EXECUTION_PROJECT, parent); createContentElement("is-excution-root", Constant.PROP_NAME_MAVEN_IS_EXECUTION_ROOT, parent); final Element goals = document.createElement("goals"); final String goalsString = buildMetaDataProperties.getProperty(Constant.PROP_NAME_MAVEN_GOALS); renderList(goals, "goal", goalsString); parent.appendChild(goals); final Element filters = document.createElement("filters"); final String filtersString = buildMetaDataProperties.getProperty(Constant.PROP_NAME_MAVEN_FILTERS); renderFiles(filters, "filter", filtersString); if (filters.hasChildNodes()) { parent.appendChild(filters); } final Element profiles = document.createElement("profiles"); final String profilesString = buildMetaDataProperties .getProperty(Constant.PROP_NAME_MAVEN_ACTIVE_PROFILES); if (StringUtils.isNotBlank(profilesString)) { renderProfiles(profiles, profilesString); parent.appendChild(profiles); } createContentElement("options", Constant.PROP_NAME_MAVEN_OPTS, parent); if (parent.hasChildNodes()) { runtime.appendChild(parent); } } private void renderProfiles(final Element profiles, final String value) { final String stringValue = Constant.prettify(value); final StringTokenizer tokenizer = new StringTokenizer(stringValue, ","); while (tokenizer.hasMoreTokens()) { final String profileName = tokenizer.nextToken().trim(); final Element profile = createValueElement("profile", profileName, profiles); if (profile != null) { final String profileSourceKey = Constant.MAVEN_ACTIVE_PROFILE_PREFIX + '.' + profileName; final String source = buildMetaDataProperties.getProperty(profileSourceKey); profile.setAttribute("source", source); } } } private void createEnvElement(final Element runtime) { final Element parent = document.createElement("env"); final Properties sorted = SortedProperties.createSorted(buildMetaDataProperties); final String matchPrefix = Constant.MAVEN_EXECUTION_PROPERTIES_PREFIX + '.'; for (final Map.Entry entry : sorted.entrySet()) { final String key = String.valueOf(entry.getKey()); if (key.startsWith(matchPrefix)) { final String value = String.valueOf(entry.getValue()); final Element env = createValueElement("var", value, parent); if (env != null) { env.setAttribute(GI_NAME, key); } } } if (parent.hasChildNodes()) { runtime.appendChild(parent); } } private void createMiscElement(final Element docRoot) { final Properties nonStandardProperties = Constant .calcNonStandardProperties(buildMetaDataProperties, selectedProperties); if (!nonStandardProperties.isEmpty()) { final Element parent = document.createElement("misc"); for (final Enumeration en = nonStandardProperties.keys(); en .hasMoreElements();) { final String key = String.valueOf(en.nextElement()); createMetaDataElement(parent, key); } docRoot.appendChild(parent); } } private void createMetaDataElement(final Element parent, final String key) { if (Constant.isIntendedForMiscSection(key)) { final Element metadata = createContentElement("metadata", key, parent); if (metadata != null) { metadata.setAttribute(GI_NAME, key); } } } private Element createDocRoot() throws DOMException { final Element docRoot = document.createElement("buildmetadata"); docRoot.setAttribute("xmlns:xsi", XML_SCHEMA_INSTANCE); docRoot.setAttribute("xmlns", CODE_URI); docRoot.setAttribute("xsi:schemaLocation", CODE_URI + ' ' + CODE_URI); document.appendChild(docRoot); return docRoot; } private Element createContentElement(final String gi, final String propertyKey, final Element parent) { final String content = buildMetaDataProperties.getProperty(propertyKey); return createValueElement(gi, content, parent); } private Element createValueElement(final String gi, final String value, final Element parent) { if (value != null) { final Element element = document.createElement(gi); final Text text = document.createTextNode(value); element.appendChild(text); parent.appendChild(element); return element; } return null; } // --- object basics -------------------------------------------------------- }