001: /* Copyright 2001 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal.utils;
007:
008: import java.io.IOException;
009: import java.io.Writer;
010:
011: /**
012: * Performs substitution operation on a stream of integer write requests.
013: *
014: * 7/25/05 - UP-1180 - dmindler@rutgers.edu
015: * Modified to utilize characters instead of integers. Main reason is
016: * that actual writing was delegated to the WriteableWriterWrapper class,
017: * who had a statement:
018: * <code>
019: * cbuf[j++]=(char)ibuf[i];
020: * </code>
021: * in effect, converting an integer to a character. This was an expensive
022: * transformation since all data was copied into an int[] then a char[] was
023: * allocated in the WriteableWriterWrapper class to which all data was
024: * copied (as shown above):
025: * <code>
026: * char[] cbuf = new char[len-off];
027: * </code>
028: * Note: This class name was not changed.
029: *
030: * @author Peter Kharchenko {@link <a href="mailto:pkharchenko@interactivebusiness.com"">pkharchenko@interactivebusiness.com"</a>}
031: * @version $Revision: 36690 $
032: */
033: public class SubstitutionIntegerFilter {
034: private final static int DEFAULT_BUFFER_SIZE = 2048;
035: final Writer out;
036:
037: final char[] substitute;
038: final char[] target;
039: private int matchindex;
040: private char[] buffer;
041: private int bufferindex;
042: private int maxBuffer = DEFAULT_BUFFER_SIZE;
043:
044: /**
045: * Creates a new <code>SubstitutionIntegerFilter</code> instance.
046: *
047: * @param out an <code>IWriteable</code> object value
048: * @param target an <code>int[]</code> pattern to be replaced
049: * @param substitute an <code>int[]</code> pattern to replace the original
050: */
051: public SubstitutionIntegerFilter(Writer out, char[] target,
052: char[] substitute) {
053: this .out = out;
054: this .substitute = substitute;
055: this .target = target;
056: this .matchindex = 0;
057: this .bufferindex = 0;
058: this .buffer = new char[maxBuffer + target.length];
059: }
060:
061: /**
062: * Creates a new <code>SubstitutionIntegerFilter</code> instance.
063: *
064: * @param out an <code>IWriteable</code> object value
065: * @param target an <code>int[]</code> pattern to be replaced
066: * @param substitute an <code>int[]</code> pattern to replace the original
067: * @param bufferSize a buffer size
068: */
069: public SubstitutionIntegerFilter(Writer out, char[] target,
070: char[] substitute, int bufferSize) {
071: this .out = out;
072: this .substitute = substitute;
073: this .target = target;
074: this .matchindex = 0;
075: this .bufferindex = 0;
076: this .maxBuffer = bufferSize - target.length;
077: this .buffer = new char[maxBuffer + target.length];
078: }
079:
080: public void write(char number) throws IOException {
081: if (number == target[matchindex]) {
082: if (matchindex < target.length - 1) {
083: // assume match will fail, but track buffered ints
084: addToBuffer(number);
085: matchindex++;
086: } else {
087: // we have a match, roll back buffer and add substitute
088: bufferindex = bufferindex - matchindex;
089: matchindex = 0;
090: for (int x = 0; x < substitute.length; x++) {
091: addToBuffer(substitute[x]);
092: }
093: }
094: } else {
095: matchindex = 0;
096: addToBuffer(number);
097: }
098: }
099:
100: public void flush() throws IOException {
101: // do internal flush
102: out.write(buffer, 0, bufferindex);
103: bufferindex = 0;
104: out.flush();
105: }
106:
107: public void close() throws IOException {
108: this .flush();
109: out.close();
110: }
111:
112: protected void addToBuffer(char i) throws IOException {
113: // flush if buffer fills up, but only if we're not tracking a possible substitution
114: if ((bufferindex > (maxBuffer - 2)) && matchindex == 0) {
115: flush();
116: }
117: buffer[bufferindex++] = i;
118: }
119:
120: }
|