// // Thanks to Jakob Jenkov for his tutorial at // http://tutorials.jenkov.com/java-howto/replace-strings-in-streams-arrays-files.html // package name.abuchen.portfolio.util; import java.io.IOException; import java.io.PushbackReader; import java.io.Reader; public class TokenReplacingReader extends Reader { public interface ITokenResolver { public String resolveToken(String tokenName); } protected PushbackReader pushbackReader = null; protected ITokenResolver tokenResolver = null; protected StringBuilder tokenNameBuffer = new StringBuilder(); protected String tokenValue = null; protected int tokenValueIndex = 0; public TokenReplacingReader(Reader source, ITokenResolver resolver) { this.pushbackReader = new PushbackReader(source, 2); this.tokenResolver = resolver; } @Override public int read() throws IOException { if (this.tokenValue != null) { if (this.tokenValueIndex < this.tokenValue.length()) return this.tokenValue.charAt(this.tokenValueIndex++); if (this.tokenValueIndex == this.tokenValue.length()) { this.tokenValue = null; this.tokenValueIndex = 0; } } int data = this.pushbackReader.read(); if (data != '$') return data; data = this.pushbackReader.read(); if (data != '{') { this.pushbackReader.unread(data); return '$'; } this.tokenNameBuffer.delete(0, this.tokenNameBuffer.length()); data = this.pushbackReader.read(); while (data != '}') { this.tokenNameBuffer.append((char) data); data = this.pushbackReader.read(); } this.tokenValue = this.tokenResolver.resolveToken(this.tokenNameBuffer.toString()); if (this.tokenValue == null) this.tokenValue = "${" + this.tokenNameBuffer.toString() + "}"; //$NON-NLS-1$ //$NON-NLS-2$ if (this.tokenValue.length() == 0) return read(); return this.tokenValue.charAt(this.tokenValueIndex++); } @Override public int read(char cbuf[]) throws IOException { return read(cbuf, 0, cbuf.length); } @Override public int read(char cbuf[], int off, int len) throws IOException { int charsRead = 0; for (int i = 0; i < len; i++) { int nextChar = read(); if (nextChar == -1) { if (charsRead == 0) { charsRead = -1; } break; } charsRead = i + 1; cbuf[off + i] = (char) nextChar; } return charsRead; } @Override public void close() throws IOException { this.pushbackReader.close(); } @Override public long skip(long n) throws IOException { throw new UnsupportedOperationException(); } @Override public boolean ready() throws IOException { return this.pushbackReader.ready(); } @Override public boolean markSupported() { return false; } @Override public void mark(int readAheadLimit) throws IOException { throw new UnsupportedOperationException(); } @Override public void reset() throws IOException { throw new UnsupportedOperationException(); } }