/*
@see com.ibm.wsspi.channelfw.ChannelFramework#stopChain(String, long)
490081
@Override
    public synchronized void stopChain(String chainName, long millisec) throws ChannelException, ChainException {
        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
            Tr.entry(tc, "stopChain: " + chainName + " time=" + millisec);
        }
        if (null == chainName) {
            throw new InvalidChainNameException("Null chain name");
        }
        if (millisec < 0) {
            throw new ChainTimerException("Invalid time length give to stopChain, " + millisec);
        }

        // Verify the chain is found in the runtime.
        Chain chain = getRunningChain(chainName);
        if (null == chain) {
            // Due to timing windows (i.e. multiple channel providers going away), there is
            // a race to stop chains. This is not a notable condition: the chain can only be stopped
            // once.
            if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
                Tr.exit(tc, "stopChain " + chainName, "chain is not running");
            }
            return;
        }

        // Ensure we have an inbound chain.
        if (FlowType.OUTBOUND.equals(chain.getChainData().getType())) {
            throw new InvalidChainNameException("Outbound chain cannot use this interface.");
        }

        stopChainInternal(chain, millisec);

        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
            Tr.exit(tc, "stopChain");
        }
    }
1106391
public void addChain(ChainData newChain) throws ChainException {
        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
            Tr.entry(tc, "addChain: " + newChain.getName());
        }

        if (containsChain(newChain.getName())) {
            ChainException e = new ChainException("Chain already exists: " + newChain.getName());
            FFDCFilter.processException(e, getClass().getName() + ".addChain", "116", this, new Object[] { newChain });
            throw e;
        }

        // Create a chain array that is one element bigger than the current one.
        int currentLength = this.chainArray.length;
        ChainData[] newChains = new ChainData[currentLength + 1];
        // Copy the existing elements to the new array.
        System.arraycopy(getChains(), 0, newChains, 0, currentLength);
        // Add the new chain to the end of the new list.
        newChains[currentLength] = newChain;
        // Update this group's chain list
        setChains(newChains);
        // Add all group listeners to this chain. If some already exist,
        // this doesn't break anything.
        for (ChainEventListener listener : getChainEventListeners()) {
            ((ChainDataImpl) newChain).addChainEventListener(listener);
        }

        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
            Tr.exit(tc, "addChain");
        }
    }
749852
public void stop(long millisec) {
        if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
            Tr.debug(tc, "Stopping (" + millisec + ") : " + this);
        }
        if (0 == millisec) {
            setState(STATE_STOPPED);
        } else {
            setState(STATE_STOPPING);
        }
    }
324497
@Override
    protected void stopInner() {
        /*
         * TODO REST-Server Need to handle inflight operations. What happens to
         * the existing async operations when a channel.close() is issued in
         * Netty?
         */
        if(this.nettyServerChannel != null) {
            this.nettyServerChannel.close();
        }

        if(allChannels != null) {
            allChannels.close().awaitUninterruptibly();
        }
        this.bootstrap.releaseExternalResources();
    }
775968
public ChannelFuture close(Channel channel, CloseWebSocketFrame frame) {
        if (channel == null) {
            throw new NullPointerException("channel");
        }
        return close(channel, frame, channel.newPromise());
    }
1257120
@Override
    public void start() throws ChannelException {
        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
            Tr.entry(tc, "start");
        }

        stop0Called = false;

        try {
            // If this is an inbound channel, we can pull out the listening host/port/endpointName.
            if (getConfig().isInbound()) {
                // Get access to the ChainData object for future use.
                ChainData chainData = SSLChannelProvider.getCfw().getInternalRunningChains(getConfig().getName())[0];
                ChannelData channelData = chainData.getChannelList()[0];
                Map<?, ?> channelProperties = channelData.getPropertyBag();
                this.inboundHost = (String) channelProperties.get("hostname");
                this.inboundPort = (String) channelProperties.get("port");
                // End point name will only ever get a value when running in was. Otherwise, null is fine.
                this.endPointName = (String) channelProperties.get("endPointName");
                if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                    Tr.debug(tc, "inboundHost = " + this.inboundHost
                                 + " inboundPort = " + this.inboundPort
                                 + " endPointName = " + this.endPointName);

                }
            }
        } catch (Exception e) {
            // no FFDC required
            if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                Tr.debug(tc, "Caught exception during start, throwing up stack.  " + e);
            }
            throw new ChannelException(e);
        }

        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
            Tr.exit(tc, "start");
        }
    }
873331
@Override
    public synchronized void removeChainEventListener(ChainEventListener cel, String chainName) throws InvalidChainNameException {
        if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
            Tr.debug(tc, "removeChainEventListener: chainName=" + chainName + " listener=" + cel);
        }
        ChainDataImpl chainData = null;
        if (null == chainName) {
            InvalidChainNameException e = new InvalidChainNameException("Unregister listener for null chain name");
            //Race condition can occur where chain is stopped before we register the listener, no need to FFDC
            //FFDCFilter.processException(e, getClass().getName() + ".addChainEventListener", "2910", this, new Object[] { chainName, this });
            throw e;
        }

        // Handle a listener unregistering for events from all chains.
        if (chainName.equals(ChainEventListener.ALL_CHAINS)) {
            for (ChainData chain : this.chainDataMap.values()) {
                ((ChainDataImpl) chain).removeChainEventListener(cel);
            }
            this.globalChainEventListeners.remove(cel);
        } else {
            // Extract the chain config from the framework.
            chainData = this.chainDataMap.get(chainName);
            // Verify the chain config is in the framework.
            if (null == chainData) {
                InvalidChainNameException e = new InvalidChainNameException("Unable to unregister listener for unknown chain config, " + chainName);
                FFDCFilter.processException(e, getClass().getName() + ".removeChainEventListener", "2948", this, new Object[] { chainName, this });
                throw e;
            } else if (globalChainEventListeners.contains(cel)) {
                // Can't remove a global listener from individual chains
                InvalidChainNameException e = new InvalidChainNameException("Can't remove a global listener from individual chains, " + chainName);
                FFDCFilter.processException(e, getClass().getName() + ".removeChainEventListener", "2953", this, new Object[] { chainName, this });
                throw e;
            }
            chainData.removeChainEventListener(cel);
        }
    }
628299
@Override
    public void handleEvent(Event event) {
        String topic = event.getTopic();
        if (topic.equalsIgnoreCase(ChannelFramework.EVENT_STOPCHAIN.getName())) {
            String chainName = event.getProperty(ChannelFramework.EVENT_CHAINNAME, String.class);
            if (null != chainName) {
                stopChain(chainName, event);
            } else {
                String channelName = event.getProperty(ChannelFramework.EVENT_CHANNELNAME, String.class);
                if (null != channelName) {
                    stopChannel(channelName, event);
                }
            }
        } else if (topic.equalsIgnoreCase(EVENT_CHECK_MISSING.getName())) {
            ChannelUtils.checkMissingConfig();
        }
    }
645962
@Override
    public synchronized ChannelData removeChannel(String channelName) throws ChannelException, ChainException {
        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
            Tr.entry(tc, "removeChannel: " + channelName);
        }
        if (null == channelName) {
            throw new InvalidChannelNameException("Input channel name is null");
        }

        // Fetch the channel data from the framework.
        ChannelDataImpl channelData = (ChannelDataImpl) channelDataMap.get(channelName);
        if (null == channelData) {
            if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
                // Due to timing windows (i.e. multiple channel providers going away), there is
                // a race to stop and/or clean up chains. This is not a notable condition: the chain can only be removed
                // once.
                Tr.exit(tc, "removeChannel: " + channelName, "Channel not found");
            }
            return null;
        }

        // Channel configs can only be removed if they are not in use by the
        // runtime.
        if (0 != channelData.getNumChildren()) {
            throw new ChannelException("Can't remove channel config " + channelName + " in runtime.  Destroy must happen first. ");
        }

        // Remove the chain config from the framework's map.
        this.channelDataMap.remove(channelName);

        // iterating chain configs will clear out live chains/channelRunningMap
        // Remove any chain configurations that refer to this channel.
        // Get a temp array so we can release the lock needed by removeChain.
        // This isn't a clone, but we should be okay holding the references.
        Object[] chainDataArray = this.chainDataMap.values().toArray();
        ChainDataImpl chainData = null;
        for (int i = 0; i < chainDataArray.length; i++) {
            chainData = (ChainDataImpl) chainDataArray[i];
            if (chainData.containsChannel(channelName)) {
                // Found reference to channel config. Remove chain config.
                // This ripples into the chain groups and cleans them up too.
                removeChain(chainData.getName());
            }
        }

        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
            Tr.exit(tc, "removeChannel");
        }
        return channelData;
    }
