--- /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");
+ }
+ }
+}