Java tutorial
/** * Copyright 2009-2017 the original author or authors. * * 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 org.metaeffekt.dcc.commons.ant; import static org.metaeffekt.dcc.commons.DccProperties.DCC_UNIT_CONTRIBUTION_ITERATOR_SEQUENCE_REGEX; import static org.metaeffekt.dcc.commons.DccProperties.DCC_UNIT_PROVISION_ITERATOR_SEQUENCE_REGEX; import static org.metaeffekt.dcc.commons.DccProperties.DCC_UNIT_REQUISITION_ITERATOR_SEQUENCE_REGEX; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.Velocity; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.texen.util.FileUtil; import org.metaeffekt.dcc.commons.DccProperties; /** * Applies a velocity template to a given input properties file. The task supports an additional * iterator sequence to support an iterator in the velocity template independent from the data * inside the property file. * * @author Karsten Klein * @author Alexander D. */ public class ApplyVelocityTemplateTask extends Task { private static final String ENCODING_UTF_8 = "UTF-8"; private File propertyFile; private File templateFile; private File targetFile; private boolean enableLogging = false; @Override public void execute() throws BuildException { notNull(propertyFile, "propertyFile"); notNull(templateFile, "templateFile"); notNull(targetFile, "targetFile"); Properties properties = PropertyUtils.loadEnrichedProperties(getProject(), propertyFile); String contributionIteratorSequence = properties .getProperty(DccProperties.DCC_UNIT_CONTRIBUTION_ITERATOR_SEQUENCE); String requisitionIteratorSequence = properties .getProperty(DccProperties.DCC_UNIT_REQUISITION_ITERATOR_SEQUENCE); String provisionIteratorSequence = properties .getProperty(DccProperties.DCC_UNIT_PROVISION_ITERATOR_SEQUENCE); Properties velocityProperties = new Properties(); velocityProperties.setProperty(Velocity.RESOURCE_LOADER, "file"); velocityProperties.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader"); velocityProperties.setProperty(Velocity.FILE_RESOURCE_LOADER_CACHE, Boolean.FALSE.toString()); velocityProperties.setProperty(Velocity.INPUT_ENCODING, ENCODING_UTF_8); velocityProperties.setProperty(Velocity.OUTPUT_ENCODING, ENCODING_UTF_8); if (!enableLogging) { velocityProperties.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM_CLASS, "org.apache.velocity.runtime.log.NullLogChute"); } String templatePath = templateFile.getParentFile().getAbsolutePath(); velocityProperties.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, templatePath); VelocityEngine velocityEngine = new VelocityEngine(velocityProperties); Template template = velocityEngine.getTemplate(templateFile.getName()); VelocityContext context = new VelocityContext(); context.put("system", System.getProperties()); context.put("input", properties); context.put("project", getProject()); context.put("contributionIteratorSequence", deserializeSequence(contributionIteratorSequence)); context.put("requisitionIteratorSequence", deserializeSequence(requisitionIteratorSequence)); context.put("provisionIteratorSequence", deserializeSequence(provisionIteratorSequence)); context.put("StringUtils", StringUtils.class); context.put("FileUtil", FileUtil.class); context.put("UrlUtils", new UrlUtils()); context.put("xpath", new XPathProvider()); context.put("PropertyUtils", new PropertyUtils()); addConcreteExtensionSequence(DCC_UNIT_CONTRIBUTION_ITERATOR_SEQUENCE_REGEX, context, "ContributionIteratorSequence", properties); addConcreteExtensionSequence(DCC_UNIT_REQUISITION_ITERATOR_SEQUENCE_REGEX, context, "RequisitionIteratorSequence", properties); addConcreteExtensionSequence(DCC_UNIT_PROVISION_ITERATOR_SEQUENCE_REGEX, context, "ProvisionIteratorSequence", properties); targetFile.getParentFile().mkdirs(); try (Writer writer = new OutputStreamWriter(new FileOutputStream(targetFile), ENCODING_UTF_8)) { template.merge(context, writer); } catch (IOException e) { throw new BuildException(e); } } private void addConcreteExtensionSequence(Pattern extensionPattern, VelocityContext velocityContext, String suffix, Properties inputProperties) { final Set<String> existingKeys = new HashSet<>(); for (Enumeration<?> enumeration = inputProperties.propertyNames(); enumeration.hasMoreElements();) { final String key = (String) enumeration.nextElement(); final Matcher matcher = extensionPattern.matcher(key); if (matcher.matches()) { final List<String> sequence = deserializeSequence(inputProperties.getProperty(key)); final String extensionName = matcher.group(1); String variableName = removeIllegalCharactersFromVariableName(extensionName + suffix); if (existingKeys.contains(variableName)) { variableName = generateUniqueName(variableName, existingKeys); } existingKeys.add(variableName); velocityContext.put(variableName, sequence); } else { existingKeys.add(key); } } } private String generateUniqueName(String name, Set<String> existingKeys) { for (int i = 1; i < Integer.MAX_VALUE; i++) { final String newName = name + "_" + i; if (!existingKeys.contains(newName)) { return newName; } } throw new IllegalStateException("Failed to generate unique name : " + name); } private static String removeIllegalCharactersFromVariableName(String variableName) { final char[] charArray = new char[variableName.length()]; boolean toUpperCase = false; int j = 0; for (int i = 0; i < variableName.length(); i++) { final char current = variableName.charAt(i); final boolean isValidLetter = (current >= 'a' && current <= 'z') || (current >= 'A' && current <= 'Z'); final boolean isValidDigit = (current >= '0' && current <= '9'); final boolean isValidSeparator = (current == '-' && current <= '_'); if (!((j == 0 && isValidLetter) || (j != 0 && (isValidLetter || isValidDigit || isValidSeparator)))) { toUpperCase = true; } else if (toUpperCase && !isValidDigit && !isValidSeparator && j != 0) { charArray[j] = Character.toUpperCase(current); toUpperCase = false; j++; } else { charArray[j] = current; j++; } } return new String(charArray, 0, j); } private List<String> deserializeSequence(String iteratorSequence) { if (iteratorSequence == null) { return Collections.emptyList(); } String[] items = iteratorSequence.split(","); List<String> list = new ArrayList<>(); for (int i = 0; i < items.length; i++) { if (items[i] != null && !items[i].trim().isEmpty()) { list.add(items[i].trim()); } } return list; } private <T> T notNull(T parameter, String label) { if (parameter == null) { throw new IllegalArgumentException(label + " property not set"); } return parameter; } public File getPropertyFile() { return propertyFile; } public void setPropertyFile(File propertyFile) { this.propertyFile = propertyFile; } public File getTemplateFile() { return templateFile; } public void setTemplateFile(File templateFile) { this.templateFile = templateFile; } public File getTargetFile() { return targetFile; } public void setTargetFile(File targetFile) { this.targetFile = targetFile; } public boolean isEnableLogging() { return enableLogging; } public void setEnableLogging(boolean enableLogging) { this.enableLogging = enableLogging; } }