jdk/src/java.httpclient/share/classes/java/net/http/WSShared.java
changeset 37874 02589df0999a
child 39730 196f4e25d9f5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSShared.java	Mon May 09 23:33:09 2016 +0100
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General  License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General  License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General  License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net.http;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+//
+//  +-----------+---------------+------------ ~ ------+
+//  |  shared#1 |    shared#2   | non-shared          |
+//  +-----------+---------------+------------ ~ ------+
+//  |                                                 |
+//  |<------------------  shared0  ---------- ~ ----->|
+//
+//
+// Objects of the type are not thread-safe. It's the responsibility of the
+// client to access shared buffers safely between threads.
+//
+// It would be perfect if we could extend java.nio.Buffer, but it's not an
+// option since Buffer and all its descendants have package-private
+// constructors.
+//
+abstract class WSShared<T extends Buffer> implements WSDisposable {
+
+    protected final AtomicBoolean disposed = new AtomicBoolean();
+    protected final T buffer;
+
+    protected WSShared(T buffer) {
+        this.buffer = Objects.requireNonNull(buffer);
+    }
+
+    static <T extends Buffer> WSShared<T> wrap(T buffer) {
+        return new WSShared<>(buffer) {
+            @Override
+            WSShared<T> share(int pos, int limit) {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    // TODO: should be a terminal operation as after it returns the buffer might
+    //       have escaped (we can't protect it any more)
+    public T buffer() {
+        checkDisposed();
+        return buffer;
+    }
+
+    abstract WSShared<T> share(final int pos, final int limit);
+
+    WSShared<T> select(final int pos, final int limit) {
+        checkRegion(pos, limit, buffer());
+        select(pos, limit, buffer());
+        return this;
+    }
+
+    @Override
+    public void dispose() {
+        if (!disposed.compareAndSet(false, true)) {
+            throw new IllegalStateException("Has been disposed previously");
+        }
+    }
+
+    int limit() {
+        return buffer().limit();
+    }
+
+    WSShared<T> limit(int newLimit) {
+        buffer().limit(newLimit);
+        return this;
+    }
+
+    int position() {
+        return buffer().position();
+    }
+
+    WSShared<T> position(int newPosition) {
+        buffer().position(newPosition);
+        return this;
+    }
+
+    int remaining() {
+        return buffer().remaining();
+    }
+
+    boolean hasRemaining() {
+        return buffer().hasRemaining();
+    }
+
+    WSShared<T> flip() {
+        buffer().flip();
+        return this;
+    }
+
+    WSShared<T> rewind() {
+        buffer().rewind();
+        return this;
+    }
+
+    WSShared<T> put(WSShared<? extends T> src) {
+        put(this.buffer(), src.buffer());
+        return this;
+    }
+
+    static void checkRegion(int position, int limit, Buffer buffer) {
+        if (position < 0 || position > buffer.capacity()) {
+            throw new IllegalArgumentException("position: " + position);
+        }
+        if (limit < 0 || limit > buffer.capacity()) {
+            throw new IllegalArgumentException("limit: " + limit);
+        }
+        if (limit < position) {
+            throw new IllegalArgumentException
+                    ("limit < position: limit=" + limit + ", position=" + position);
+        }
+    }
+
+    void select(int newPos, int newLim, Buffer buffer) {
+        int oldPos = buffer.position();
+        int oldLim = buffer.limit();
+        assert 0 <= oldPos && oldPos <= oldLim && oldLim <= buffer.capacity();
+        if (oldLim <= newPos) {
+            buffer().limit(newLim).position(newPos);
+        } else {
+            buffer.position(newPos).limit(newLim);
+        }
+    }
+
+    // The same as dst.put(src)
+    static <T extends Buffer> T put(T dst, T src) {
+        if (dst instanceof ByteBuffer) {
+            ((ByteBuffer) dst).put((ByteBuffer) src);
+        } else if (dst instanceof CharBuffer) {
+            ((CharBuffer) dst).put((CharBuffer) src);
+        } else {
+            // We don't work with buffers of other types
+            throw new IllegalArgumentException();
+        }
+        return dst;
+    }
+
+    // TODO: Remove when JDK-8150785 has been done
+    @SuppressWarnings("unchecked")
+    static <T extends Buffer> T slice(T buffer) {
+        if (buffer instanceof ByteBuffer) {
+            return (T) ((ByteBuffer) buffer).slice();
+        } else if (buffer instanceof CharBuffer) {
+            return (T) ((CharBuffer) buffer).slice();
+        } else {
+            // We don't work with buffers of other types
+            throw new IllegalArgumentException();
+        }
+    }
+
+    // TODO: Remove when JDK-8150785 has been done
+    @SuppressWarnings("unchecked")
+    static <T extends Buffer> T duplicate(T buffer) {
+        if (buffer instanceof ByteBuffer) {
+            return (T) ((ByteBuffer) buffer).duplicate();
+        } else if (buffer instanceof CharBuffer) {
+            return (T) ((CharBuffer) buffer).duplicate();
+        } else {
+            // We don't work with buffers of other types
+            throw new IllegalArgumentException();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + "[" + WSUtils.toString(buffer()) + "]";
+    }
+
+    private void checkDisposed() {
+        if (disposed.get()) {
+            throw new IllegalStateException("Has been disposed previously");
+        }
+    }
+}