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

org.apache.tools.ant.filters.ReplaceTokens Maven / Gradle / Ivy

There is a newer version: 2.0.27
Show newest version
/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You 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
 *
 *      https://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.apache.tools.ant.filters;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.Parameter;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.resources.FileResource;
import org.apache.tools.ant.util.FileUtils;

/**
 * Replaces tokens in the original input with user-supplied values.
 *
 * Example:
 *
 * 
<replacetokens begintoken="#" endtoken="#">
 *   <token key="DATE" value="${TODAY}"/>
 * </replacetokens>
* * Or: * *
<filterreader classname="org.apache.tools.ant.filters.ReplaceTokens">
 *   <param type="tokenchar" name="begintoken" value="#"/>
 *   <param type="tokenchar" name="endtoken" value="#"/>
 *   <param type="token" name="DATE" value="${TODAY}"/>
 * </filterreader>
* */ public final class ReplaceTokens extends BaseParamFilterReader implements ChainableReader { /** Default "begin token" character. */ private static final String DEFAULT_BEGIN_TOKEN = "@"; /** Default "end token" character. */ private static final String DEFAULT_END_TOKEN = "@"; /** Hashtable to holds the original replacee-replacer pairs (String to String). */ private Hashtable hash = new Hashtable<>(); /** This map holds the "resolved" tokens (begin- and end-tokens are added to make searching simpler) */ private final TreeMap resolvedTokens = new TreeMap<>(); private boolean resolvedTokensBuilt = false; /** Used for comparisons and lookup into the resolvedTokens map. */ private String readBuffer = ""; /** replacement test from a token */ private String replaceData = null; /** Index into replacement data */ private int replaceIndex = -1; /** Character marking the beginning of a token. */ private String beginToken = DEFAULT_BEGIN_TOKEN; /** Character marking the end of a token. */ private String endToken = DEFAULT_END_TOKEN; /** * Constructor for "dummy" instances. * * @see BaseFilterReader#BaseFilterReader() */ public ReplaceTokens() { } /** * Creates a new filtered reader. * * @param in A Reader object providing the underlying stream. * Must not be null. */ public ReplaceTokens(final Reader in) { super(in); } /** * Returns the next character in the filtered stream, replacing tokens * from the original stream. * * @return the next character in the resulting stream, or -1 * if the end of the resulting stream has been reached * * @exception IOException if the underlying stream throws an IOException * during reading */ public int read() throws IOException { if (!getInitialized()) { initialize(); setInitialized(true); } if (!resolvedTokensBuilt) { // build the resolved tokens tree map. for (Map.Entry entry : hash.entrySet()) { resolvedTokens.put(beginToken + entry.getKey() + endToken, entry.getValue()); } resolvedTokensBuilt = true; } // are we currently serving replace data? if (replaceData != null) { if (replaceIndex < replaceData.length()) { return replaceData.charAt(replaceIndex++); } else { replaceData = null; } } // is the read buffer empty? if (readBuffer.isEmpty()) { int next = in.read(); if (next == -1) { return next; // end of stream. all buffers empty. } readBuffer += (char) next; } for (;;) { // get the closest tokens SortedMap possibleTokens = resolvedTokens.tailMap(readBuffer); if (possibleTokens.isEmpty() || !possibleTokens.firstKey().startsWith(readBuffer)) { // if there is none, then deliver the first char from the buffer. return getFirstCharacterFromReadBuffer(); } else if (readBuffer.equals(possibleTokens.firstKey())) { // there exists a nearest token - is it an exact match? // we have found a token. prepare the replaceData buffer. replaceData = resolvedTokens.get(readBuffer); replaceIndex = 0; readBuffer = ""; // destroy the readBuffer - it's contents are being replaced entirely. // get the first character via recursive call. return read(); } else { // nearest token is not matching exactly - read one character more. int next = in.read(); if (next != -1) { readBuffer += (char) next; } else { return getFirstCharacterFromReadBuffer(); // end of stream. deliver remaining characters from buffer. } } } } /** * @return the first character from the read buffer or -1 if read buffer is empty. */ private int getFirstCharacterFromReadBuffer() { if (readBuffer.isEmpty()) { return -1; } int chr = readBuffer.charAt(0); readBuffer = readBuffer.substring(1); return chr; } /** * Sets the "begin token" character. * * @param beginToken the character used to denote the beginning of a token */ public void setBeginToken(final String beginToken) { this.beginToken = beginToken; } /** * Returns the "begin token" character. * * @return the character used to denote the beginning of a token */ private String getBeginToken() { return beginToken; } /** * Sets the "end token" character. * * @param endToken the character used to denote the end of a token */ public void setEndToken(final String endToken) { this.endToken = endToken; } /** * Returns the "end token" character. * * @return the character used to denote the end of a token */ private String getEndToken() { return endToken; } /** * A resource containing properties, each of which is interpreted * as a token/value pair. * * @param r Resource * @since Ant 1.8.0 */ public void setPropertiesResource(Resource r) { makeTokensFromProperties(r); } /** * Adds a token element to the map of tokens to replace. * * @param token The token to add to the map of replacements. * Must not be null. */ public void addConfiguredToken(final Token token) { hash.put(token.getKey(), token.getValue()); resolvedTokensBuilt = false; // invalidate to build them again if they have been built already. } /** * Returns properties from a specified properties file. * * @param resource The resource to load properties from. */ private Properties getProperties(Resource resource) { InputStream in = null; Properties props = new Properties(); try { in = resource.getInputStream(); props.load(in); } catch (IOException ioe) { if (getProject() != null) { getProject().log("getProperties failed, " + ioe.getMessage(), Project.MSG_ERR); } else { ioe.printStackTrace(); //NOSONAR } } finally { FileUtils.close(in); } return props; } /** * Sets the map of tokens to replace. * * @param hash A map (String->String) of token keys to replacement * values. Must not be null. */ private void setTokens(final Hashtable hash) { this.hash = hash; } /** * Returns the map of tokens which will be replaced. * * @return a map (String->String) of token keys to replacement * values */ private Hashtable getTokens() { return hash; } /** * Creates a new ReplaceTokens using the passed in * Reader for instantiation. * * @param rdr A Reader object providing the underlying stream. * Must not be null. * * @return a new filter based on this configuration, but filtering * the specified reader */ public Reader chain(final Reader rdr) { ReplaceTokens newFilter = new ReplaceTokens(rdr); newFilter.setBeginToken(getBeginToken()); newFilter.setEndToken(getEndToken()); newFilter.setTokens(getTokens()); newFilter.setInitialized(true); return newFilter; } /** * Initializes tokens and loads the replacee-replacer hashtable. */ private void initialize() { Parameter[] params = getParameters(); if (params != null) { for (Parameter param : params) { if (param != null) { final String type = param.getType(); if ("tokenchar".equals(type)) { final String name = param.getName(); if ("begintoken".equals(name)) { beginToken = param.getValue(); } else if ("endtoken".equals(name)) { endToken = param.getValue(); } } else if ("token".equals(type)) { final String name = param.getName(); final String value = param.getValue(); hash.put(name, value); } else if ("propertiesfile".equals(type)) { makeTokensFromProperties( new FileResource(new File(param.getValue()))); } } } } } private void makeTokensFromProperties(Resource r) { Properties props = getProperties(r); props.stringPropertyNames().forEach(key -> hash.put(key, props.getProperty(key))); } /** * Holds a token */ public static class Token { /** Token key */ private String key; /** Token value */ private String value; /** * Sets the token key * * @param key The key for this token. Must not be null. */ public final void setKey(String key) { this.key = key; } /** * Sets the token value * * @param value The value for this token. Must not be null. */ public final void setValue(String value) { this.value = value; } /** * Returns the key for this token. * * @return the key for this token */ public final String getKey() { return key; } /** * Returns the value for this token. * * @return the value for this token */ public final String getValue() { return value; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy