001package ca.uhn.hl7v2.hoh.relay.listener;
002
003import java.util.ArrayList;
004import java.util.List;
005import java.util.concurrent.Executors;
006import java.util.concurrent.ThreadFactory;
007import java.util.concurrent.atomic.AtomicInteger;
008
009import org.springframework.beans.factory.BeanNameAware;
010import org.springframework.beans.factory.DisposableBean;
011import org.springframework.beans.factory.InitializingBean;
012
013import ca.uhn.hl7v2.DefaultHapiContext;
014import ca.uhn.hl7v2.app.SimpleServer;
015import ca.uhn.hl7v2.hoh.util.Validate;
016import ca.uhn.hl7v2.llp.MinLowerLayerProtocol;
017import ca.uhn.hl7v2.parser.GenericModelClassFactory;
018import ca.uhn.hl7v2.protocol.ApplicationRouter.AppRoutingData;
019import ca.uhn.hl7v2.protocol.ReceivingApplication;
020import ca.uhn.hl7v2.util.StandardSocketFactory;
021
022public class RelayMllpListener implements InitializingBean, DisposableBean, IRelayListener, BeanNameAware {
023
024        private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RelayMllpListener.class);
025        private List<ReceivingApplication> myApplications = new ArrayList<ReceivingApplication>();
026        private List<AppRoutingData> myAppRoutingData = new ArrayList<AppRoutingData>();
027        private String myBeanName;
028        private int myPort;
029        private SimpleServer myServer;
030        private AtomicInteger threadNum = new AtomicInteger(1);
031        private DefaultHapiContext myContext;
032
033        /**
034         * Fired automatically by the container when
035         * the bean is ready to start
036         */
037        public void afterPropertiesSet() throws Exception {
038                if (myPort <= 0) {
039                        throw new IllegalStateException("Port not set");
040                }
041                
042                myContext = new DefaultHapiContext();
043                StandardSocketFactory socketFactory = new StandardSocketFactory();
044                socketFactory.setAcceptedSocketTimeout(2000);
045                myContext.setSocketFactory(socketFactory);
046                myContext.setExecutorService(Executors.newCachedThreadPool(new MyThreadFactory()));
047                myContext.setLowerLayerProtocol(new MinLowerLayerProtocol(true));
048                myContext.setModelClassFactory(new GenericModelClassFactory());
049                myServer = myContext.newServer(myPort, false);
050
051                for (int i = 0; i < myAppRoutingData.size(); i++) {
052                        myServer.registerApplication(myAppRoutingData.get(i), myApplications.get(i));
053                }
054                
055                ourLog.info("Starting listener on port {}", myPort);
056                myServer.startAndWait();
057                ourLog.info("Listener on port {} has started, and is ready for processing", myPort);
058
059                if (myServer.getServiceExitedWithException() != null) {
060                        Throwable ex = myServer.getServiceExitedWithException();
061                        ourLog.error("Server failed to start", ex);
062                        if (ex instanceof Exception) {
063                                throw (Exception) ex;
064                        } else {
065                                throw new Error(ex);
066                        }
067                }
068
069        }
070
071        
072        /**
073         * Fired automatically by the container when
074         * the bean is shutting down
075         */
076        public void destroy() throws Exception {
077                ourLog.info("Stopping listener on port {}", myPort);
078                myServer.stopAndWait();
079                ourLog.info("Listener on port {} has stopped", myPort);
080                
081                ourLog.info("Closing HAPI Context Object");
082                myContext.close();
083                ourLog.info("Done closing HAPI Context object");
084        }
085
086        public String getBeanName() {
087                return myBeanName;
088        }
089
090
091        public void registerApplication(AppRoutingData theAppRouting, ReceivingApplication theReceivingApplication) {
092                Validate.notNull(theAppRouting, "appRouting");
093                Validate.notNull(theReceivingApplication, "receivingApplication");
094                
095                if (myServer != null) {
096                        myServer.registerApplication(theAppRouting, theReceivingApplication);
097                } else {
098                        myAppRoutingData.add(theAppRouting);
099                        myApplications.add(theReceivingApplication);
100                }
101        }
102
103
104        public void setBeanName(String theBeanName) {
105                myBeanName = theBeanName;
106        }
107
108        public void setPort(int thePort) {
109                myPort = thePort;
110        }
111
112        private class MyThreadFactory implements ThreadFactory {
113
114                private ThreadGroup group;
115
116                private MyThreadFactory() {
117                        group = Thread.currentThread().getThreadGroup();
118                }
119
120                public Thread newThread(Runnable theR) {
121                        String name = "hoh-port-" + myPort + "-worker-" + threadNum.getAndIncrement();
122                        Thread t = new Thread(group, theR, name, 0);
123                        if (t.isDaemon()) {
124                                t.setDaemon(false);
125                        }
126                        if (t.getPriority() != Thread.NORM_PRIORITY) {
127                                t.setPriority(Thread.NORM_PRIORITY);
128                        }
129                        return t;
130                }
131
132        }
133
134
135}