add experimental Fountain.DatabaseColumn
[org.ibex.io.git] / src / org / ibex / io / Fountain.java
index ddf66e4..849544f 100644 (file)
@@ -31,6 +31,16 @@ public interface Fountain {
         private final byte[] bytes;
         private final int off;
         private final int len;
+        protected ByteArray(String s) {
+            try {
+                byte[] bytes = s.getBytes("UTF-8");
+                this.bytes = bytes;
+                this.off = 0;
+                this.len = bytes.length;
+            } catch (UnsupportedEncodingException e) {
+                throw new RuntimeException(e);
+            }
+        }
         public ByteArray(byte[] bytes)                   { this(bytes, 0, bytes.length); }
         public ByteArray(byte[] bytes, int off, int len) { this.bytes = bytes; this.off=off; this.len=len; }
         public Stream getStream()                        { return new Stream(bytes, off, len); }
@@ -38,23 +48,111 @@ public interface Fountain {
         public int getNumLines()                         { return Stream.countLines(getStream()); } 
     }
 
-    public static class StringFountain implements Fountain {
-        String s;
-        public StringFountain(String s)                  { this.s = s; }
-        public Stream getStream()                        { return new Stream(s); }
-        public int getLength()                           { return s.length(); }   // FIXME ENCODING ISSUES!!!!!
-        public int getNumLines()                         { return Stream.countLines(getStream()); } 
+
+    public static class StringFountain extends ByteArray {
+        public StringFountain(String s)                  { super(s); }
     }
 
     public static class Concatenate implements Fountain {
-        Fountain f1, f2;
-        public Concatenate(Fountain f1, Fountain f2)     { this.f1 = f1; this.f2 = f2; }
-        public Stream getStream()                        { return f1.getStream().appendStream(f2.getStream()); }
-        public int getLength()                           { return f1.getLength()+f2.getLength(); }
-        public int getNumLines()                         { return f1.getNumLines()+f2.getNumLines(); }
+        private Fountain[] founts;
+        public Concatenate(Fountain f1, Fountain f2)     { this(new Fountain[] { f1, f2 }); }
+        public Concatenate(Fountain[] f)                 { this.founts = f; }
+        public Stream getStream() {
+            Stream ret = null;
+            for(int i=founts.length-1; i>=0; i--)
+                ret = ret==null ? founts[i].getStream() : founts[i].getStream().appendStream(ret);
+            return ret;
+        }
+        public long getLength() {
+            long ret = 0;
+            for(int i=0; i<founts.length; i++)
+                ret += founts[i].getLength();
+            return ret;
+        }
+        public int getNumLines() {
+            int ret = 0;
+            for(int i=0; i<founts.length; i++)
+                ret += founts[i].getNumLines();
+            return ret;
+        }
     }
 
+    // FIXME: untested
+    // note: only one ResultSet is allowed per Statement
+    public static class DatabaseColumn implements Fountain {
+        private ResultSet rs;
+        private int row;
+        private int column;
+        public DatabaseColumn(ResultSet rs, int column) throws SQLException {
+            this(rs, column, rs.getRow());
+        }
+        public DatabaseColumn(ResultSet rs, int column, int row) throws SQLException {
+            this.rs = rs;
+            this.row = row;
+            this.column = column;
+            synchronized(rs) {
+                int type = rs.getType();
+                if ((type | ResultSet.TYPE_SCROLL_INSENSITIVE) == 0)
+                    throw new RuntimeException("Fountain.DatabaseColumn(ResultSet,int) requires a SCROLL_INSENSITIVE ResultSet");
+                if ((type | ResultSet.TYPE_FORWARD_ONLY) != 0)
+                    throw new RuntimeException("Fountain.DatabaseColumn(ResultSet,int) cannot use TYPE_FORWARD_ONLY ResultSets");
+            }
+            // FIXME: do we want to check HOLD_CURSORS_OVER_COMMIT ?
+        }
+        private Blob getBlob() throws SQLException {
+            synchronized(rs) {
+                if (!rs.absolute(row))
+                    throw new RuntimeException("resultset was unable to move to desired row");
+                return rs.getBlob(column);
+            }
+        }
+        public Stream getStream() {
+            try {
+                synchronized(rs) {
+                    return new Stream(rs.getBinaryStream(column));
+                }
+            } catch (SQLException e) { throw new RuntimeException(e); }
+        }
+        public long getLength() {
+            try {
+                synchronized(rs) {
+                    return getBlob().length();
+                }
+            } catch (SQLException e) { throw new RuntimeException(e); }
+        }
+        public int getNumLines()       { 
+            throw new RuntimeException("not implemented");
+        } 
+    }
+
+
     //public static class LazyCachingStreamFountain implements Fountain {
     //}
 
+    /*
+    public static interface Transformer {
+        public Fountain transform(Fountain in);
+
+        public static class Lift implements Fountain.Transformer {
+            private final Stream.Transformer func;
+            public Lift(Stream.Transformer func) { this.func = func; }
+            public Fountain transform(final Fountain in) {
+                return new Fountain() {
+                        public Stream getStream() {
+                            return func.transform(in.getStream()); } };
+            }
+        }
+    }
+    */
+
+    public static class Util {
+        public static Fountain create(String s) { return new StringFountain(s); }
+        public static Fountain concat(Fountain[] f) { return new Concatenate(f); }
+        public static Fountain concat(Fountain f1, Fountain f2) {
+            return new Concatenate(f1, f2);
+        }
+        public static Fountain concat(Fountain f1, Fountain f2, Fountain f3) {
+            return new Concatenate(f1, new Concatenate(f2, f3));
+        }
+    }
 }