001/**
002 * The contents of this file are subject to the Mozilla Public License Version 1.1
003 * (the "License"); you may not use this file except in compliance with the License.
004 * You may obtain a copy of the License at http://www.mozilla.org/MPL/
005 * Software distributed under the License is distributed on an "AS IS" basis,
006 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
007 * specific language governing rights and limitations under the License.
008 *
009 * The Original Code is "Receiver.java".  Description:
010 * "Listens for incoming messages on a certain input stream, and
011 * sends them to the appropriate location."
012 *
013 * The Initial Developer of the Original Code is University Health Network. Copyright (C)
014 * 2002.  All Rights Reserved.
015 *
016 * Contributor(s): _____________.
017 *
018 * Alternatively, the contents of this file may be used under the terms of the
019 * GNU General Public License (the  ?GPL?), in which case the provisions of the GPL are
020 * applicable instead of those above.  If you wish to allow use of your version of this
021 * file only under the terms of the GPL and not to allow others to use your version
022 * of this file under the MPL, indicate your decision by deleting  the provisions above
023 * and replace  them with the notice and other provisions required by the GPL License.
024 * If you do not delete the provisions above, a recipient may use your version of
025 * this file under either the MPL or the GPL.
026 */
027package ca.uhn.hl7v2.app;
028
029import java.util.HashMap;
030import java.util.Map;
031
032import org.slf4j.Logger;
033import org.slf4j.LoggerFactory;
034
035import ca.uhn.hl7v2.HL7Exception;
036import ca.uhn.hl7v2.model.Message;
037import ca.uhn.hl7v2.protocol.ApplicationRouter;
038import ca.uhn.hl7v2.util.Terser;
039
040/**
041 * Routes messages to various Applications based on message type and trigger
042 * event. The router is told which Application to which to route various
043 * messages by calling the method <code>registerApplication(...)</code>.
044 * 
045 * @author Bryan Tripp
046 * @deprecated Replaced with {@link ApplicationRouter}
047 */
048public class MessageTypeRouter implements Application,
049                ApplicationExceptionHandler {
050
051        private static final Logger log = LoggerFactory
052                        .getLogger(MessageTypeRouter.class);
053        private Map<String, Application> apps;
054
055        /** Creates a new instance of MessageTypeRouter */
056        public MessageTypeRouter() {
057                apps = new HashMap<String, Application>(20);
058        }
059
060        /**
061         * Returns true if at least one application has been registered to accept
062         * this type of message. Applications are registered using
063         * <code>registerApplication(...)</code>.
064         */
065        public boolean canProcess(Message in) {
066                try {
067                        Application match = getMatchingApplication(in);
068                        return match != null && match.canProcess(in);
069                } catch (Exception e) {
070                        return false;
071                }
072        }
073
074        /**
075         * Forwards the given message to any Applications that have been registered
076         * to accept messages of that type and trigger event.
077         * 
078         * @throws ApplicationException
079         *             if no such Applications are registered, or if the underlying
080         *             Application throws this exception during processing.
081         */
082        public Message processMessage(Message in) throws ApplicationException {
083                try {
084                        Application matchingApp = this.getMatchingApplication(in);
085                        return matchingApp.processMessage(in);
086                } catch (HL7Exception e) {
087                        throw new ApplicationException("Error internally routing message: "
088                                        + e.toString(), e);
089                }
090        }
091
092        /**
093         * Forwards the given exception to all Applications.
094     * TODO this may call itself leading to infinite loops
095         */
096        public String processException(String incomingMessage,
097                        String outgoingMessage, Exception e) throws HL7Exception {
098                String outgoingMessageResult = outgoingMessage;
099                for (Application app : apps.values()) {
100                        if (app instanceof ApplicationExceptionHandler) {
101                                ApplicationExceptionHandler aeh = (ApplicationExceptionHandler) app;
102                                outgoingMessageResult = aeh.processException(incomingMessage,
103                                                outgoingMessageResult, e);
104                        }
105                }
106                return outgoingMessageResult;
107        }
108
109        /**
110         * Registers the given application to handle messages corresponding to the
111         * given type and trigger event. Only one application can be registered for
112         * a given message type and trigger event combination. A repeated
113         * registration for a particular combination of type and trigger event
114         * over-writes the previous one. Use "*" as a wildcard (e.g.
115         * registerApplication("ADT", "*", myApp) would register your app for all
116         * ADT messages).
117         */
118        public synchronized void registerApplication(String messageType,
119                        String triggerEvent, Application handler) {
120                this.apps.put(getKey(messageType, triggerEvent), handler);
121                log.info("{} registered to handle {}^{} messages", new Object[] {
122                                handler.getClass().getName(), messageType, triggerEvent });
123        }
124
125        /**
126         * Returns the Applications that has been registered to handle messages of
127         * the type and trigger event of the given message, or null if there are
128         * none.
129         */
130        private Application getMatchingApplication(Message message)
131                        throws HL7Exception {
132                Terser t = new Terser(message);
133                String messageType = t.get("/MSH-9-1");
134                String triggerEvent = t.get("/MSH-9-2");
135                return this.getMatchingApplication(messageType, triggerEvent);
136        }
137
138        /**
139         * Returns the Applications that has been registered to handle messages of
140         * the given type and trigger event, or null if there are none. If there is
141         * not an exact match, wildcards ("*") are tried as well.
142         */
143        private synchronized Application getMatchingApplication(String messageType,
144                        String triggerEvent) {
145                Application matchingApp = null;
146                Application o = this.apps.get(getKey(messageType, triggerEvent));
147                if (o == null)
148                        o = this.apps.get(getKey(messageType, "*"));
149                if (o == null)
150                        o = this.apps.get(getKey("*", triggerEvent));
151                if (o == null)
152                        o = this.apps.get(getKey("*", "*"));
153                if (o != null)
154                        matchingApp = o;
155                return matchingApp;
156        }
157
158        /**
159         * Creates reproducible hash key.
160         */
161        private String getKey(String messageType, String triggerEvent) {
162                // create hash key string by concatenating type and trigger event
163                return messageType + "|" + triggerEvent;
164        }
165
166}