All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.internal.nio.IOUtil Maven / Gradle / Ivy

There is a newer version: 5.0-BETA-1
Show newest version
/*
 * Copyright (c) 2008-2021, Hazelcast, Inc. All Rights Reserved.
 *
 * Licensed 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 com.hazelcast.internal.nio;

import com.hazelcast.config.EndpointConfig;
import com.hazelcast.core.HazelcastException;
import com.hazelcast.internal.networking.Channel;
import com.hazelcast.internal.networking.ChannelOptions;
import com.hazelcast.internal.serialization.Data;
import com.hazelcast.logging.ILogger;
import com.hazelcast.logging.Logger;
import com.hazelcast.nio.ObjectDataInput;
import com.hazelcast.nio.ObjectDataOutput;
import com.hazelcast.nio.serialization.ClassNameFilter;

import javax.annotation.Nonnull;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.io.OutputStream;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Random;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

import static com.hazelcast.internal.networking.ChannelOption.DIRECT_BUF;
import static com.hazelcast.internal.networking.ChannelOption.SO_KEEPALIVE;
import static com.hazelcast.internal.networking.ChannelOption.SO_LINGER;
import static com.hazelcast.internal.networking.ChannelOption.SO_RCVBUF;
import static com.hazelcast.internal.networking.ChannelOption.SO_SNDBUF;
import static com.hazelcast.internal.networking.ChannelOption.TCP_NODELAY;
import static com.hazelcast.internal.server.ServerContext.KILO_BYTE;
import static com.hazelcast.internal.util.EmptyStatement.ignore;
import static com.hazelcast.internal.util.ExceptionUtil.rethrow;
import static java.lang.String.format;
import static java.nio.file.FileVisitResult.CONTINUE;
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;

@SuppressWarnings({ "WeakerAccess", "checkstyle:methodcount", "checkstyle:magicnumber", "checkstyle:classfanoutcomplexity",
        "checkstyle:ClassDataAbstractionCoupling" })
public final class IOUtil {

    private static final ILogger LOGGER = Logger.getLogger(IOUtil.class);

    private IOUtil() {
    }

    /**
     * Compacts or clears the buffer depending if bytes are remaining in the byte-buffer.
     *
     * @param bb the ByteBuffer
     */
    public static void compactOrClear(ByteBuffer bb) {
        if (bb.hasRemaining()) {
            bb.compact();
        } else {
            bb.clear();
        }
    }

    public static ByteBuffer newByteBuffer(int bufferSize, boolean direct) {
        if (direct) {
            return ByteBuffer.allocateDirect(bufferSize);
        } else {
            return ByteBuffer.allocate(bufferSize);
        }
    }

    public static void writeByteArray(ObjectDataOutput out, byte[] value) throws IOException {
        int size = (value == null) ? 0 : value.length;
        out.writeInt(size);
        if (size > 0) {
            out.write(value);
        }
    }

    public static byte[] readByteArray(ObjectDataInput in) throws IOException {
        int size = in.readInt();
        if (size == 0) {
            return null;
        } else {
            byte[] b = new byte[size];
            in.readFully(b);
            return b;
        }
    }

    public static void writeObject(ObjectDataOutput out, Object object) throws IOException {
        boolean isBinary = object instanceof Data;
        out.writeBoolean(isBinary);
        if (isBinary) {
            writeData(out, (Data) object);
        } else {
            out.writeObject(object);
        }
    }

    @SuppressWarnings("unchecked")
    public static  T readObject(ObjectDataInput in) throws IOException {
        boolean isBinary = in.readBoolean();
        if (isBinary) {
            return (T) readData(in);
        }
        return in.readObject();
    }

    public static void writeBigInteger(ObjectDataOutput out, BigInteger value) throws IOException {
        final byte[] bytes = value.toByteArray();
        out.writeInt(bytes.length);
        out.write(bytes);
    }

    public static BigInteger readBigInteger(ObjectDataInput in) throws IOException {
        final byte[] bytes = new byte[in.readInt()];
        in.readFully(bytes);
        return new BigInteger(bytes);
    }

    public static void writeBigDecimal(ObjectDataOutput out, BigDecimal value) throws IOException {
        IOUtil.writeBigInteger(out, value.unscaledValue());
        int scale = value.scale();
        out.writeInt(scale);
    }

    public static BigDecimal readBigDecimal(ObjectDataInput in) throws IOException {
        BigInteger bigInteger = readBigInteger(in);
        int scale = in.readInt();
        return new BigDecimal(bigInteger, scale);
    }

    public static void writeLocalTime(ObjectDataOutput out, LocalTime value) throws IOException {
        int hour = value.getHour();
        int minute = value.getMinute();
        int second = value.getSecond();
        int nano = value.getNano();
        out.writeByte(hour);
        out.writeByte(minute);
        out.writeByte(second);
        out.writeInt(nano);
    }

    public static LocalTime readLocalTime(ObjectDataInput in) throws IOException {
        int hour = in.readByte();
        int minute = in.readByte();
        int second = in.readByte();
        int nano = in.readInt();
        return LocalTime.of(hour, minute, second, nano);
    }

    public static void writeLocalDate(ObjectDataOutput out, LocalDate value) throws IOException {
        int year = value.getYear();
        int monthValue = value.getMonthValue();
        int dayOfMonth = value.getDayOfMonth();
        out.writeShort(year);
        out.writeByte(monthValue);
        out.writeByte(dayOfMonth);
    }

    public static LocalDate readLocalDate(ObjectDataInput in) throws IOException {
        int year = in.readShort();
        int month = in.readByte();
        int dayOfMonth = in.readByte();
        return LocalDate.of(year, month, dayOfMonth);
    }

    public static void writeLocalDateTime(ObjectDataOutput out, LocalDateTime value) throws IOException {
        int year = value.getYear();
        int monthValue = value.getMonthValue();
        int dayOfMonth = value.getDayOfMonth();
        out.writeShort(year);
        out.writeByte(monthValue);
        out.writeByte(dayOfMonth);

        int hour = value.getHour();
        int minute = value.getMinute();
        int second = value.getSecond();
        int nano = value.getNano();
        out.writeByte(hour);
        out.writeByte(minute);
        out.writeByte(second);
        out.writeInt(nano);
    }

    public static LocalDateTime readLocalDateTime(ObjectDataInput in) throws IOException {
        int year = in.readShort();
        int month = in.readByte();
        int dayOfMonth = in.readByte();

        int hour = in.readByte();
        int minute = in.readByte();
        int second = in.readByte();
        int nano = in.readInt();

        return LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, nano);
    }

    public static void writeOffsetDateTime(ObjectDataOutput out, OffsetDateTime value) throws IOException {
        int year = value.getYear();
        int monthValue = value.getMonthValue();
        int dayOfMonth = value.getDayOfMonth();
        out.writeShort(year);
        out.writeByte(monthValue);
        out.writeByte(dayOfMonth);

        int hour = value.getHour();
        int minute = value.getMinute();
        int second = value.getSecond();
        int nano = value.getNano();
        out.writeByte(hour);
        out.writeByte(minute);
        out.writeByte(second);
        out.writeInt(nano);

        ZoneOffset offset = value.getOffset();
        int totalSeconds = offset.getTotalSeconds();
        out.writeInt(totalSeconds);
    }

    public static OffsetDateTime readOffsetDateTime(ObjectDataInput in) throws IOException {
        int year = in.readShort();
        int month = in.readByte();
        int dayOfMonth = in.readByte();

        int hour = in.readByte();
        int minute = in.readByte();
        int second = in.readByte();
        int nano = in.readInt();

        int zoneTotalSeconds = in.readInt();
        ZoneOffset zoneOffset = ZoneOffset.ofTotalSeconds(zoneTotalSeconds);
        return OffsetDateTime.of(year, month, dayOfMonth, hour, minute, second, nano, zoneOffset);
    }

    public static void writeData(ObjectDataOutput out, Data data) throws IOException {
        assert out instanceof DataWriter : "out must be an instance of DataWriter";
        ((DataWriter) out).writeData(data);
    }

    public static Data readData(ObjectDataInput in) throws IOException {
        assert in instanceof DataReader : "in must be an instance of DataReader";
        return ((DataReader) in).readData();
    }

    public static  T readDataAsObject(ObjectDataInput in) throws IOException {
        assert in instanceof DataReader : "in must be an instance of DataReader";
        return ((DataReader) in).readDataAsObject();
    }

    /**
     * Fills a buffer from an {@link InputStream}. If it doesn't contain any
     * more data, returns {@code false}. If it contains some data, but not
     * enough to fill the buffer, {@link EOFException} is thrown.
     *
     * @param in     the {@link InputStream} to read from
     * @param buffer the buffer to fill
     * @return {@code true} if the buffer was filled completely,
     * {@code false} if there was no data in the {@link InputStream}
     * @throws EOFException if there was some, but not enough, data in the
     *                      {@link InputStream} to fill the buffer
     */
    public static boolean readFullyOrNothing(InputStream in, byte[] buffer) throws IOException {
        int bytesRead = 0;
        do {
            int count = in.read(buffer, bytesRead, buffer.length - bytesRead);
            if (count < 0) {
                if (bytesRead == 0) {
                    return false;
                }
                throw new EOFException();
            }
            bytesRead += count;
        } while (bytesRead < buffer.length);
        return true;
    }

    /**
     * Fills a buffer from an {@link InputStream}.
     *
     * @param in     the {@link InputStream} to read from
     * @param buffer the buffer to fill
     * @throws EOFException if there was not enough data in the {@link InputStream} to fill the buffer
     */
    public static void readFully(InputStream in, byte[] buffer) throws IOException {
        if (!readFullyOrNothing(in, buffer)) {
            throw new EOFException();
        }
    }

    public static ObjectInputStream newObjectInputStream(final ClassLoader classLoader, ClassNameFilter classFilter,
                                                         InputStream in) throws IOException {
        return new ClassLoaderAwareObjectInputStream(classLoader, classFilter, in);
    }

    public static OutputStream newOutputStream(final ByteBuffer dst) {
        return new OutputStream() {
            public void write(int b) {
                dst.put((byte) b);
            }

            public void write(byte[] bytes, int off, int len) {
                dst.put(bytes, off, len);
            }
        };
    }

    public static InputStream newInputStream(final ByteBuffer src) {
        return new InputStream() {
            public int read() {
                if (!src.hasRemaining()) {
                    return -1;
                }
                return src.get() & 0xff;
            }

            public int read(byte[] bytes, int off, int len) {
                if (!src.hasRemaining()) {
                    return -1;
                }
                len = Math.min(len, src.remaining());
                src.get(bytes, off, len);
                return len;
            }
        };
    }

    public static int copyToHeapBuffer(ByteBuffer src, ByteBuffer dst) {
        if (src == null) {
            return 0;
        }
        int n = Math.min(src.remaining(), dst.remaining());
        if (n > 0) {
            if (n < 16) {
                for (int i = 0; i < n; i++) {
                    dst.put(src.get());
                }
            } else {
                int srcPosition = src.position();
                int destPosition = dst.position();
                System.arraycopy(src.array(), srcPosition, dst.array(), destPosition, n);
                src.position(srcPosition + n);
                dst.position(destPosition + n);
            }
        }
        return n;
    }

    public static byte[] compress(byte[] input) {
        if (input.length == 0) {
            return new byte[0];
        }
        int len = Math.max(input.length / 10, 10);

        Deflater compressor = new Deflater();
        compressor.setLevel(Deflater.BEST_SPEED);
        compressor.setInput(input);
        compressor.finish();
        ByteArrayOutputStream bos = new ByteArrayOutputStream(len);
        byte[] buf = new byte[len];
        while (!compressor.finished()) {
            int count = compressor.deflate(buf);
            bos.write(buf, 0, count);
        }
        compressor.end();
        return bos.toByteArray();
    }

    public static byte[] decompress(byte[] compressedData) {
        if (compressedData.length == 0) {
            return compressedData;
        }
        Inflater inflater = new Inflater();
        inflater.setInput(compressedData);
        ByteArrayOutputStream bos = new ByteArrayOutputStream(compressedData.length);
        byte[] buf = new byte[1024];
        while (!inflater.finished()) {
            try {
                int count = inflater.inflate(buf);
                bos.write(buf, 0, count);
            } catch (DataFormatException e) {
                LOGGER.finest("Decompression failed", e);
            }
        }
        inflater.end();
        return bos.toByteArray();
    }

    /**
     * Quietly attempts to close a {@link Closeable} resource, swallowing any exception.
     *
     * @param closeable the resource to close. If {@code null}, no action is taken.
     */
    public static void closeResource(Closeable closeable) {
        if (closeable == null) {
            return;
        }
        try {
            closeable.close();
        } catch (IOException e) {
            LOGGER.finest("closeResource failed", e);
        }
    }

    public static void close(Connection conn, String reason) {
        if (conn == null) {
            return;
        }
        try {
            conn.close(reason, null);
        } catch (Throwable e) {
            LOGGER.finest("closeResource failed", e);
        }
    }

    /**
     * Quietly attempts to close a {@link ServerSocket}, swallowing any exception.
     *
     * @param serverSocket server socket to close. If {@code null}, no action is taken.
     */
    public static void close(ServerSocket serverSocket) {
        if (serverSocket == null) {
            return;
        }
        try {
            serverSocket.close();
        } catch (IOException e) {
            LOGGER.finest("closeResource failed", e);
        }
    }

    /**
     * Quietly attempts to close a {@link Socket}, swallowing any exception.
     *
     * @param socket socket to close. If {@code null}, no action is taken.
     */
    public static void close(Socket socket) {
        if (socket == null) {
            return;
        }
        try {
            socket.close();
        } catch (IOException e) {
            LOGGER.finest("closeResource failed", e);
        }
    }

    /**
     * Ensures that the file described by the supplied parameter does not exist
     * after the method returns. If the file didn't exist, returns silently.
     * If the file could not be deleted, returns silently.
     * If the file is a directory, its children are recursively deleted.
     */
    public static void deleteQuietly(@Nonnull File f) {
        try {
            delete(f.toPath());
        } catch (Exception e) {
            ignore(e);
        }
    }

    /**
     * Ensures that the file described by the supplied parameter does not exist
     * after the method returns. If the file didn't exist, returns silently.
     * If the file could not be deleted, fails with an exception.
     * If the file is a directory, its children are recursively deleted.
     */
    public static void delete(@Nonnull File f) {
        delete(f.toPath());
    }

    /**
     * Ensures that the file described by the supplied parameter does not exist
     * after the method returns. If the file didn't exist, returns silently.
     * If the file could not be deleted, fails with an exception.
     * If the file is a directory, its children are recursively deleted.
     */
    public static void delete(@Nonnull Path path) {
        if (!Files.exists(path, NOFOLLOW_LINKS)) {
            return;
        }
        try {
            Files.walkFileTree(path, new SimpleFileVisitor() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    Files.delete(file);
                    return CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                    Files.delete(dir);
                    return CONTINUE;
                }
            });
        } catch (IOException e) {
            throw new HazelcastException("Failed to delete " + path, e);
        }
    }

    /**
     * Ensures that the file described by {@code fileNow} is renamed to file described by {@code fileToBe}.
     * First attempts to perform a direct, atomic rename; if that fails, checks whether the target exists,
     * deletes it, and retries. Throws an exception in each case where the rename failed.
     *
     * @param fileNow  describes an existing file
     * @param fileToBe describes the desired pathname for the file
     */
    public static void rename(File fileNow, File fileToBe) {
        if (fileNow.renameTo(fileToBe)) {
            return;
        }
        if (!fileNow.exists()) {
            throw new HazelcastException(format("Failed to rename %s to %s because %s doesn't exist.",
                    fileNow, fileToBe, fileNow));
        }
        if (!fileToBe.exists()) {
            throw new HazelcastException(format("Failed to rename %s to %s even though %s doesn't exist.",
                    fileNow, fileToBe, fileToBe));
        }
        if (!fileToBe.delete()) {
            throw new HazelcastException(format("Failed to rename %s to %s. %s exists and could not be deleted.",
                    fileNow, fileToBe, fileToBe));
        }
        if (!fileNow.renameTo(fileToBe)) {
            throw new HazelcastException(format("Failed to rename %s to %s even after deleting %s.",
                    fileNow, fileToBe, fileToBe));
        }
    }

    /**
     * Move or rename a file to a target file. This move method contains a fallback (delete target + atomic move) for cases when
     * the first try fails. It's a NIO-based alternative to the {@link #rename(File, File)} method.
     *
     * @param source path to the file to move
     * @param target path to the target file
     */
    public static void move(Path source, Path target) throws IOException {
        try {
            Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            LOGGER.finest("File move failed. Fallbacking to delete&move.", e);
            Files.deleteIfExists(target);
            Files.move(source, target, StandardCopyOption.ATOMIC_MOVE);
        }
    }

    /**
     * Move or rename a file to a target file with retries within the given timeout.
     * Retrying can be beneficial on some systems (e.g. Windows), where file locking may behave non-intuitively.
     *
     * @param source path to the file to move
     * @param target path to the target file
     */
    public static void moveWithTimeout(Path source, Path target, Duration duration) {
        long endTime = System.nanoTime() + duration.toNanos();
        IOException lastException = null;
        Random rnd = new Random();
        do {
            try {
                move(source, target);
            } catch (IOException e) {
                lastException = e;
                LOGGER.finest("File move failed", e);
            }
            if (!Files.exists(source)) {
                return;
            }
            try {
                //random delay up to half a second
                Thread.sleep(rnd.nextInt(500));
            } catch (InterruptedException e) {
                ignore(e);
            }
        } while (System.nanoTime() - endTime < 0);
        throw new HazelcastException("File move timed out.", lastException);
    }

    public static String toFileName(String name) {
        return name.replaceAll("[:\\\\/*\"?|<>',]", "_");
    }

    /**
     * Concatenates path parts to a single path using the {@link File#separator} where it applies.
     * There is no validation done on the newly formed path.
     *
     * @param parts The path parts that together should form a path
     * @return The path formed using the parts
     * @throws IllegalArgumentException if the parts param is null or empty
     */
    public static String getPath(String... parts) {
        if (parts == null || parts.length == 0) {
            throw new IllegalArgumentException("Parts is null or empty.");
        }

        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < parts.length; i++) {
            String part = parts[i];
            builder.append(part);

            boolean hasMore = i < parts.length - 1;
            if (!part.endsWith(File.separator) && hasMore) {
                builder.append(File.separator);
            }
        }

        return builder.toString();
    }

    public static File getFileFromResources(String resourceFileName) {
        try {
            URL resource = IOUtil.class.getClassLoader().getResource(resourceFileName);
            //noinspection ConstantConditions
            return new File(resource.toURI());
        } catch (Exception e) {
            throw new HazelcastException("Could not find resource file " + resourceFileName, e);
        }
    }

    public static InputStream getFileFromResourcesAsStream(String resourceFileName) {
        try {
            return IOUtil.class.getClassLoader().getResourceAsStream(resourceFileName);
        } catch (Exception e) {
            throw new HazelcastException("Could not find resource file " + resourceFileName, e);
        }
    }

    /**
     * Simulates a Linux {@code touch} command, by setting the last modified time of given file.
     *
     * @param file the file to touch
     */
    public static void touch(File file) {
        FileOutputStream fos = null;
        try {
            if (!file.exists()) {
                fos = new FileOutputStream(file);
            }
            if (!file.setLastModified(System.currentTimeMillis())) {
                throw new HazelcastException("Could not touch file " + file.getAbsolutePath());
            }
        } catch (IOException e) {
            throw rethrow(e);
        } finally {
            closeResource(fos);
        }
    }

    /**
     * Deep copies source to target and creates the target if necessary.
     * 

* The source can be a directory or a file and the target can be a directory or file. *

* If the source is a directory, it expects that the target is a directory (or that it doesn't exist) * and nests the copied source under the target directory. * * @param source the source * @param target the destination * @throws IllegalArgumentException if the source was not found or the source is a directory and the target is a file * @throws HazelcastException if there was any exception while creating directories or copying */ public static void copy(File source, File target) { if (!source.exists()) { throw new IllegalArgumentException("Source does not exist"); } if (source.isDirectory()) { copyDirectory(source, target); } else { copyFile(source, target, -1); } } /** * Deep copies source to target. If target doesn't exist, this will fail with {@link HazelcastException}. *

* The source is only accessed here, but not managed. It's the responsibility of the caller to release * any resources held by the source. * * @param source the source * @param target the destination * @throws HazelcastException if the target doesn't exist */ public static void copy(InputStream source, File target) { if (!target.exists()) { throw new HazelcastException("The target file doesn't exist " + target.getAbsolutePath()); } FileOutputStream out = null; try { out = new FileOutputStream(target); byte[] buff = new byte[8192]; int length; while ((length = source.read(buff)) > 0) { out.write(buff, 0, length); } } catch (Exception e) { throw new HazelcastException("Error occurred while copying InputStream", e); } finally { closeResource(out); } } /** * Copies source file to target and creates the target if necessary. The target can be a directory or file. If the target * is a file, nests the new file under the target directory, otherwise copies to the given target. * * @param source the source file * @param target the destination file or directory * @param sourceCount the maximum number of bytes to be transferred (if negative transfers the entire source file) * @throws IllegalArgumentException if the source was not found or the source not a file * @throws HazelcastException if there was any exception while creating directories or copying */ public static void copyFile(File source, File target, long sourceCount) { if (!source.exists()) { throw new IllegalArgumentException("Source does not exist " + source.getAbsolutePath()); } if (!source.isFile()) { throw new IllegalArgumentException("Source is not a file " + source.getAbsolutePath()); } if (!target.exists() && !target.mkdirs()) { throw new HazelcastException("Could not create the target directory " + target.getAbsolutePath()); } final File destination = target.isDirectory() ? new File(target, source.getName()) : target; FileInputStream in = null; FileOutputStream out = null; try { in = new FileInputStream(source); out = new FileOutputStream(destination); final FileChannel inChannel = in.getChannel(); final FileChannel outChannel = out.getChannel(); final long transferCount = sourceCount > 0 ? sourceCount : inChannel.size(); inChannel.transferTo(0, transferCount, outChannel); } catch (Exception e) { throw new HazelcastException("Error occurred while copying file", e); } finally { closeResource(in); closeResource(out); } } private static void copyDirectory(File source, File target) { if (target.exists() && !target.isDirectory()) { throw new IllegalArgumentException("Cannot copy source directory since the target already exists," + " but it is not a directory"); } final File targetSubDir = new File(target, source.getName()); if (!targetSubDir.exists() && !targetSubDir.mkdirs()) { throw new HazelcastException("Could not create the target directory " + target); } final File[] sourceFiles = source.listFiles(); if (sourceFiles == null) { throw new HazelcastException("Error occurred while listing directory contents for copy"); } for (File file : sourceFiles) { copy(file, targetSubDir); } } public static byte[] toByteArray(InputStream is) throws IOException { ByteArrayOutputStream os = null; try { os = new ByteArrayOutputStream(); drainTo(is, os); return os.toByteArray(); } finally { closeResource(os); } } public static void drainTo(InputStream input, OutputStream output) throws IOException { byte[] buffer = new byte[1024]; int n; while (-1 != (n = input.read(buffer))) { output.write(buffer, 0, n); } } /** * Writes {@code len} bytes from the given input stream to the given output stream. * * @param input the input stream * @param output the output stream * @param len the number of bytes to write * @throws IOException if there are not enough bytes in the input stream, or if there is any other IO error. */ public static void drainTo(InputStream input, OutputStream output, int len) throws IOException { byte[] buffer = new byte[1024]; int remaining = len; while (remaining > 0) { int n = input.read(buffer, 0, Math.min(buffer.length, remaining)); if (n == -1) { throw new IOException("Not enough bytes in the input stream"); } output.write(buffer, 0, n); remaining -= n; } } /** * Writes maximum {@code limit} bytes from the given input stream to the given output stream. * * @param input the input stream * @param output the output stream * @param limit the maximum number of bytes to write * @throws IOException if there is any other IO error. */ public static void drainToLimited(InputStream input, OutputStream output, int limit) throws IOException { byte[] buffer = new byte[1024]; int remaining = limit; while (remaining > 0) { int n = input.read(buffer, 0, Math.min(buffer.length, remaining)); if (n < 1) { return; } output.write(buffer, 0, n); remaining -= n; } } /** * Creates a debug String for te given ByteBuffer. Useful when debugging IO. *

* Do not remove even if this method isn't used. * * @param name name of the ByteBuffer. * @param byteBuffer the ByteBuffer * @return the debug String */ public static String toDebugString(String name, ByteBuffer byteBuffer) { return name + "(pos:" + byteBuffer.position() + " lim:" + byteBuffer.limit() + " remain:" + byteBuffer.remaining() + " cap:" + byteBuffer.capacity() + ")"; } /** * Sets configured channel options on given {@link Channel}. * * @param channel the {@link Channel} on which options will be set * @param config the endpoint configuration */ public static void setChannelOptions(Channel channel, EndpointConfig config) { ChannelOptions options = channel.options(); options.setOption(DIRECT_BUF, config.isSocketBufferDirect()) .setOption(TCP_NODELAY, config.isSocketTcpNoDelay()) .setOption(SO_KEEPALIVE, config.isSocketKeepAlive()) .setOption(SO_SNDBUF, config.getSocketSendBufferSizeKb() * KILO_BYTE) .setOption(SO_RCVBUF, config.getSocketRcvBufferSizeKb() * KILO_BYTE) .setOption(SO_LINGER, config.getSocketLingerSeconds()); } private static final class ClassLoaderAwareObjectInputStream extends ObjectInputStream { private final ClassLoader classLoader; private final ClassNameFilter classFilter; private ClassLoaderAwareObjectInputStream(final ClassLoader classLoader, ClassNameFilter classFilter, final InputStream in) throws IOException { super(in); this.classLoader = classLoader; this.classFilter = classFilter; } @Override protected Class resolveClass(ObjectStreamClass desc) throws ClassNotFoundException { String name = desc.getName(); if (classFilter != null) { classFilter.filter(name); } return ClassLoaderUtil.loadClass(classLoader, name); } @Override protected Class resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException { ClassLoader theClassLoader = getClassLoader(); if (theClassLoader == null) { return super.resolveProxyClass(interfaces); } ClassLoader nonPublicLoader = null; Class[] classObjs = new Class[interfaces.length]; for (int i = 0; i < interfaces.length; i++) { Class cl = ClassLoaderUtil.loadClass(theClassLoader, interfaces[i]); if ((cl.getModifiers() & Modifier.PUBLIC) == 0) { if (nonPublicLoader != null) { if (nonPublicLoader != cl.getClassLoader()) { throw new IllegalAccessError("conflicting non-public interface class loaders"); } } else { nonPublicLoader = cl.getClassLoader(); } } classObjs[i] = cl; } try { return Proxy.getProxyClass(nonPublicLoader != null ? nonPublicLoader : theClassLoader, classObjs); } catch (IllegalArgumentException e) { throw new ClassNotFoundException(null, e); } } private ClassLoader getClassLoader() { ClassLoader theClassLoader = this.classLoader; if (theClassLoader == null) { theClassLoader = Thread.currentThread().getContextClassLoader(); } return theClassLoader; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy