/*
* Copyright (c) 2008-2012, Hazel Bilisim Ltd. 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.nio;
import com.hazelcast.impl.base.SystemLogService;
import com.hazelcast.logging.ILogger;
import com.hazelcast.util.SimpleBoundedQueue;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.logging.Level;
public final class Connection {
final SocketChannelWrapper socketChannel;
final ReadHandler readHandler;
final WriteHandler writeHandler;
final ConnectionManager connectionManager;
final InOutSelector inOutSelector;
private volatile boolean live = true;
private volatile Type type = Type.NONE;
Address endPoint = null;
private final ILogger logger;
private final SystemLogService systemLogService;
private final int connectionId;
private final SimpleBoundedQueue<Packet> packetQueue = new SimpleBoundedQueue<Packet>(100);
private ConnectionMonitor monitor;
public Connection(ConnectionManager connectionManager, InOutSelector inOutSelector, int connectionId, SocketChannelWrapper socketChannel) {
this.inOutSelector = inOutSelector;
this.connectionId = connectionId;
this.logger = connectionManager.ioService.getLogger(Connection.class.getName());
this.systemLogService = connectionManager.ioService.getSystemLogService();
this.connectionManager = connectionManager;
this.socketChannel = socketChannel;
this.writeHandler = new WriteHandler(this);
this.readHandler = new ReadHandler(this);
}
public SystemLogService getSystemLogService() {
return systemLogService;
}
public Type getType() {
return type;
}
public void releasePacket(Packet packet) {
packetQueue.offer(packet);
}
public Packet obtainPacket() {
Packet packet = packetQueue.poll();
if (packet == null) {
packet = new Packet();
} else {
packet.reset();
}
return packet;
}
public ConnectionManager getConnectionManager() {
return connectionManager;
}
public enum Type {
NONE(false, false),
MEMBER(true, true),
CLIENT(false, true),
REST_CLIENT(false, false),
MEMCACHE_CLIENT(false, false);
final boolean member;
final boolean binary;
Type(boolean member, boolean binary) {
this.member = member;
this.binary = binary;
}
public boolean isBinary() {
return binary;
}
public boolean isClient() {
return !member;
}
}
public boolean isClient() {
return (type != null) && type != Type.NONE && type.isClient();
}
public void setType(Type type) {
if (this.type == Type.NONE) {
this.type = type;
}
}
public SocketChannelWrapper getSocketChannelWrapper() {
return socketChannel;
}
public ReadHandler getReadHandler() {
return readHandler;
}
public WriteHandler getWriteHandler() {
return writeHandler;
}
public InOutSelector getInOutSelector() {
return inOutSelector;
}
public boolean live() {
return live;
}
public Address getEndPoint() {
return endPoint;
}
public void setEndPoint(Address endPoint) {
this.endPoint = endPoint;
}
public void setMonitor(ConnectionMonitor monitor) {
this.monitor = monitor;
}
public ConnectionMonitor getMonitor() {
return monitor;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Connection)) return false;
Connection that = (Connection) o;
return connectionId == that.getConnectionId();
}
@Override
public int hashCode() {
return connectionId;
}
public void close0() throws IOException {
if (!live)
return;
live = false;
if (socketChannel != null && socketChannel.isOpen()) {
socketChannel.close();
}
readHandler.shutdown();
writeHandler.shutdown();
}
public void close() {
close(null);
}
public void close(Throwable t) {
try {
close0();
} catch (Exception e) {
logger.log(Level.WARNING, e.getMessage(), e);
}
Object connAddress = (endPoint == null) ? socketChannel.socket().getRemoteSocketAddress() : endPoint;
String message = "Connection [" + connAddress + "] lost. Reason: ";
if (t != null) {
message += t.getClass().getName() + "[" + t.getMessage() + "]";
} else {
message += "Explicit close";
}
logger.log(Level.INFO, message);
systemLogService.logConnection(message);
connectionManager.destroyConnection(this);
connectionManager.ioService.disconnectExistingCalls(endPoint);
if (t != null && monitor != null) {
monitor.onError(t);
}
}
public int getConnectionId() {
return connectionId;
}
@Override
public String toString() {
final Socket socket = this.socketChannel.socket();
final SocketAddress remoteSocketAddress = socket != null ? socket.getRemoteSocketAddress() : null;
return "Connection [" + remoteSocketAddress + " -> " + endPoint + "] live=" + live + ", client=" + isClient() + ", type=" + type;
}
}