You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2017/06/29 22:41:39 UTC

logging-log4j2 git commit: Rename private ivar.

Repository: logging-log4j2
Updated Branches:
  refs/heads/master 73d17a99e -> d41054232


Rename private ivar.

Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/d4105423
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/d4105423
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/d4105423

Branch: refs/heads/master
Commit: d41054232aaeb0cdf3d04aa6f39cc9cb878e06a4
Parents: 73d17a9
Author: Gary Gregory <gg...@apache.org>
Authored: Thu Jun 29 15:41:37 2017 -0700
Committer: Gary Gregory <gg...@apache.org>
Committed: Thu Jun 29 15:41:37 2017 -0700

----------------------------------------------------------------------
 .../core/appender/OutputStreamManager.java      | 728 +++++++++----------
 1 file changed, 364 insertions(+), 364 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d4105423/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
index 60d63a7..55e51e4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
@@ -1,364 +1,364 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.core.appender;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.Serializable;
-import java.nio.ByteBuffer;
-import java.util.Objects;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.logging.log4j.core.Layout;
-import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.layout.ByteBufferDestination;
-import org.apache.logging.log4j.core.layout.ByteBufferDestinationHelper;
-import org.apache.logging.log4j.core.util.Constants;
-
-/**
- * Manages an OutputStream so that it can be shared by multiple Appenders and will
- * allow appenders to reconfigure without requiring a new stream.
- */
-public class OutputStreamManager extends AbstractManager implements ByteBufferDestination {
-    protected final Layout<?> layout;
-    protected ByteBuffer byteBuffer;
-    private volatile OutputStream os;
-    private boolean skipFooter;
-
-    protected OutputStreamManager(final OutputStream os, final String streamName, final Layout<?> layout,
-            final boolean writeHeader) {
-        // Can't use new ctor because it throws an exception
-        this(os, streamName, layout, writeHeader, Constants.ENCODER_BYTE_BUFFER_SIZE);
-    }
-
-    protected OutputStreamManager(final OutputStream os, final String streamName, final Layout<?> layout,
-            final boolean writeHeader, final int bufferSize) {
-        // Can't use new ctor because it throws an exception
-        this(os, streamName, layout, writeHeader, ByteBuffer.wrap(new byte[bufferSize]));
-    }
-
-    /**
-     * @since 2.6
-     * @deprecated
-     */
-    @Deprecated
-    protected OutputStreamManager(final OutputStream os, final String streamName, final Layout<?> layout,
-            final boolean writeHeader, final ByteBuffer byteBuffer) {
-        super(null, streamName);
-        this.os = os;
-        this.layout = layout;
-        if (writeHeader && layout != null) {
-            final byte[] header = layout.getHeader();
-            if (header != null) {
-                try {
-                    getOutputStream().write(header, 0, header.length);
-                } catch (final IOException e) {
-                    logError("Unable to write header", e);
-                }
-            }
-        }
-        this.byteBuffer = Objects.requireNonNull(byteBuffer, "byteBuffer");
-    }
-
-    /**
-     * @since 2.7
-     */
-    protected OutputStreamManager(final LoggerContext loggerContext, final OutputStream os, final String streamName,
-            final boolean createOnDemand, final Layout<? extends Serializable> layout, final boolean writeHeader,
-            final ByteBuffer byteBuffer) {
-        super(loggerContext, streamName);
-        if (createOnDemand && os != null) {
-            LOGGER.error(
-                    "Invalid OutputStreamManager configuration for '{}': You cannot both set the OutputStream and request on-demand.",
-                    streamName);
-        }
-        this.layout = layout;
-        this.byteBuffer = Objects.requireNonNull(byteBuffer, "byteBuffer");
-        this.os = os;
-        if (writeHeader && layout != null) {
-            final byte[] header = layout.getHeader();
-            if (header != null) {
-                try {
-                    getOutputStream().write(header, 0, header.length);
-                } catch (final IOException e) {
-                    logError("Unable to write header for " + streamName, e);
-                }
-            }
-        }
-    }
-
-    /**
-     * Creates a Manager.
-     *
-     * @param name The name of the stream to manage.
-     * @param data The data to pass to the Manager.
-     * @param factory The factory to use to create the Manager.
-     * @param <T> The type of the OutputStreamManager.
-     * @return An OutputStreamManager.
-     */
-    public static <T> OutputStreamManager getManager(final String name, final T data,
-                                                 final ManagerFactory<? extends OutputStreamManager, T> factory) {
-        return AbstractManager.getManager(name, factory, data);
-    }
-
-    @SuppressWarnings("unused")
-    protected OutputStream createOutputStream() throws IOException {
-        throw new IllegalStateException(getClass().getCanonicalName() + " must implement createOutputStream()");
-    }
-
-    /**
-     * Indicate whether the footer should be skipped or not.
-     * @param skipFooter true if the footer should be skipped.
-     */
-    public void skipFooter(final boolean skipFooter) {
-        this.skipFooter = skipFooter;
-    }
-
-    /**
-     * Default hook to write footer during close.
-     */
-    @Override
-    public boolean releaseSub(final long timeout, final TimeUnit timeUnit) {
-        writeFooter();
-        return closeOutputStream();
-    }
-
-    /**
-     * Writes the footer.
-     */
-    protected void writeFooter() {
-        if (layout == null || skipFooter) {
-            return;
-        }
-        final byte[] footer = layout.getFooter();
-        if (footer != null) {
-            write(footer);
-        }
-    }
-
-    /**
-     * Returns the status of the stream.
-     * @return true if the stream is open, false if it is not.
-     */
-    public boolean isOpen() {
-        return getCount() > 0;
-    }
-
-    public boolean hasOutputStream() {
-        return os != null;
-    }
-
-    protected OutputStream getOutputStream() throws IOException {
-        if (os == null) {
-            os = createOutputStream();
-        }
-        return os;
-    }
-
-    protected void setOutputStream(final OutputStream os) {
-        final byte[] header = layout.getHeader();
-        if (header != null) {
-            try {
-                os.write(header, 0, header.length);
-                this.os = os; // only update field if os.write() succeeded
-            } catch (final IOException ioe) {
-                logError("Unable to write header", ioe);
-            }
-        } else {
-            this.os = os;
-        }
-    }
-
-    /**
-     * Some output streams synchronize writes while others do not.
-     * @param bytes The serialized Log event.
-     * @throws AppenderLoggingException if an error occurs.
-     */
-    protected void write(final byte[] bytes)  {
-        write(bytes, 0, bytes.length, false);
-    }
-
-    /**
-     * Some output streams synchronize writes while others do not.
-     * @param bytes The serialized Log event.
-     * @param immediateFlush If true, flushes after writing.
-     * @throws AppenderLoggingException if an error occurs.
-     */
-    protected void write(final byte[] bytes, final boolean immediateFlush)  {
-        write(bytes, 0, bytes.length, immediateFlush);
-    }
-
-    @Override
-    public void writeBytes(final byte[] data, final int offset, final int length) {
-        write(data, offset, length, false);
-    }
-
-    /**
-     * Some output streams synchronize writes while others do not. Synchronizing here insures that
-     * log events won't be intertwined.
-     * @param bytes The serialized Log event.
-     * @param offset The offset into the byte array.
-     * @param length The number of bytes to write.
-     * @throws AppenderLoggingException if an error occurs.
-     */
-    protected void write(final byte[] bytes, final int offset, final int length) {
-        writeBytes(bytes, offset, length);
-    }
-
-    /**
-     * Some output streams synchronize writes while others do not. Synchronizing here insures that
-     * log events won't be intertwined.
-     * @param bytes The serialized Log event.
-     * @param offset The offset into the byte array.
-     * @param length The number of bytes to write.
-     * @param immediateFlush flushes immediately after writing.
-     * @throws AppenderLoggingException if an error occurs.
-     */
-    protected synchronized void write(final byte[] bytes, final int offset, final int length, final boolean immediateFlush) {
-        if (immediateFlush && byteBuffer.position() == 0) {
-            writeToDestination(bytes, offset, length);
-            flushDestination();
-            return;
-        }
-        if (length >= byteBuffer.capacity()) {
-            // if request length exceeds buffer capacity, flush the buffer and write the data directly
-            flush();
-            writeToDestination(bytes, offset, length);
-        } else {
-            if (length > byteBuffer.remaining()) {
-                flush();
-            }
-            byteBuffer.put(bytes, offset, length);
-        }
-        if (immediateFlush) {
-            flush();
-        }
-    }
-
-    /**
-     * Writes the specified section of the specified byte array to the stream.
-     *
-     * @param bytes the array containing data
-     * @param offset from where to write
-     * @param length how many bytes to write
-     * @since 2.6
-     */
-    protected synchronized void writeToDestination(final byte[] bytes, final int offset, final int length) {
-        try {
-            getOutputStream().write(bytes, offset, length);
-        } catch (final IOException ex) {
-            throw new AppenderLoggingException("Error writing to stream " + getName(), ex);
-        }
-    }
-
-    /**
-     * Calls {@code flush()} on the underlying output stream.
-     * @since 2.6
-     */
-    protected synchronized void flushDestination() {
-        final OutputStream stream = os; // access volatile field only once per method
-        if (stream != null) {
-            try {
-                stream.flush();
-            } catch (final IOException ex) {
-                throw new AppenderLoggingException("Error flushing stream " + getName(), ex);
-            }
-        }
-    }
-
-    /**
-     * Drains the ByteBufferDestination's buffer into the destination. By default this calls
-     * {@link OutputStreamManager#write(byte[], int, int, boolean)} with the buffer contents.
-     * The underlying stream is not {@linkplain OutputStream#flush() flushed}.
-     *
-     * @see #flushDestination()
-     * @since 2.6
-     */
-    protected synchronized void flushBuffer(final ByteBuffer buf) {
-        buf.flip();
-        if (buf.remaining() > 0) {
-            writeToDestination(buf.array(), buf.arrayOffset() + buf.position(), buf.remaining());
-        }
-        buf.clear();
-    }
-
-    /**
-     * Flushes any buffers.
-     */
-    public synchronized void flush() {
-        flushBuffer(byteBuffer);
-        flushDestination();
-    }
-
-    protected synchronized boolean closeOutputStream() {
-        flush();
-        final OutputStream stream = os; // access volatile field only once per method
-        if (stream == null || stream == System.out || stream == System.err) {
-            return true;
-        }
-        try {
-            stream.close();
-        } catch (final IOException ex) {
-            logError("Unable to close stream", ex);
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Returns this {@code ByteBufferDestination}'s buffer.
-     * @return the buffer
-     * @since 2.6
-     */
-    @Override
-    public ByteBuffer getByteBuffer() {
-        return byteBuffer;
-    }
-
-    /**
-     * Drains the ByteBufferDestination's buffer into the destination. By default this calls
-     * {@link #flushBuffer(ByteBuffer)} with the specified buffer. Subclasses may override.
-     * <p>
-     * Do not call this method lightly! For some subclasses this is a very expensive operation. For example,
-     * {@link MemoryMappedFileManager} will assume this method was called because the end of the mapped region
-     * was reached during a text encoding operation and will {@linkplain MemoryMappedFileManager#remap() remap} its
-     * buffer.
-     * </p><p>
-     * To just flush the buffered contents to the underlying stream, call
-     * {@link #flushBuffer(ByteBuffer)} directly instead.
-     * </p>
-     *
-     * @param buf the buffer whose contents to write the the destination
-     * @return the specified buffer
-     * @since 2.6
-     */
-    @Override
-    public ByteBuffer drain(final ByteBuffer buf) {
-        flushBuffer(buf);
-        return buf;
-    }
-
-    @Override
-    public void writeBytes(ByteBuffer data) {
-        if (data.remaining() == 0) {
-          return;
-        }
-        synchronized (this) {
-          ByteBufferDestinationHelper.writeToUnsynchronized(data, this);
-        }
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.appender;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.layout.ByteBufferDestination;
+import org.apache.logging.log4j.core.layout.ByteBufferDestinationHelper;
+import org.apache.logging.log4j.core.util.Constants;
+
+/**
+ * Manages an OutputStream so that it can be shared by multiple Appenders and will
+ * allow appenders to reconfigure without requiring a new stream.
+ */
+public class OutputStreamManager extends AbstractManager implements ByteBufferDestination {
+    protected final Layout<?> layout;
+    protected ByteBuffer byteBuffer;
+    private volatile OutputStream outputStream;
+    private boolean skipFooter;
+
+    protected OutputStreamManager(final OutputStream os, final String streamName, final Layout<?> layout,
+            final boolean writeHeader) {
+        // Can't use new ctor because it throws an exception
+        this(os, streamName, layout, writeHeader, Constants.ENCODER_BYTE_BUFFER_SIZE);
+    }
+
+    protected OutputStreamManager(final OutputStream os, final String streamName, final Layout<?> layout,
+            final boolean writeHeader, final int bufferSize) {
+        // Can't use new ctor because it throws an exception
+        this(os, streamName, layout, writeHeader, ByteBuffer.wrap(new byte[bufferSize]));
+    }
+
+    /**
+     * @since 2.6
+     * @deprecated
+     */
+    @Deprecated
+    protected OutputStreamManager(final OutputStream os, final String streamName, final Layout<?> layout,
+            final boolean writeHeader, final ByteBuffer byteBuffer) {
+        super(null, streamName);
+        this.outputStream = os;
+        this.layout = layout;
+        if (writeHeader && layout != null) {
+            final byte[] header = layout.getHeader();
+            if (header != null) {
+                try {
+                    getOutputStream().write(header, 0, header.length);
+                } catch (final IOException e) {
+                    logError("Unable to write header", e);
+                }
+            }
+        }
+        this.byteBuffer = Objects.requireNonNull(byteBuffer, "byteBuffer");
+    }
+
+    /**
+     * @since 2.7
+     */
+    protected OutputStreamManager(final LoggerContext loggerContext, final OutputStream os, final String streamName,
+            final boolean createOnDemand, final Layout<? extends Serializable> layout, final boolean writeHeader,
+            final ByteBuffer byteBuffer) {
+        super(loggerContext, streamName);
+        if (createOnDemand && os != null) {
+            LOGGER.error(
+                    "Invalid OutputStreamManager configuration for '{}': You cannot both set the OutputStream and request on-demand.",
+                    streamName);
+        }
+        this.layout = layout;
+        this.byteBuffer = Objects.requireNonNull(byteBuffer, "byteBuffer");
+        this.outputStream = os;
+        if (writeHeader && layout != null) {
+            final byte[] header = layout.getHeader();
+            if (header != null) {
+                try {
+                    getOutputStream().write(header, 0, header.length);
+                } catch (final IOException e) {
+                    logError("Unable to write header for " + streamName, e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates a Manager.
+     *
+     * @param name The name of the stream to manage.
+     * @param data The data to pass to the Manager.
+     * @param factory The factory to use to create the Manager.
+     * @param <T> The type of the OutputStreamManager.
+     * @return An OutputStreamManager.
+     */
+    public static <T> OutputStreamManager getManager(final String name, final T data,
+                                                 final ManagerFactory<? extends OutputStreamManager, T> factory) {
+        return AbstractManager.getManager(name, factory, data);
+    }
+
+    @SuppressWarnings("unused")
+    protected OutputStream createOutputStream() throws IOException {
+        throw new IllegalStateException(getClass().getCanonicalName() + " must implement createOutputStream()");
+    }
+
+    /**
+     * Indicate whether the footer should be skipped or not.
+     * @param skipFooter true if the footer should be skipped.
+     */
+    public void skipFooter(final boolean skipFooter) {
+        this.skipFooter = skipFooter;
+    }
+
+    /**
+     * Default hook to write footer during close.
+     */
+    @Override
+    public boolean releaseSub(final long timeout, final TimeUnit timeUnit) {
+        writeFooter();
+        return closeOutputStream();
+    }
+
+    /**
+     * Writes the footer.
+     */
+    protected void writeFooter() {
+        if (layout == null || skipFooter) {
+            return;
+        }
+        final byte[] footer = layout.getFooter();
+        if (footer != null) {
+            write(footer);
+        }
+    }
+
+    /**
+     * Returns the status of the stream.
+     * @return true if the stream is open, false if it is not.
+     */
+    public boolean isOpen() {
+        return getCount() > 0;
+    }
+
+    public boolean hasOutputStream() {
+        return outputStream != null;
+    }
+
+    protected OutputStream getOutputStream() throws IOException {
+        if (outputStream == null) {
+            outputStream = createOutputStream();
+        }
+        return outputStream;
+    }
+
+    protected void setOutputStream(final OutputStream os) {
+        final byte[] header = layout.getHeader();
+        if (header != null) {
+            try {
+                os.write(header, 0, header.length);
+                this.outputStream = os; // only update field if os.write() succeeded
+            } catch (final IOException ioe) {
+                logError("Unable to write header", ioe);
+            }
+        } else {
+            this.outputStream = os;
+        }
+    }
+
+    /**
+     * Some output streams synchronize writes while others do not.
+     * @param bytes The serialized Log event.
+     * @throws AppenderLoggingException if an error occurs.
+     */
+    protected void write(final byte[] bytes)  {
+        write(bytes, 0, bytes.length, false);
+    }
+
+    /**
+     * Some output streams synchronize writes while others do not.
+     * @param bytes The serialized Log event.
+     * @param immediateFlush If true, flushes after writing.
+     * @throws AppenderLoggingException if an error occurs.
+     */
+    protected void write(final byte[] bytes, final boolean immediateFlush)  {
+        write(bytes, 0, bytes.length, immediateFlush);
+    }
+
+    @Override
+    public void writeBytes(final byte[] data, final int offset, final int length) {
+        write(data, offset, length, false);
+    }
+
+    /**
+     * Some output streams synchronize writes while others do not. Synchronizing here insures that
+     * log events won't be intertwined.
+     * @param bytes The serialized Log event.
+     * @param offset The offset into the byte array.
+     * @param length The number of bytes to write.
+     * @throws AppenderLoggingException if an error occurs.
+     */
+    protected void write(final byte[] bytes, final int offset, final int length) {
+        writeBytes(bytes, offset, length);
+    }
+
+    /**
+     * Some output streams synchronize writes while others do not. Synchronizing here insures that
+     * log events won't be intertwined.
+     * @param bytes The serialized Log event.
+     * @param offset The offset into the byte array.
+     * @param length The number of bytes to write.
+     * @param immediateFlush flushes immediately after writing.
+     * @throws AppenderLoggingException if an error occurs.
+     */
+    protected synchronized void write(final byte[] bytes, final int offset, final int length, final boolean immediateFlush) {
+        if (immediateFlush && byteBuffer.position() == 0) {
+            writeToDestination(bytes, offset, length);
+            flushDestination();
+            return;
+        }
+        if (length >= byteBuffer.capacity()) {
+            // if request length exceeds buffer capacity, flush the buffer and write the data directly
+            flush();
+            writeToDestination(bytes, offset, length);
+        } else {
+            if (length > byteBuffer.remaining()) {
+                flush();
+            }
+            byteBuffer.put(bytes, offset, length);
+        }
+        if (immediateFlush) {
+            flush();
+        }
+    }
+
+    /**
+     * Writes the specified section of the specified byte array to the stream.
+     *
+     * @param bytes the array containing data
+     * @param offset from where to write
+     * @param length how many bytes to write
+     * @since 2.6
+     */
+    protected synchronized void writeToDestination(final byte[] bytes, final int offset, final int length) {
+        try {
+            getOutputStream().write(bytes, offset, length);
+        } catch (final IOException ex) {
+            throw new AppenderLoggingException("Error writing to stream " + getName(), ex);
+        }
+    }
+
+    /**
+     * Calls {@code flush()} on the underlying output stream.
+     * @since 2.6
+     */
+    protected synchronized void flushDestination() {
+        final OutputStream stream = outputStream; // access volatile field only once per method
+        if (stream != null) {
+            try {
+                stream.flush();
+            } catch (final IOException ex) {
+                throw new AppenderLoggingException("Error flushing stream " + getName(), ex);
+            }
+        }
+    }
+
+    /**
+     * Drains the ByteBufferDestination's buffer into the destination. By default this calls
+     * {@link OutputStreamManager#write(byte[], int, int, boolean)} with the buffer contents.
+     * The underlying stream is not {@linkplain OutputStream#flush() flushed}.
+     *
+     * @see #flushDestination()
+     * @since 2.6
+     */
+    protected synchronized void flushBuffer(final ByteBuffer buf) {
+        buf.flip();
+        if (buf.remaining() > 0) {
+            writeToDestination(buf.array(), buf.arrayOffset() + buf.position(), buf.remaining());
+        }
+        buf.clear();
+    }
+
+    /**
+     * Flushes any buffers.
+     */
+    public synchronized void flush() {
+        flushBuffer(byteBuffer);
+        flushDestination();
+    }
+
+    protected synchronized boolean closeOutputStream() {
+        flush();
+        final OutputStream stream = outputStream; // access volatile field only once per method
+        if (stream == null || stream == System.out || stream == System.err) {
+            return true;
+        }
+        try {
+            stream.close();
+        } catch (final IOException ex) {
+            logError("Unable to close stream", ex);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns this {@code ByteBufferDestination}'s buffer.
+     * @return the buffer
+     * @since 2.6
+     */
+    @Override
+    public ByteBuffer getByteBuffer() {
+        return byteBuffer;
+    }
+
+    /**
+     * Drains the ByteBufferDestination's buffer into the destination. By default this calls
+     * {@link #flushBuffer(ByteBuffer)} with the specified buffer. Subclasses may override.
+     * <p>
+     * Do not call this method lightly! For some subclasses this is a very expensive operation. For example,
+     * {@link MemoryMappedFileManager} will assume this method was called because the end of the mapped region
+     * was reached during a text encoding operation and will {@linkplain MemoryMappedFileManager#remap() remap} its
+     * buffer.
+     * </p><p>
+     * To just flush the buffered contents to the underlying stream, call
+     * {@link #flushBuffer(ByteBuffer)} directly instead.
+     * </p>
+     *
+     * @param buf the buffer whose contents to write the the destination
+     * @return the specified buffer
+     * @since 2.6
+     */
+    @Override
+    public ByteBuffer drain(final ByteBuffer buf) {
+        flushBuffer(buf);
+        return buf;
+    }
+
+    @Override
+    public void writeBytes(ByteBuffer data) {
+        if (data.remaining() == 0) {
+          return;
+        }
+        synchronized (this) {
+          ByteBufferDestinationHelper.writeToUnsynchronized(data, this);
+        }
+    }
+}