package org.wso2.carbon.inbound.endpoint.protocol.hl7.core; /** * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you 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. */ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.impl.nio.reactor.DefaultListeningIOReactor; import org.apache.http.impl.nio.reactor.IOReactorConfig; import org.apache.http.nio.reactor.IOReactorStatus; import org.apache.http.nio.reactor.ListenerEndpoint; import org.apache.http.nio.reactor.ListeningIOReactor; import org.wso2.carbon.inbound.endpoint.protocol.hl7.util.HL7Configuration; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.SocketAddress; import java.util.concurrent.ConcurrentHashMap; public class InboundHL7IOReactor { private static final Log log = LogFactory.getLog(InboundHL7IOReactor.class); private static ListeningIOReactor reactor; private static ConcurrentHashMap<Integer, ListenerEndpoint> endpointMap = new ConcurrentHashMap<Integer, ListenerEndpoint>(); private static ConcurrentHashMap<Integer, HL7Processor> processorMap = new ConcurrentHashMap<Integer, HL7Processor>(); private static MultiIOHandler multiIOHandler; private static volatile boolean isStarted = false; public static void start() throws IOException { if (reactor != null && reactor.getStatus().equals(IOReactorStatus.ACTIVE)) { return; } IOReactorConfig config = getDefaultReactorConfig(); reactor = new DefaultListeningIOReactor(config); Thread reactorThread = new Thread(new Runnable() { @Override public void run() { try { isStarted = true; multiIOHandler = new MultiIOHandler(processorMap); log.info("MLLP Transport IO Reactor Started"); reactor.execute(multiIOHandler); } catch (IOException e) { isStarted = false; log.error("Error while starting the MLLP Transport IO Reactor.", e); } } }); reactorThread.start(); } public static void stop() { try { reactor.shutdown(); endpointMap.clear(); isStarted = false; } catch (IOException e) { log.error("Error while shutting down MLLP Transport IO Reactor. ", e); } } public static void pause() { try { reactor.pause(); } catch (IOException e) { log.error("Error while pausing MLLP Transport IO Reactor. ", e); } } public static boolean isStarted() { return isStarted; } public static boolean bind(int port, HL7Processor processor) { checkReactor(); if (!isPortAvailable(port)) { log.error("A service is already listening on port " + port + ". Please select a different port for this endpoint."); return false; } ListenerEndpoint ep = reactor.listen(getSocketAddress(port)); try { ep.waitFor(); endpointMap.put(port, ep); processorMap.put(port, processor); return true; } catch (InterruptedException e) { log.error("Error while starting a new MLLP Listener on port " + port + ". ", e); return false; } } private static boolean isPortAvailable(int port) { try { ServerSocket ss = new ServerSocket(port); ss.close(); return true; } catch (IOException e) { return false; } } public static boolean unbind(int port) { ListenerEndpoint ep = endpointMap.get(port); endpointMap.remove(port); processorMap.remove(port); multiIOHandler.disconnectSessions(port); if (ep == null) { return false; } ep.close(); return true; } /** * In certain cases, reactor is not started prior to a bind() (e.g. if HL7EndpointManager triggers a bind() i.e. * via tenant loader and at that time no InboundListeners were initialized). If the reactor is not started, this * method will start it. */ protected static void checkReactor() { if (reactor == null) { try { start(); } catch (IOException e) { log.error("Reactor failed to start."); } } } public static boolean isEndpointRunning(int port) { return endpointMap.get(port) != null; } private static SocketAddress getSocketAddress(int port) { InetSocketAddress isa = new InetSocketAddress(port); return isa; } private static IOReactorConfig getDefaultReactorConfig() { IOReactorConfig.Builder builder = IOReactorConfig.custom(); return builder .setSelectInterval(HL7Configuration.getInstance().getIntProperty( MLLPConstants.TCPConstants.SELECT_INTERVAL, 1000)) .setShutdownGracePeriod(HL7Configuration.getInstance().getIntProperty( MLLPConstants.TCPConstants.SHUTDOWN_GRACE_PERIOD, 500)) .setIoThreadCount(HL7Configuration.getInstance().getIntProperty( MLLPConstants.TCPConstants.IO_THREAD_COUNT, Runtime.getRuntime().availableProcessors())) .setSoTimeout(HL7Configuration.getInstance().getIntProperty( MLLPConstants.TCPConstants.SO_TIMEOUT, 0)) .setSoKeepAlive(HL7Configuration.getInstance().getBooleanProperty( MLLPConstants.TCPConstants.SO_KEEP_ALIVE, true)) .setTcpNoDelay(HL7Configuration.getInstance().getBooleanProperty( MLLPConstants.TCPConstants.TCP_NO_DELAY, true)) .setConnectTimeout(HL7Configuration.getInstance().getIntProperty( MLLPConstants.TCPConstants.CONNECT_TIMEOUT, 0)) .setRcvBufSize(HL7Configuration.getInstance().getIntProperty( MLLPConstants.TCPConstants.SO_RCVBUF, 0)) .setSndBufSize(HL7Configuration.getInstance().getIntProperty( MLLPConstants.TCPConstants.SO_SNDBUF, 0)) .setInterestOpQueued(false) .setSoReuseAddress(true) .setSoLinger(-1) .build(); } }