/** * This file is part of Waarp Project. * * Copyright 2009, Frederic Bregier, and individual contributors by the @author tags. See the * COPYRIGHT.txt in the distribution for a full listing of individual contributors. * * All Waarp Project is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * Waarp 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 * Public License for more details. * * You should have received a copy of the GNU General Public License along with Waarp . If not, see * <http://www.gnu.org/licenses/>. */ package org.waarp.openr66.protocol.networkhandler; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.ArrayList; import io.netty.channel.Channel; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.util.internal.ConcurrentSet; import org.waarp.common.future.WaarpLock; import org.waarp.common.logging.WaarpLogger; import org.waarp.common.logging.WaarpLoggerFactory; import org.waarp.openr66.context.ErrorCode; import org.waarp.openr66.context.R66Result; import org.waarp.openr66.context.task.exception.OpenR66RunnerErrorException; import org.waarp.openr66.protocol.configuration.Configuration; import org.waarp.openr66.protocol.exception.OpenR66ProtocolRemoteShutdownException; import org.waarp.openr66.protocol.exception.OpenR66ProtocolSystemException; import org.waarp.openr66.protocol.localhandler.LocalChannelReference; /** * NetworkChannelReference object to keep Network channel open while some local channels are attached to it. * * @author Frederic Bregier * */ public class NetworkChannelReference { /** * Internal Logger */ protected static final WaarpLogger logger = WaarpLoggerFactory.getLogger(NetworkChannelReference.class); /** * Does this Network Channel is in shutdown */ protected volatile boolean isShuttingDown = false; /** * Associated LocalChannelReference */ private final ConcurrentSet<LocalChannelReference> localChannelReferences = new ConcurrentSet<LocalChannelReference>(); /** * Group for all Local Channels */ private final ChannelGroup localChannels; /** * Network Channel */ protected final Channel channel; /** * Remote network address (when valid) */ protected final SocketAddress networkAddress; /** * Remote IP address */ private final String hostAddress; /** * Remote Host Id */ private String hostId; /** * ClientNetworkChannels object that contains this NetworkChannelReference */ protected ClientNetworkChannels clientNetworkChannels; /** * Associated lock */ protected final WaarpLock lock; /** * Last Time in ms this channel was used by a LocalChannel */ private long lastTimeUsed = System.currentTimeMillis(); public NetworkChannelReference(Channel networkChannel, WaarpLock lock) { this.channel = networkChannel; this.networkAddress = channel.remoteAddress(); this.hostAddress = ((InetSocketAddress) this.networkAddress).getAddress().getHostAddress(); this.lock = lock; localChannels = new DefaultChannelGroup(Configuration.configuration.getSubTaskGroup().next()); } public NetworkChannelReference(SocketAddress address, WaarpLock lock) { this.channel = null; this.networkAddress = address; this.hostAddress = ((InetSocketAddress) this.networkAddress).getAddress().getHostAddress(); this.lock = lock; localChannels = new DefaultChannelGroup(Configuration.configuration.getSubTaskGroup().next()); } public void add(LocalChannelReference localChannel) throws OpenR66ProtocolRemoteShutdownException { // lock is of no use since caller is itself in locked situation for the very same lock if (isShuttingDown) { throw new OpenR66ProtocolRemoteShutdownException("Current NetworkChannelReference is closed"); } use(); localChannelReferences.add(localChannel); localChannels.add(localChannel.getLocalChannel()); } /** * To set the last time used */ public void use() { if (!isShuttingDown) { lastTimeUsed = System.currentTimeMillis(); } } /** * To set the last time used when correct * * @return True if last time used is set */ public boolean useIfUsed() { if (!isShuttingDown && !localChannelReferences.isEmpty()) { lastTimeUsed = System.currentTimeMillis(); return true; } return false; } /** * Remove one LocalChanelReference, closing it if necessary. * * @param localChannel */ public void remove(LocalChannelReference localChannel) { if (localChannel.getLocalChannel().isActive()) { localChannel.getLocalChannel().close(); } localChannelReferences.remove(localChannel); //Do not since it prevents shutdown: lastTimeUsed = System.currentTimeMillis(); } /** * Shutdown All Local Channels associated with this NCR */ public void shutdownAllLocalChannels() { isShuttingDown = true; LocalChannelReference[] localChannelReferenceArray = localChannelReferences .toArray(new LocalChannelReference[0]); ArrayList<LocalChannelReference> toCloseLater = new ArrayList<LocalChannelReference>(); for (LocalChannelReference localChannelReference : localChannelReferenceArray) { if (!localChannelReference.getFutureRequest().isDone()) { if (localChannelReference.getFutureValidRequest().isDone() && localChannelReference.getFutureValidRequest().isFailed()) { toCloseLater.add(localChannelReference); continue; } else { R66Result finalValue = new R66Result( localChannelReference.getSession(), true, ErrorCode.Shutdown, null); if (localChannelReference.getSession() != null) { try { localChannelReference.getSession().tryFinalizeRequest(finalValue); } catch (OpenR66RunnerErrorException e) { } catch (OpenR66ProtocolSystemException e) { } } } } localChannelReference.getLocalChannel().close(); } try { Thread.sleep(Configuration.WAITFORNETOP); } catch (InterruptedException e) { } for (LocalChannelReference localChannelReference : toCloseLater) { localChannelReference.getLocalChannel().close(); } toCloseLater.clear(); } public int nbLocalChannels() { return localChannelReferences.size(); } @Override public String toString() { return "NC: " + hostId + ":" + (channel != null ? channel.isActive() : false) + " " + networkAddress + " Count: " + localChannelReferences.size(); } @Override public boolean equals(Object obj) { if (obj instanceof NetworkChannelReference) { NetworkChannelReference obj2 = (NetworkChannelReference) obj; if (obj2.channel == null || this.channel == null) { return false; } return (obj2.channel.id().compareTo(this.channel.id()) == 0); } return false; } @Override public int hashCode() { if (this.channel == null) { return Integer.MIN_VALUE; } return this.channel.id().hashCode(); } /** * * @return the hashcode for the global remote networkaddress */ public int getSocketHashCode() { return this.networkAddress.hashCode(); } /** * Used for BlackList * * @return the hashcode for the address */ public int getAddressHashCode() { return this.hostAddress.hashCode(); } /** * Check if the last time used is ok with a delay applied to the current time (timeout) * * @param delay * @return <= 0 if OK, else > 0 (should send a KeepAlive or wait that time in ms) */ public long checkLastTime(long delay) { return (lastTimeUsed + delay - System.currentTimeMillis()); } /** * @return the isShuttingDown */ public boolean isShuttingDown() { return isShuttingDown; } /** * @return the channel */ public Channel channel() { return channel; } /** * @return the hostId */ public String getHostId() { return hostId; } /** * @param hostId * the hostId to set */ public void setHostId(String hostId) { this.hostId = hostId; } /** * @return the lock */ public WaarpLock getLock() { return lock; } /** * @return the lastTimeUsed */ public long getLastTimeUsed() { return lastTimeUsed; } }