481681
public synchronized void shutdown(boolean force) {

        if (shutdown) {
            return;
        }

        String ltransactionListenerProcessorHandle = transactionListenerProcessorHandle;
        transactionListenerProcessorHandle = null;
        if (null != ltransactionListenerProcessorHandle) {

            try {
                unregisterBlockListener(ltransactionListenerProcessorHandle);
            } catch (Exception e) {
                logger.error(format("Shutting down channel %s transactionListenerProcessorHandle", name), e);
            }
        }

        String lchaincodeEventUpgradeListenerHandle = chaincodeEventUpgradeListenerHandle;
        chaincodeEventUpgradeListenerHandle = null;
        if (null != lchaincodeEventUpgradeListenerHandle) {

            try {
                unregisterChaincodeEventListener(lchaincodeEventUpgradeListenerHandle);
            } catch (Exception e) {
                logger.error(format("Shutting down channel %s chaincodeEventUpgradeListenr", name), e);
            }
        }

        initialized = false;
        shutdown = true;

        final ServiceDiscovery lserviceDiscovery = serviceDiscovery;
        serviceDiscovery = null;
        if (null != lserviceDiscovery) {
            lserviceDiscovery.shutdown();
        }

        if (chainCodeListeners != null) {
            chainCodeListeners.clear();

        }

        if (blockListeners != null) {
            blockListeners.clear();
        }

        if (client != null) {
            client.removeChannel(this);
        }

        client = null;

        for (Peer peer : new ArrayList<>(getPeers())) {

            try {
                removePeerInternal(peer);
                peer.shutdown(force);
            } catch (Exception e) {
                // Best effort.
            }
        }
        peers.clear(); // make sure.

        peerEndpointMap.clear();
        ordererEndpointMap.clear();

        //Make sure
        for (Set<Peer> peerRoleSet : peerRoleSetMap.values()) {
            peerRoleSet.clear();
        }

        for (Orderer orderer : getOrderers()) {
            orderer.shutdown(force);
        }

        orderers.clear();

        if (null != eventQueueThread) {
            eventQueueThread.interrupt();
            eventQueueThread = null;
        }
        ScheduledFuture<?> lsweeper = sweeper;
        sweeper = null;

        if (null != lsweeper) {
            lsweeper.cancel(true);
        }

        ScheduledExecutorService lse = sweeperExecutorService;
        sweeperExecutorService = null;
        if (null != lse) {
            lse.shutdownNow();
        }
    }
728207
public Optional<String> stop() {
        final LinkedList<String> uuids = context.get();
        if (!uuids.isEmpty()) {
            return Optional.of(uuids.pop());
        }
        return Optional.empty();
    }
1203296
public void stop(long millisec) throws ChannelException {
        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
            Tr.entry(this, tc, "stop " + millisec + "; " + getName());
        }
        // only stop the channel if millisec is 0, otherwise ignore.
        if (millisec == 0) {
            stoppedFlag = true;

            // Stop accepting new connections on the inbound channels
            if (getConfig().isInboundChannel()) {

                try {
                    Tr.info(tc, "CWUDP0002I", new Object[] { getConfig().getExternalName(), displayableHostName, String.valueOf(getConfig().getPort()) });
                } catch (Exception e) {
                    // just debug,since this is on an audit attempt
                    if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                        Tr.debug(this, tc, "Got exception auditing UDP Channel Stop: " + e);
                    }
                }
            }

            // destroy all the "in use" UDPConnLink. This should close all
            // the sockets held by these connections.
            destroyConnLinks();

        }
        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
            Tr.exit(this, tc, "stop");
        }
    }
464122
final void stop() {

        final String methodName = "stop";
        if (TraceComponent.isAnyTracingEnabled() && TRACE.isEntryEnabled()) {
            SibTr.entry(this, TRACE, methodName);
        }

        try {

            // Make sure we have a session and that it hasn't already been stopped
            // If an MDB is stopped by the system due to messages failing to be delivered 
            // the session will be stopped and the consumerSessionStopped method on the
            // StoppableAsynchConsumerCallback interface on this class will be called.
            // This will cause the _sessionStopped field to be set to true (which indicates
            // that this listener is in the process of shutting down). We do not then 
            // need to call stop again as the session is already stopped. When the MDB is 
            // resumed a new SibRaListener object is created and so we don't need to reset 
            // the _sessionStopped variable.
            if ((_session != null) && (!_sessionStopped))
            {
                sessionStarted = false;
                stopIfRequired();
            }

        } catch (final SIException exception) {

            FFDCFilter.processException(exception, CLASS_NAME + "."
                                                   + methodName, "1:878:1.68", this);
            if (TraceComponent.isAnyTracingEnabled() && TRACE.isEventEnabled()) {
                SibTr.exception(this, TRACE, exception);
            }

        } catch (final SIErrorException exception) {

            FFDCFilter.processException(exception, CLASS_NAME + "."
                                                   + methodName, "1:886:1.68", this);
            if (TraceComponent.isAnyTracingEnabled() && TRACE.isEventEnabled()) {
                SibTr.exception(this, TRACE, exception);
            }

        }

        if (TraceComponent.isAnyTracingEnabled() && TRACE.isEntryEnabled()) {
            SibTr.exit(this, TRACE, methodName);
        }

    }
