# HG changeset patch # User Jaroslav Tulach # Date 1213429986 -7200 # Node ID 4db7ceebd2b33ac27bbbb049358aeb4908187dc3 # Parent 7b26c64804c2a7376a26fa324cd4ff2b782c9146 Nonsubclassable Writer example diff -r 7b26c64804c2 -r 4db7ceebd2b3 samples/delegatingwriterfinal/build.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/delegatingwriterfinal/build.xml Sat Jun 14 09:53:06 2008 +0200 @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 7b26c64804c2 -r 4db7ceebd2b3 samples/delegatingwriterfinal/nbproject/project.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/delegatingwriterfinal/nbproject/project.xml Sat Jun 14 09:53:06 2008 +0200 @@ -0,0 +1,89 @@ + + + org.netbeans.modules.ant.freeform + + + delegatingwriterfinal + + + + delegatingwriterfinal + + + + + java + src-api1.0 + UTF-8 + + + + java + src-api2.0 + UTF-8 + + + + java + src-test + UTF-8 + + + + + build + + + clean + + + test + + + clean + build + + + + + + + src-api1.0 + + + + src-api2.0 + + + + src-test + + + build.xml + + + + + + + + + + + + + src-api1.0 + 1.5 + + + src-api2.0 + 1.5 + + + src-test + src-api1.0:../libs/dist/junit-4.4.jar + 1.5 + + + + diff -r 7b26c64804c2 -r 4db7ceebd2b3 samples/delegatingwriterfinal/src-api1.0/api/Writer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/delegatingwriterfinal/src-api1.0/api/Writer.java Sat Jun 14 09:53:06 2008 +0200 @@ -0,0 +1,96 @@ +package api; + +import java.io.BufferedWriter; +import java.io.IOException; + +/** Fixing the problem caused by mixing subclassing and delegation in + * the java.io.BufferedWriter + * + * @author Jaroslav Tulach + */ +public final class Writer { + private final Impl impl; + + private Writer(Impl impl) { + this.impl = impl; + } + public final void write(int c) throws IOException { + char[] arr = { (char)c }; + impl.write(arr, 0, 1); + } + + public final void write(char cbuf[]) throws IOException { + impl.write(cbuf, 0, cbuf.length); + } + public final void write(char cbuf[], int off, int len) throws IOException { + impl.write(cbuf, off, len); + } + public final void write(String str) throws IOException { + impl.write(str, 0, str.length()); + } + public final void write(String str, int off, int len) throws IOException { + impl.write(str, off, len); + } + public final void flush() throws IOException { + impl.flush(); + } + public final void close() throws IOException { + impl.close(); + } + + public static Writer create(Impl impl) { + return new Writer(impl); + } + + public static Writer create(final java.io.Writer w) { + return new Writer(new Impl() { + public void write(String str, int off, int len) throws IOException { + w.write(str, off, len); + } + + public void write(char[] arr, int off, int len) throws IOException { + w.write(arr, off, len); + } + + public void close() throws IOException { + w.close(); + } + + public void flush() throws IOException { + w.flush(); + } + }); + } + + public static Writer createBuffered(final Writer out) { + class Delegate extends java.io.Writer { + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + out.write(cbuf, off, len); + } + + @Override + public void flush() throws IOException { + out.flush(); + } + + @Override + public void close() throws IOException { + out.close(); + } + + } + return create(new BufferedWriter(new Delegate())); + } + + + public static interface Impl { + public void close() throws IOException; + public void flush() throws IOException; + public void write(String str, int off, int len) throws IOException; + public void write(char[] arr, int off, int len) throws IOException; + } + + + +} diff -r 7b26c64804c2 -r 4db7ceebd2b3 samples/delegatingwriterfinal/src-api2.0/api/CharSeq.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/delegatingwriterfinal/src-api2.0/api/CharSeq.java Sat Jun 14 09:53:06 2008 +0200 @@ -0,0 +1,56 @@ +package api; + +/** + * + * @author Jaroslav Tulach + */ +final class CharSeq implements CharSequence { + final char[] arr; + final int off; + final int len; + final int c; + + public CharSeq(int c) { + this.arr = null; + this.off = 0; + this.len = 1; + this.c = c; + } + + public CharSeq(char[] arr, int off, int len) { + this.arr = arr; + this.off = off; + this.len = len; + this.c = -1; + } + + public int length() { + return arr == null ? 1 : len; + } + + public char charAt(int index) { + if (index < 0) { + throw new IndexOutOfBoundsException(); + } + if (arr == null) { + if (index > 0) { + throw new IndexOutOfBoundsException(); + } + return (char)c; + } else { + if (index >= len) { + throw new IndexOutOfBoundsException(); + } + return arr[off + index]; + } + } + + public CharSequence subSequence(int start, int end) { + if (end >= this.len) { + throw new IndexOutOfBoundsException(); + } + char[] array = arr == null ? new char[]{ (char)c } : arr; + return new CharSeq(array, off + start, off + end); + } + +} diff -r 7b26c64804c2 -r 4db7ceebd2b3 samples/delegatingwriterfinal/src-api2.0/api/Writer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/delegatingwriterfinal/src-api2.0/api/Writer.java Sat Jun 14 09:53:06 2008 +0200 @@ -0,0 +1,41 @@ +package api; + +import java.io.IOException; + +/** Fixing the problem caused by mixing subclassing and delegation in + * the java.io.BufferedWriter + * + * @author Jaroslav Tulach + */ +public final class Writer { + private final Impl impl; + + private Writer(Impl impl) { + this.impl = impl; + } + public final void write(int c) throws IOException { + impl.write(new CharSeq(c)); + } + + public final void write(char cbuf[]) throws IOException { + impl.write(new CharSeq(cbuf, 0, cbuf.length)); + } + public final void write(char cbuf[], int off, int len) throws IOException { + impl.write(new CharSeq(cbuf, off, len)); + } + public final void write(String str) throws IOException { + impl.write(str); + } + public final void write(String str, int off, int len) throws IOException { + impl.write(str.subSequence(off, off + len)); + } + + + + public static interface Impl { + public void write(CharSequence seq) throws IOException; + } + + + +} diff -r 7b26c64804c2 -r 4db7ceebd2b3 samples/delegatingwriterfinal/src-test/api/usage/BufferedWriterCryptoTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/delegatingwriterfinal/src-test/api/usage/BufferedWriterCryptoTest.java Sat Jun 14 09:53:06 2008 +0200 @@ -0,0 +1,37 @@ + +package api.usage; + +import api.Writer; +import java.io.IOException; +import java.io.StringWriter; +import java.io.StringWriter; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + +/** Converting the Crypto example to the APIs that split client and provider + * concerns and do not mix delegation and subclassing. + * + * @author Jaroslav Tulach + */ +public class BufferedWriterCryptoTest { + private StringWriter writer; + + + public BufferedWriterCryptoTest() { + } + + @Before + public void setUp() { + writer = new StringWriter(); + } + + @Test + public void testBehaviourOfRealBufferInJDKWorksFine() throws IOException { + Writer bufferedWriter = CryptoWriter.create(Writer.create(writer)); + bufferedWriter.write("VMS"); + bufferedWriter.flush(); + assertEquals("Converted", "WNT", writer.toString()); + } + +} \ No newline at end of file diff -r 7b26c64804c2 -r 4db7ceebd2b3 samples/delegatingwriterfinal/src-test/api/usage/CryptoWriter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/delegatingwriterfinal/src-test/api/usage/CryptoWriter.java Sat Jun 14 09:53:06 2008 +0200 @@ -0,0 +1,60 @@ + +package api.usage; + +import api.Writer; +import java.io.IOException; + + +/** Writer alters each char from 'A' to 'Z' range with next one just like + * old Romans did. + * + * @author Jaroslav Tulach + */ +public class CryptoWriter implements Writer.Impl { + private Writer out; + + private CryptoWriter(Writer out) { + this.out = out; + } + + + public static Writer create(Writer out) { + return Writer.create(new CryptoWriter(out)); + } + + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + char[] arr = new char[len]; + for (int i = 0; i < len; i++) { + arr[i] = convertChar(cbuf[off + i]); + } + out.write(arr, 0, len); + } + + @Override + public void write(String str, int off, int len) throws IOException { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < len; i++) { + sb.append(convertChar(str.charAt(off + i))); + } + out.write(sb.toString(), 0, len); + } + + private char convertChar(int c) { + if (c == 'Z') { + return 'A'; + } + if (c == 'z') { + return 'a'; + } + return (char)(c + 1); + } + + public void close() throws IOException { + out.close(); + } + + public void flush() throws IOException { + out.flush(); + } +}