blob: b8e1b44e8837b49a9c0bb842bebfbe1bc76c0f77 [file] [log] [blame]
/*
* 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
*
* 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.apache.servicemix.maven.plugin.res;
import java.io.FilterReader;
import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
import java.util.Map;
/**
*/
public class InterpolationFilterReader extends FilterReader {
/** replacement text from a token */
private String replaceData;
/** Index into replacement data */
private int replaceIndex = -1;
/** Hashtable to hold the replacee-replacer pairs (String to String). */
private Map variables = new HashMap();
/** Character marking the beginning of a token. */
private String beginToken;
/** Character marking the end of a token. */
private String endToken;
/** Length of begin token. */
private int beginTokenLength;
/** Length of end token. */
private int endTokenLength;
public InterpolationFilterReader(Reader in, Map variables, String beginToken, String endToken) {
super(in);
this.variables = variables;
this.beginToken = beginToken;
this.endToken = endToken;
beginTokenLength = beginToken.length();
endTokenLength = endToken.length();
}
/**
* Skips characters. This method will block until some characters are
* available, an I/O error occurs, or the end of the stream is reached.
*
* @param n The number of characters to skip
*
* @return the number of characters actually skipped
*
* @exception IllegalArgumentException If <code>n</code> is negative.
* @exception IOException If an I/O error occurs
*/
public long skip(long n) throws IOException {
if (n < 0L) {
throw new IllegalArgumentException("skip value is negative");
}
for (long i = 0; i < n; i++) {
if (read() == -1) {
return i;
}
}
return n;
}
/**
* Reads characters into a portion of an array. This method will block
* until some input is available, an I/O error occurs, or the end of the
* stream is reached.
*
* @param cbuf Destination buffer to write characters to.
* Must not be <code>null</code>.
* @param off Offset at which to start storing characters.
* @param len Maximum number of characters to read.
*
* @return the number of characters read, or -1 if the end of the
* stream has been reached
*
* @exception IOException If an I/O error occurs
*/
public int read(char cbuf[], int off, int len) throws IOException {
for (int i = 0; i < len; i++) {
int ch = read();
if (ch == -1) {
if (i == 0) {
return -1;
} else {
return i;
}
}
cbuf[off + i] = (char)ch;
}
return len;
}
/**
* 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 (replaceIndex != -1) {
int ch = replaceData.charAt(replaceIndex++);
if (replaceIndex >= replaceData.length()) {
replaceIndex = -1;
}
return ch;
}
int ch = in.read();
if (ch == beginToken.charAt(0)) {
StringBuffer key = new StringBuffer();
int beginTokenMatchPos = 1;
do {
ch = in.read();
if (ch != -1) {
key.append((char)ch);
if ((beginTokenMatchPos < beginTokenLength)
&& (ch != beginToken.charAt(beginTokenMatchPos++))) {
ch = -1; // not really EOF but to trigger code below
break;
}
} else {
break;
}
} while (ch != endToken.charAt(0));
// now test endToken
if (ch != -1 && endTokenLength > 1) {
int endTokenMatchPos = 1;
do {
ch = in.read();
if (ch != -1) {
key.append((char)ch);
if (ch != endToken.charAt(endTokenMatchPos++)) {
ch = -1; // not really EOF but to trigger code below
break;
}
} else {
break;
}
} while (endTokenMatchPos < endTokenLength);
}
// There is nothing left to read so we have the situation where the begin/end token
// are in fact the same and as there is nothing left to read we have got ourselves
// end of a token boundary so let it pass through.
if (ch == -1) {
replaceData = key.toString();
replaceIndex = 0;
return beginToken.charAt(0);
}
String variableKey = key.substring(beginTokenLength - 1, key.length() - endTokenLength);
Object o = variables.get(variableKey);
if (o != null) {
String value = o.toString();
if (value.length() != 0) {
replaceData = value;
replaceIndex = 0;
}
return read();
} else {
replaceData = key.toString();
replaceIndex = 0;
return beginToken.charAt(0);
}
}
return ch;
}
}