Java tutorial
/* * This file is part of the OpenCms Module Manifest Generator by mediaworx. * * For further information about the OpenCms Module Manifest Generator, * please see the project website at GitHub: * https://github.com/mediaworx/opencms-manifestgenerator * * The OpenCms Module Manifest Generator is used by the OpenCms Plugin for * IntelliJ. For further information see the plugin's project site at GitHub: * https://github.com/mediaworx/opencms-intellijplugin * * Copyright (C) 2012-2014 mediaworx berlin AG (http://www.mediaworx.com) * * 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; either version 3 of the License, or (at your * option) any later version. * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package com.mediaworx.opencms.moduleutils.manifestgenerator; import com.mediaworx.opencms.moduleutils.manifestgenerator.exceptions.OpenCmsMetaXmlFileWriteException; import com.mediaworx.opencms.moduleutils.manifestgenerator.exceptions.OpenCmsMetaXmlParseException; import com.mediaworx.xmlutils.XmlHelper; import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.IOFileFilter; import org.apache.commons.io.filefilter.RegexFileFilter; import org.apache.commons.io.filefilter.TrueFileFilter; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.SAXException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPathExpressionException; import java.io.File; import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Generates the manifest.xml for OpenCms modules from meta files (manifest_stub.xml and separate meta files for all * files and folders in the VFS). The manifest_stub.xml must contain all module specific data, structured exactly like * in a standard OpenCms module manifest, but the files node must be empty. * <br /> * <br /> * Sample manifest_stub.xml: * <pre> * <export> * <info> * <creator>Admin</creator> * <opencms_version>8.5.1</opencms_version> * <createdate>Tue, 17 Dec 2013 14:04:17 GMT</createdate> * <infoproject>Offline</infoproject> * <export_version>7</export_version> * </info> * <module> * <name>com.mediaworx.opencms.intellijconnector</name> * <nicename><![CDATA[IntelliJ Plugin Connector]]></nicename> * <class/> * <description><![CDATA[Connects the IntelliJ Plugin to OpenCms]]></description> * <version>0.2</version> * <authorname><![CDATA[Kai Widmann]]></authorname> * <authoremail><![CDATA[widmann@mediaworx.com]]></authoremail> * <datecreated/> * <userinstalled/> * <dateinstalled/> * <dependencies/> * <exportpoints> * <exportpoint uri="/system/modules/com.mediaworx.opencms.intellijconnector/classes/" destination="WEB-INF/classes/"/> * </exportpoints> * <resources> * <resource uri="/system/modules/com.mediaworx.opencms.intellijconnector/"/> * </resources> * <parameters/> * </module> * <files/> * </export> * </pre> * <br /> * Meta-Files for VFS files must contain all the meta data for the file that is to be included in the manifest, * structured like a file node (type != folder) in a standard OpenCms manifest file, plus additional information about * the sibling count of the file, all wrapped in a fileinfo node. The file name for the meta file is equal to the VFS * file name with ".ocmsfile.xml" added as suffix. * <br /> * <br /> * Sample meta file for VFS files (test.jsp.ocmsfile.xml): * <pre> * <fileinfo> * <file> * <source>${source}</source> * <destination>${destination}</destination> * <type>jsp</type> * <uuidstructure>c76b8773-7c44-11e3-92bb-210cc9a3bba6</uuidstructure> * <uuidresource>c76b8774-7c44-11e3-92bb-210cc9a3bba6</uuidresource> * <datelastmodified>Mon, 13 Jan 2014 12:13:24 GMT</datelastmodified> * <userlastmodified>Admin</userlastmodified> * <datecreated>Mon, 13 Jan 2014 11:20:59 GMT</datecreated> * <usercreated>Admin</usercreated> * <flags>0</flags> * <properties> * <property> * <name>Title</name> * <value><![CDATA[Test Formatter]]></value> * </property> * <property type="shared"> * <name>export</name> * <value><![CDATA[false]]></value> * </property> * </properties> * <relations/> * <accesscontrol> * <accessentry> * <uuidprincipal>GROUP.Guests</uuidprincipal> * <flags>32</flags> * <permissionset> * <allowed>0</allowed> * <denied>0</denied> * </permissionset> * </accessentry> * <accessentry> * <uuidprincipal>GROUP.Users</uuidprincipal> * <flags>36</flags> * <permissionset> * <allowed>23</allowed> * <denied>0</denied> * </permissionset> * </accessentry> * <accessentry> * <uuidprincipal>USER.Admin</uuidprincipal> * <flags>16</flags> * <permissionset> * <allowed>5</allowed> * <denied>26</denied> * </permissionset> * </accessentry> * </accesscontrol> * </file> * <siblingcount>1</siblingcount> * </fileinfo> * </pre> * <br /> * Meta-Files for VFS folders must contain all the meta data for the folder that is to be included in the manifest, * structured like a file node (type == folder) in a standard OpenCms manifest file. The file name for the meta file * is equal to the VFS folder name with ".ocmsfolder.xml" added as suffix. * <br /> * <br /> * Sample meta file for VFS files (formatter.ocmsfolder.xml): * <pre> * <file> * <destination>${destination}</destination> * <type>folder</type> * <uuidstructure>b9fb9670-7c44-11e3-92bb-210cc9a3bba6</uuidstructure> * <datelastmodified>Mon, 13 Jan 2014 11:20:43 GMT</datelastmodified> * <userlastmodified>Admin</userlastmodified> * <datecreated>Mon, 13 Jan 2014 11:20:37 GMT</datecreated> * <usercreated>Admin</usercreated> * <flags>0</flags> * <properties> * <property> * <name>Title</name> * <value><![CDATA[Test Formatters]]></value> * </property> * </properties> * <relations/> * <accesscontrol/> * </file> * </pre> * <br /> * When putting meta files into version control, there may occur a lot of conflicts because of differing dates and * UUIDs on local development machines. To avoid conflicts manifest data can be stored with variables instead of dates * and UUIDs. The manifest generator replaces these variables with generated values when a manifest is created. * <br /> * <br /> * Sample meta file for VFS files with variables instead of dates and UUIDs (formatter.ocmsfolder.xml): * <pre> * <file> * <destination>${destination}</destination> * <type>folder</type> * <uuidstructure>${uuidstructure}</uuidstructure> * <datelastmodified>${datelastmodified}</datelastmodified> * <userlastmodified>Admin</userlastmodified> * <datecreated>${datecreated}</datecreated> * <usercreated>Admin</usercreated> * <flags>0</flags> * <properties> * <property> * <name>Title</name> * <value><![CDATA[Test Formatters]]></value> * </property> * </properties> * <relations/> * <accesscontrol/> * </file> * </pre> * <br /> * mediaworx provides an OpenCms module for pulling the meta files from OpenCms * (com.mediaworx.opencms.intellijconnector). */ public class OpenCmsModuleManifestGenerator { private static final Logger LOG = LoggerFactory.getLogger(OpenCmsModuleManifestGenerator.class); /** File name of the module manifest stub file (standard OpenCms module manifest with an empty files node) */ private static final String FILENAME_MANIFEST_STUB = "manifest_stub.xml"; /** File name for the generated module manifest */ private static final String FILENAME_MANIFEST = "manifest.xml"; /** File name suffix for VFS folder meta files */ private static final String FOLDER_META_SUFFIX = ".ocmsfolder.xml"; /** File name suffix for VFS file meta files */ private static final String FILE_META_SUFFIX = ".ocmsfile.xml"; /** XPath pointing to the files node in the manifest stub file */ private static final String FILES_NODE_XPATH = "/export/files"; /** XPath pointing to the file node in VFS file meta files */ private static final String FILE_NODE_XPATH = "/fileinfo/file"; /** XPath pointing to the siblingcount node in VFS file meta files */ private static final String SIBLINGCOUNT_NODE_XPATH = "/fileinfo/siblingcount"; /** XPath pointing to the uuidresource node in VFS file meta files (used to track siblings) */ private static final String RESOURCEID_NODE_XPATH = "/fileinfo/file/uuidresource"; /** XPath pointing to the source node in VFS file meta files */ private static final String SOURCE_NODE_XPATH = "/fileinfo/file/source"; /** Array of manifest nodes using CDATA sections */ private static final String[] CDATA_NODES = new String[] { "nicename", "description", "authorname", "authoremail", "value" }; /** Variable used as placeholder for the source path */ public static final String META_VAR_SOURCE = "${source}"; /** Variable used as placeholder for the destination path */ public static final String META_VAR_DESTINATION = "${destination}"; /** Variable used as placeholder for the structure UUID */ public static final String META_VAR_UUIDSTRUCTURE = "${uuidstructure}"; /** Variable used as placeholder for the resource UUID */ public static final String META_VAR_UUIDRESOURCE = "${uuidresource}"; /** Variable used as placeholder for the resource modification date */ public static final String META_VAR_DATELASTMODIFIED = "${datelastmodified}"; /** Variable used as placeholder for the resource creation date */ public static final String META_VAR_DATECREATED = "${datecreated}"; /** Variable used as placeholder for the manifest's creation date */ public static final String META_VAR_CREATEDATE = "${createdate}"; /** The date format to use for resource creation/modification dates, this is exactly like the date format used by OpenCms */ private static final DateFormat RESOURCE_DATE_FORMAT = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); static { RESOURCE_DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT")); } /** * Set used to track resource Ids of resources with siblings (if a resource is referenced by multiple siblings, * only the first file entry pointing to that resource contains a source node) */ private HashSet<String> handledSiblingResourceIds; /** * Xml helper object used for parsing the manifest stub file */ private XmlHelper xmlHelper; /** * Module version to be used in the manifest, ignored if <code>null</code> or empty */ private String moduleVersion; /** * The root path under which the manifest stub and all the meta files are stored */ private String manifestRootPath; /** * Flag indicating if meta variables (<code>${uuidstructure}</code>, <code>${uuidresource}</code>, * <code>${datelastmodified}</code> and <code>${datecreated}</code>) should be replaced with generated values. */ private boolean replaceMetaVariables = false; /** * Flag indicating if the <code>${datelastmodified}</code> meta variable should be set to "now" to force * compilation of new servlet classes from JSPs. */ private boolean touchAllFiles = false; /** * Generates the manifest.xml for OpenCms modules from meta files (manifest_stub.xml and separate meta files for all * files and folders in the VFS). * @param manifestRoot file representing the root folder of the manifest meta data (including manifest_stub.xml) * * @throws OpenCmsMetaXmlParseException if the XmlHelper can not be initialized or the manifest stub file or any * meta file can not be read or parsed * @throws OpenCmsMetaXmlFileWriteException if the resulting manifest file can not be written */ public void generateManifest(File manifestRoot) throws OpenCmsMetaXmlParseException, OpenCmsMetaXmlFileWriteException { manifestRootPath = manifestRoot.getPath(); handledSiblingResourceIds = new HashSet<String>(); String manifestStubPath = manifestRoot.getPath() + File.separator + FILENAME_MANIFEST_STUB; String manifestPath = manifestRoot.getPath() + File.separator + FILENAME_MANIFEST; LOG.info("manifestStubPath: {}", manifestStubPath); Node filesNode; Document manifest; try { xmlHelper = new XmlHelper(); Map<String, String> replacements = null; if (replaceMetaVariables) { replacements = new HashMap<String, String>(); replacements.put(META_VAR_CREATEDATE, formatDate((new Date()).getTime())); } manifest = xmlHelper.parseFile(manifestStubPath, replacements); filesNode = xmlHelper.getSingleNodeForXPath(manifest, FILES_NODE_XPATH); } catch (ParserConfigurationException e) { throw new OpenCmsMetaXmlParseException("The XmlHelper could not be initialized", e); } catch (IOException e) { throw new OpenCmsMetaXmlParseException("The manifest stub file could not be read", e); } catch (SAXException e) { throw new OpenCmsMetaXmlParseException("The manifest stub xml could not be parsed (parse error)", e); } catch (XPathExpressionException e) { throw new OpenCmsMetaXmlParseException("The manifest stub xml could not be parsed (xpath error)", e); } // Regular Expression matching anything but Strings ending with the VFS folder meta file suffix (".ocmsfolder.xml") String excludeFolderMetaRegex = "^(?:(?!" + Pattern.quote(FOLDER_META_SUFFIX) + "$).)*$"; // FileFilter filtering all VFS folder meta files (so only VFS file meta files and folders are included) IOFileFilter excludeFolderMetaFilter = new RegexFileFilter(excludeFolderMetaRegex); // read all files and folders excluding VFS folder meta files Collection<File> files = FileUtils.listFilesAndDirs(manifestRoot, excludeFolderMetaFilter, TrueFileFilter.INSTANCE); for (File file : files) { if (file.isDirectory()) { // exclude the manifest root if (file.getPath().equals(manifestRoot.getPath())) { continue; } addFolderToFilesNode(filesNode, file); } else { // exclude the manifest stub file and the manifest file if (file.getPath().equals(manifestPath) || file.getPath().equals(manifestStubPath)) { continue; } addFileToFilesNode(filesNode, file); } } // render the xml string String manifestString = xmlHelper.getXmlStringFromDocument(manifest, CDATA_NODES); // if a specific version is provided, replace the original version if (StringUtils.isNotBlank(moduleVersion)) { manifestString = manifestString.replaceFirst("<version>[^<]*</version>", "<version>" + Matcher.quoteReplacement(moduleVersion) + "</version>"); } // write the manifest to the disk try { writeManifest(manifestPath, manifestString); } catch (IOException e) { throw new OpenCmsMetaXmlFileWriteException("manifest.xml could not be written", e); } } /** * Generates a random UUID * @return a random UUID */ private static String generateUUID() { return UUID.randomUUID().toString(); } /** * Creates a String from the date that can be used as a resource date in the manifest file * @param millisecondsSinceEpoch the milliseconds since January 1, 1970, 00:00:00 GMT. * @return formatted date as String */ private static String formatDate(long millisecondsSinceEpoch) { Date date = new Date(millisecondsSinceEpoch); return RESOURCE_DATE_FORMAT.format(date); } /** * Replaces System file separators with a forward slash ("/") that's needed for the VFS * @param path the path containing system file separators * @return the path with file separators replaced by "/" */ private String fixVfsFileSeparator(String path) { if (!File.separator.equals("/")) { path = path.replaceAll(Pattern.quote(File.separator), "/"); } return path; } /** * Adds the meta information for the given folder to the given files node. * @param filesNode the files node the folder meta data is to be added to * @param folder the folder whose meta data is to be added * @throws OpenCmsMetaXmlParseException if the VFS folder meta file can not be read or parsed */ private void addFolderToFilesNode(Node filesNode, File folder) throws OpenCmsMetaXmlParseException { LOG.debug("folder: {}", folder.getPath()); String metaXmlFilePath = folder.getPath() + FOLDER_META_SUFFIX; LOG.debug("meta folder: {}", metaXmlFilePath); String vfsPath = metaXmlFilePath.substring(manifestRootPath.length() + 1, metaXmlFilePath.length() - FOLDER_META_SUFFIX.length()); vfsPath = fixVfsFileSeparator(vfsPath); Map<String, String> replacements = new HashMap<String, String>(); replacements.put(META_VAR_DESTINATION, vfsPath); if (replaceMetaVariables) { replacements.put(META_VAR_UUIDSTRUCTURE, generateUUID()); replacements.put(META_VAR_DATELASTMODIFIED, formatDate(touchAllFiles ? new Date().getTime() : folder.lastModified())); replacements.put(META_VAR_DATECREATED, formatDate(folder.lastModified())); } try { // append the whole content of the meta file as a child node to the files node xmlHelper.appendFileAsNode(filesNode, metaXmlFilePath, replacements); } catch (IOException e) { throw new OpenCmsMetaXmlParseException("The file " + metaXmlFilePath + " could not be read", e); } catch (SAXException e) { throw new OpenCmsMetaXmlParseException( "The xml from the file " + metaXmlFilePath + " could not be parsed", e); } } /** * Adds the meta information contained in the file node of the given xml file to the given files node. Siblings are * handled according to OpenCms standard (if multiple siblings are pointing to the same resource, only the first * gets a source node). * @param filesNode the files node the file meta data is to be added to * @param metaFile the meta file whose meta data (contained in the file node) is to be added * @throws OpenCmsMetaXmlParseException if the folder meta file can not be read or parsed */ private void addFileToFilesNode(Node filesNode, File metaFile) throws OpenCmsMetaXmlParseException { String metaXmlFilePath = metaFile.getPath(); LOG.debug("meta file: {}", metaXmlFilePath); Document fileMetaInfo = getFileMetaInfoFromXmlFile(metaXmlFilePath, metaFile); Node fileNode = getFileNodeFromMetaInfo(fileMetaInfo, metaXmlFilePath); int numSiblings = getNumSiblingsForFile(fileMetaInfo, metaXmlFilePath); // sibling handling only has to be done if there are at least two siblings if (numSiblings >= 2) { String resourceId = getResourceIdForFile(fileMetaInfo, metaXmlFilePath); // if we encounter a resourceId that already has been handled ... if (handledSiblingResourceIds.contains(resourceId)) { // ... the source node is removed from the file's xml (that's how OpenCms treats siblings: only // the first gets a source node), so the resource is not imported a second time during module import removeSourceNodeFromFile(fileNode, metaXmlFilePath); } else { handledSiblingResourceIds.add(resourceId); } } xmlHelper.appendNode(filesNode, fileNode); } /** * Retrieves the XML Document from the VFS file meta file at the given path. * * @param metaXmlFilePath path pointing to the VFS file meta file * @param metaFile the VFS file meta file * @return the XML Document contained in the meta file * @throws OpenCmsMetaXmlParseException if the VFS file meta file can not be read or parsed */ private Document getFileMetaInfoFromXmlFile(String metaXmlFilePath, File metaFile) throws OpenCmsMetaXmlParseException { Document fileMetaInfo; String vfsPath = metaXmlFilePath.substring(manifestRootPath.length() + 1, metaXmlFilePath.length() - FILE_META_SUFFIX.length()); vfsPath = fixVfsFileSeparator(vfsPath); Map<String, String> replacements = new HashMap<String, String>(); replacements.put(META_VAR_SOURCE, vfsPath); replacements.put(META_VAR_DESTINATION, vfsPath); if (replaceMetaVariables) { replacements.put(META_VAR_UUIDSTRUCTURE, generateUUID()); replacements.put(META_VAR_UUIDRESOURCE, generateUUID()); replacements.put(META_VAR_DATELASTMODIFIED, formatDate(touchAllFiles ? new Date().getTime() : metaFile.lastModified())); replacements.put(META_VAR_DATECREATED, formatDate(metaFile.lastModified())); } try { fileMetaInfo = xmlHelper.parseFile(metaXmlFilePath, replacements); } catch (IOException e) { throw new OpenCmsMetaXmlParseException("The file " + metaXmlFilePath + " could not be read", e); } catch (SAXException e) { throw new OpenCmsMetaXmlParseException( "The xml from the file " + metaXmlFilePath + " could not be parsed (parse error)", e); } return fileMetaInfo; } /** * Retrieves the file node from the VFS file meta XML document (located at the XPath {@link #FILE_NODE_XPATH}). * * @param fileMetaInfo VFS file meta XML document * @param metaXmlFilePath path pointing to the VFS file meta file (only used for logging purposes) * @return the file node to be added to the manifest * @throws OpenCmsMetaXmlParseException if the file node can not be found at the expected XPath * (see {@link #FILE_NODE_XPATH}) */ private Node getFileNodeFromMetaInfo(Document fileMetaInfo, String metaXmlFilePath) throws OpenCmsMetaXmlParseException { Node fileNode; try { fileNode = xmlHelper.getSingleNodeForXPath(fileMetaInfo, FILE_NODE_XPATH); } catch (XPathExpressionException e) { throw new OpenCmsMetaXmlParseException( "The xml from the file " + metaXmlFilePath + " could not be parsed (xpath error)", e); } return fileNode; } /** * Retrieves the number of siblings for the VFS file. * @param metaInfo VFS file meta XML document * @param metaXmlFilePath path pointing to the VFS file meta file (only used for logging purposes) * @return the number of siblings for the VFS file * @throws OpenCmsMetaXmlParseException if the siblingcount node can not be found at the expected XPath * (see {@link #SIBLINGCOUNT_NODE_XPATH}) */ private int getNumSiblingsForFile(Document metaInfo, String metaXmlFilePath) throws OpenCmsMetaXmlParseException { int numSiblings; try { numSiblings = xmlHelper.getIntValueForXpath(metaInfo, SIBLINGCOUNT_NODE_XPATH); } catch (XPathExpressionException e) { throw new OpenCmsMetaXmlParseException( "Can't determine sibling count from " + metaXmlFilePath + " (xpath error)", e); } catch (NumberFormatException e) { throw new OpenCmsMetaXmlParseException( "Can't determine sibling count from " + metaXmlFilePath + " (not a number)", e); } return numSiblings; } /** * Retrieves the resource Id for the VFS file. * @param metaInfo VFS file meta XML document * @param metaXmlFilePath path pointing to the VFS file meta file (only used for logging purposes) * @return the resource Id for the VFS file * @throws OpenCmsMetaXmlParseException if the uuidresource node can not be found at the expected XPath * (see {@link #RESOURCEID_NODE_XPATH}) */ private String getResourceIdForFile(Document metaInfo, String metaXmlFilePath) throws OpenCmsMetaXmlParseException { String resourceId; try { resourceId = xmlHelper.getStringValueForXpath(metaInfo, RESOURCEID_NODE_XPATH); } catch (XPathExpressionException e) { throw new OpenCmsMetaXmlParseException( "Can't determine resource id from " + metaXmlFilePath + " (xpath error)", e); } return resourceId; } /** * Removes the source node from the given file node (used for siblings). * @param fileNode the file node from which the source node is to be removed * @param metaXmlFilePath path pointing to the VFS file meta file (only used for logging purposes) * @throws OpenCmsMetaXmlParseException if the source node can not be found at the expected XPath * (see {@link #SOURCE_NODE_XPATH}) */ private void removeSourceNodeFromFile(Node fileNode, String metaXmlFilePath) throws OpenCmsMetaXmlParseException { Node sourceNode; try { sourceNode = xmlHelper.getSingleNodeForXPath(fileNode, SOURCE_NODE_XPATH); } catch (XPathExpressionException e) { throw new OpenCmsMetaXmlParseException( "Can't remove sibling's source node from " + metaXmlFilePath + " (xpath error)", e); } sourceNode.getParentNode().removeChild(sourceNode); } /** * Gets the path to the meta info file for the VFS file or folder at the given VFS path. * @param manifestRoot root folder of the manifest meta files * @param vfsPath VFS path of the given VFS file or folder * @param isFolder <code>true</code> if the VFS resource is a folder, <code>false</code> otherwise * @return "[vfsPath].ocmsfile.xml" for files, "[vfsPath].ocmsfolder.xml" for folders */ public static String getMetaInfoPath(String manifestRoot, String vfsPath, boolean isFolder) { return manifestRoot + vfsPath + getMetaInfoSuffix(isFolder); } /** * Returns the suffix for the meta file depending in <code>isFolder</code>. * @param isFolder <code>true</code> if the suffix for folders should be returned, <code>false</code> otherwise * @return ".ocmsfolder.xml" ({@link #FOLDER_META_SUFFIX} if <code>isFolder</code> is <code>true</code>, * ".ocmsfile.xml" ({@link #FILE_META_SUFFIX} otherwise */ private static String getMetaInfoSuffix(boolean isFolder) { return isFolder ? FOLDER_META_SUFFIX : FILE_META_SUFFIX; } /** * Writes the manifest file to the disk. * @param manifestPath path to the manifest file * @param manifestString String content of the manifest file * @throws IOException if writing to disk fails */ private void writeManifest(String manifestPath, String manifestString) throws IOException { FileUtils.writeStringToFile(new File(manifestPath), manifestString); } /** * Allows to set a specific module version that is replacing the module version from the manifest stub. * @param moduleVersion the String to be used as the module version, if <code>null</code> or empty the version is * not changed */ public void setModuleVersion(String moduleVersion) { this.moduleVersion = moduleVersion; } /** * Sets the flag indicating if meta variables (<code>${uuidstructure}</code>, <code>${uuidresource}</code>, * <code>${datelastmodified}</code> and <code>${datecreated}</code>) should be replaced with generated values. * @param replaceMetaVariables <code>true</code> if meta variables should be replaced, <code>false</code> otherwise */ public void setReplaceMetaVariables(boolean replaceMetaVariables) { this.replaceMetaVariables = replaceMetaVariables; } /** * Flag indicating if the <code>${datelastmodified}</code> meta variable should be set to "now" to force * compilation of new servlet classes from JSPs. * @param touchAllFiles <code>true</code> if all files and folders should be 'touched' (have their last-modified date set to 'now'), <code>false</code> otherwise */ public void setTouchAllFiles(boolean touchAllFiles) { this.touchAllFiles = touchAllFiles; } }