549264
@Override
    public final synchronized void stopService(long millis) {
        running = false;
        try {
            if (keepRunning) {
                keepRunning = false;
                interrupt();
                quit();
                if (0L == millis) {
                    join();
                } else {
                    join(millis);
                }
            }
        } catch (InterruptedException e) {
            //its possible that the thread exits between the lines keepRunning=false and interrupt above
            log.warn("Got interrupted while stopping {}", this, e);

            Thread.currentThread().interrupt();
        }
    }
428358
private static List<String> loadChains(Map<String, String[]> chains, boolean start, boolean restart) {
        final boolean bTrace = TraceComponent.isAnyTracingEnabled();
        final ChannelFramework cf = ChannelFrameworkFactory.getChannelFramework();
        List<String> createdChains = new ArrayList<String>(chains.size());

        String key, value;
        for (Entry<String, String[]> entry : chains.entrySet()) {
            String chain = entry.getKey();
            FlowType flow = FlowType.INBOUND;
            boolean enable = true;
            boolean missingChannels = false;
            String[] chanList = null;
            for (String prop : entry.getValue()) {
                key = extractKey(prop);
                value = extractValue(prop);
                if ("enable".equalsIgnoreCase(key)) {
                    enable = Boolean.parseBoolean(value);
                } else if ("channels".equalsIgnoreCase(key)) {
                    // parse the channel list
                    chanList = extractList(value, ',');
                    for (String channel : chanList) {
                        if (null == cf.getChannel(channel)) {
                            if (bTrace && tc.isEventEnabled()) {
                                Tr.event(tc, "Chain contains missing channel: " + channel);
                            }
                            chanList = null;
                            missingChannels = true;
                            break; // out of channel check loop
                        }
                    }
                } else if ("flow".equalsIgnoreCase(key)) {
                    flow = "inbound".equalsIgnoreCase(value) ? FlowType.INBOUND : FlowType.OUTBOUND;
                }
            }
            if (null == chanList) {
                // chain either had no channels configured or it has channels
                // that are waiting on their providers
                if (!missingChannels) {
                    if (bTrace && tc.isEventEnabled()) {
                        Tr.event(tc, "Chain had no channels; " + chain);
                    }
                    continue;
                }
                if (bTrace && tc.isEventEnabled()) {
                    Tr.event(tc, "Delay; chain missing channels; " + chain);
                }
                if (start) {
                    delayedStarts.put(chain, Boolean.valueOf(restart));
                }
                delayedConfig.put(CHAIN_PREFIX + chain, entry.getValue());
                createdChains.add(chain);
                continue;
            }
            try {
                ChainData cd = cf.getChain(chain);
                if (null == cd) {
                    cd = cf.addChain(chain, flow, chanList);
                } else {
                    cd = cf.updateChain(chain, chanList);
                }
                cd.setEnabled(enable);
                createdChains.add(chain);
            } catch (Exception e) {
                FFDCFilter.processException(e, "ChannelUtils.loadChains",
                                            "create", new Object[] { entry, cf });
                if (bTrace && tc.isEventEnabled()) {
                    Tr.event(tc, "Unable to add chain " + chain + "; " + e);
                }
            }
        } // end-chains

        return createdChains;
    }
326353
public void stop(long millisec) {
        // PK12235, more specific states
        if (0 == millisec) {
            // immediate hard stop
            setState(STATE_STOPPED);
        } else {
            setState(STATE_STOPPING);
        }
        if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) {
            Tr.event(tc, "Stop: " + this);
        }
    }
691020
public StopChannelResult withTags(java.util.Map<String, String> tags) {
        setTags(tags);
        return this;
    }