Java tutorial
/* * Copyright 2006-2015 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 <code>build.properties</code> 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. * <p> * The value of this constant is {@value}. * </p> */ private static final String XML_SCHEMA_INSTANCE = "http://www.w3.org/2001/XMLSchema-instance"; /** * The URI of the code doctype. * <p> * The value of this constant is {@value}. * </p> */ 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. * <p> * The value of this constant is {@value}. * </p> */ private static final String GI_VERSION = "version"; /** * The generic identifier of the element name containing a name information. * <p> * The value of this constant is {@value}. * </p> */ 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. * <p> * The name is the name of the property, the section is relevant for placing * the property in one of the following sections: * </p> * <ul> * <li><code>build.scm</code></li> * <li><code>build.dateAndVersion</code></li> * <li><code>build.runtime</code></li> * <li><code>build.java</code></li> * <li><code>build.maven</code></li> * <li><code>build.misc</code></li> * </ul> * <p> * If no valid section is given, the property is silently rendered in the * <code>build.misc</code> section. * </p> */ private final List<Property> 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<Property> 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<Object, Object> 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<Object> 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 -------------------------------------------------------- }