Package com.hazelcast.client.connection.nio

Source Code of com.hazelcast.client.connection.nio.ClientConnection$CleanResourcesTask

/*
* Copyright (c) 2008-2013, 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.client.connection.nio;

import com.hazelcast.client.ClientTypes;
import com.hazelcast.client.spi.ClientExecutionService;
import com.hazelcast.client.spi.EventHandler;
import com.hazelcast.client.spi.impl.ClientCallFuture;
import com.hazelcast.core.HazelcastException;
import com.hazelcast.logging.ILogger;
import com.hazelcast.logging.Logger;
import com.hazelcast.nio.Address;
import com.hazelcast.nio.ClientPacket;
import com.hazelcast.nio.Connection;
import com.hazelcast.nio.ConnectionType;
import com.hazelcast.nio.IOSelector;
import com.hazelcast.nio.Protocols;
import com.hazelcast.nio.SocketChannelWrapper;
import com.hazelcast.nio.SocketWritable;
import com.hazelcast.nio.serialization.Data;
import com.hazelcast.nio.serialization.DataAdapter;
import com.hazelcast.nio.serialization.SerializationService;
import com.hazelcast.spi.exception.TargetDisconnectedException;
import com.hazelcast.util.ExceptionUtil;

import java.io.Closeable;
import java.io.EOFException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;

import static com.hazelcast.util.StringUtil.stringToBytes;

public class ClientConnection implements Connection, Closeable {

    private volatile boolean live = true;

    private final ILogger logger = Logger.getLogger(ClientConnection.class);

    private final ClientWriteHandler writeHandler;

    private final ClientReadHandler readHandler;

    private final ClientConnectionManagerImpl connectionManager;

    private final int connectionId;

    private final SocketChannelWrapper socketChannelWrapper;

    private volatile Address remoteEndpoint;

    private final ConcurrentMap<Integer, ClientCallFuture> callIdMap
            = new ConcurrentHashMap<Integer, ClientCallFuture>();
    private final ConcurrentMap<Integer, ClientCallFuture> eventHandlerMap
            = new ConcurrentHashMap<Integer, ClientCallFuture>();
    private final ByteBuffer readBuffer;
    private final SerializationService serializationService;
    private final ClientExecutionService executionService;
    private boolean readFromSocket = true;
    private final AtomicInteger packetCount = new AtomicInteger(0);

    public ClientConnection(ClientConnectionManagerImpl connectionManager, IOSelector in, IOSelector out,
                            int connectionId, SocketChannelWrapper socketChannelWrapper,
                            ClientExecutionService executionService) throws IOException {
        final Socket socket = socketChannelWrapper.socket();
        this.connectionManager = connectionManager;
        this.serializationService = connectionManager.getSerializationService();
        this.executionService = executionService;
        this.socketChannelWrapper = socketChannelWrapper;
        this.connectionId = connectionId;
        this.readHandler = new ClientReadHandler(this, in, socket.getReceiveBufferSize());
        this.writeHandler = new ClientWriteHandler(this, out, socket.getSendBufferSize());
        this.readBuffer = ByteBuffer.allocate(socket.getReceiveBufferSize());
    }

    public void incrementPacketCount() {
        packetCount.incrementAndGet();
    }

    public void decrementPacketCount() {
        packetCount.decrementAndGet();
    }

    public void registerCallId(ClientCallFuture future) {
        final int callId = connectionManager.newCallId();
        future.getRequest().setCallId(callId);
        callIdMap.put(callId, future);
        if (future.getHandler() != null) {
            eventHandlerMap.put(callId, future);
        }
    }

    public ClientCallFuture deRegisterCallId(int callId) {
        return callIdMap.remove(callId);
    }

    public ClientCallFuture deRegisterEventHandler(int callId) {
        return eventHandlerMap.remove(callId);
    }

    public EventHandler getEventHandler(int callId) {
        final ClientCallFuture future = eventHandlerMap.get(callId);
        if (future == null) {
            return null;
        }
        return future.getHandler();
    }

    @Override
    public boolean write(SocketWritable packet) {
        if (!live) {
            if (logger.isFinestEnabled()) {
                logger.finest("Connection is closed, won't write packet -> " + packet);
            }
            return false;
        }
        writeHandler.enqueueSocketWritable(packet);
        return true;
    }

    public void init() throws IOException {
        final ByteBuffer buffer = ByteBuffer.allocate(6);
        buffer.put(stringToBytes(Protocols.CLIENT_BINARY));
        buffer.put(stringToBytes(ClientTypes.JAVA));
        buffer.flip();
        socketChannelWrapper.write(buffer);
    }

    public void write(Data data) throws IOException {
        final int totalSize = data.totalSize();
        final int bufferSize = ClientConnectionManagerImpl.BUFFER_SIZE;
        final ByteBuffer buffer = ByteBuffer.allocate(totalSize > bufferSize ? bufferSize : totalSize);
        final DataAdapter packet = new DataAdapter(data);
        boolean complete = false;
        while (!complete) {
            complete = packet.writeTo(buffer);
            buffer.flip();
            try {
                socketChannelWrapper.write(buffer);
            } catch (Exception e) {
                throw ExceptionUtil.rethrow(e);
            }
            buffer.clear();
        }
    }

    public Data read() throws IOException {
        ClientPacket packet = new ClientPacket(serializationService.getSerializationContext());
        while (true) {
            if (readFromSocket) {
                int readBytes = socketChannelWrapper.read(readBuffer);
                if (readBytes == -1) {
                    throw new EOFException("Remote socket closed!");
                }
                readBuffer.flip();
            }
            boolean complete = packet.readFrom(readBuffer);
            if (complete) {
                if (readBuffer.hasRemaining()) {
                    readFromSocket = false;
                } else {
                    readBuffer.compact();
                    readFromSocket = true;
                }
                return packet.getData();
            }
            readFromSocket = true;
            readBuffer.clear();
        }
    }

    @Override
    public Address getEndPoint() {
        return remoteEndpoint;
    }

    @Override
    public boolean live() {
        return live;
    }

    @Override
    public long lastReadTime() {
        return readHandler.getLastHandle();
    }

    @Override
    public long lastWriteTime() {
        return writeHandler.getLastHandle();
    }

    @Override
    public void close() {
        close(null);
    }

    @Override
    public ConnectionType getType() {
        return ConnectionType.JAVA_CLIENT;
    }

    @Override
    public boolean isClient() {
        return true;
    }

    @Override
    public InetAddress getInetAddress() {
        return socketChannelWrapper.socket().getInetAddress();
    }

    @Override
    public InetSocketAddress getRemoteSocketAddress() {
        return (InetSocketAddress) socketChannelWrapper.socket().getRemoteSocketAddress();
    }

    @Override
    public int getPort() {
        return socketChannelWrapper.socket().getPort();
    }

    public SocketChannelWrapper getSocketChannelWrapper() {
        return socketChannelWrapper;
    }

    public ClientConnectionManagerImpl getConnectionManager() {
        return connectionManager;
    }

    public ClientReadHandler getReadHandler() {
        return readHandler;
    }

    public void setRemoteEndpoint(Address remoteEndpoint) {
        this.remoteEndpoint = remoteEndpoint;
    }

    public Address getRemoteEndpoint() {
        return remoteEndpoint;
    }

    public InetSocketAddress getLocalSocketAddress() {
        return (InetSocketAddress) socketChannelWrapper.socket().getLocalSocketAddress();
    }

    void innerClose() throws IOException {
        if (!live) {
            return;
        }
        live = false;
        if (socketChannelWrapper.isOpen()) {
            socketChannelWrapper.close();
        }
        readHandler.shutdown();
        writeHandler.shutdown();
        if (socketChannelWrapper.isBlocking()) {
            return;
        }
        if (connectionManager.isLive()) {
            try {
                executionService.execute(new CleanResourcesTask());
            } catch (RejectedExecutionException e) {
                logger.warning("Execution rejected ", e);
            }
        } else {
            cleanResources(new HazelcastException("Client is shutting down!!!"));
        }

    }

    private class CleanResourcesTask implements Runnable {
        @Override
        public void run() {
            waitForPacketsProcessed();
            cleanResources(new TargetDisconnectedException(remoteEndpoint));
        }

        private void waitForPacketsProcessed() {
            final long begin = System.currentTimeMillis();
            int count = packetCount.get();
            while (count != 0) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    logger.warning(e);
                    break;
                }
                long elapsed = System.currentTimeMillis() - begin;
                if (elapsed > 5000) {
                    logger.warning("There are packets which are not processed " + count);
                    break;
                }
                count = packetCount.get();
            }
        }
    }

    private void cleanResources(HazelcastException response){
        final Iterator<Map.Entry<Integer,ClientCallFuture>> iter = callIdMap.entrySet().iterator();
        while (iter.hasNext()) {
            final Map.Entry<Integer, ClientCallFuture> entry = iter.next();
            iter.remove();
            entry.getValue().notify(response);
            eventHandlerMap.remove(entry.getKey());
        }
        final Iterator<ClientCallFuture> iterator = eventHandlerMap.values().iterator();
        while (iterator.hasNext()) {
            final ClientCallFuture future = iterator.next();
            iterator.remove();
            future.notify(response);
        }
    }

    public void close(Throwable t) {
        if (!live) {
            return;
        }
        try {
            innerClose();
        } catch (Exception e) {
            logger.warning(e);
        }
        String message = "Connection [" + socketChannelWrapper.socket().getRemoteSocketAddress() + "] lost. Reason: ";
        if (t != null) {
            message += t.getClass().getName() + "[" + t.getMessage() + "]";
        } else {
            message += "Socket explicitly closed";
        }

        logger.warning(message);
        if (!socketChannelWrapper.isBlocking()) {
            connectionManager.destroyConnection(this);
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof ClientConnection)) return false;

        ClientConnection that = (ClientConnection) o;

        if (connectionId != that.connectionId) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return connectionId;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("ClientConnection{");
        sb.append("live=").append(live);
        sb.append(", writeHandler=").append(writeHandler);
        sb.append(", readHandler=").append(readHandler);
        sb.append(", connectionId=").append(connectionId);
        sb.append(", socketChannel=").append(socketChannelWrapper);
        sb.append(", remoteEndpoint=").append(remoteEndpoint);
        sb.append('}');
        return sb.toString();
    }

}
TOP

Related Classes of com.hazelcast.client.connection.nio.ClientConnection$CleanResourcesTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.