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 */
027 package ca.uhn.hl7v2.app;
028
029 import java.util.HashMap;
030 import java.util.Map;
031
032 import org.slf4j.Logger;
033 import org.slf4j.LoggerFactory;
034
035 import ca.uhn.hl7v2.HL7Exception;
036 import ca.uhn.hl7v2.model.Message;
037 import ca.uhn.hl7v2.util.Terser;
038
039 /**
040 * Routes messages to various Applications based on message type and trigger
041 * event. The router is told which Application to which to route various
042 * messages by calling the method <code>registerApplication(...)</code>.
043 *
044 * @author Bryan Tripp
045 */
046 public class MessageTypeRouter implements Application,
047 ApplicationExceptionHandler {
048
049 private static final Logger log = LoggerFactory
050 .getLogger(MessageTypeRouter.class);
051 private Map<String, Application> apps;
052
053 /** Creates a new instance of MessageTypeRouter */
054 public MessageTypeRouter() {
055 apps = new HashMap<String, Application>(20);
056 }
057
058 /**
059 * Returns true if at least one application has been registered to accept
060 * this type of message. Applications are registered using
061 * <code>registerApplication(...)</code>.
062 */
063 public boolean canProcess(Message in) {
064 try {
065 Application match = getMatchingApplication(in);
066 return match != null ? match.canProcess(in) : false;
067 } catch (Exception e) {
068 return false;
069 }
070 }
071
072 /**
073 * Forwards the given message to any Applications that have been registered
074 * to accept messages of that type and trigger event.
075 *
076 * @throws ApplicationException
077 * if no such Applications are registered, or if the underlying
078 * Application throws this exception during processing.
079 */
080 public Message processMessage(Message in) throws ApplicationException {
081 Message out;
082 try {
083 Application matchingApp = this.getMatchingApplication(in);
084 out = matchingApp.processMessage(in);
085 } catch (HL7Exception e) {
086 throw new ApplicationException("Error internally routing message: "
087 + e.toString(), e);
088 }
089 return out;
090 }
091
092 /**
093 * Forwards the given exception to all Applications.
094 */
095 public String processException(String incomingMessage,
096 String outgoingMessage, Exception e) throws HL7Exception {
097 String outgoingMessageResult = outgoingMessage;
098 for (Application app : apps.values()) {
099 if (app instanceof ApplicationExceptionHandler) {
100 ApplicationExceptionHandler aeh = (ApplicationExceptionHandler) app;
101 outgoingMessageResult = aeh.processException(incomingMessage,
102 outgoingMessageResult, e);
103 }
104 }
105 return outgoingMessageResult;
106 }
107
108 /**
109 * Registers the given application to handle messages corresponding to the
110 * given type and trigger event. Only one application can be registered for
111 * a given message type and trigger event combination. A repeated
112 * registration for a particular combination of type and trigger event
113 * over-writes the previous one. Use "*" as a wildcard (e.g.
114 * registerApplication("ADT", "*", myApp) would register your app for all
115 * ADT messages).
116 */
117 public synchronized void registerApplication(String messageType,
118 String triggerEvent, Application handler) {
119 this.apps.put(getKey(messageType, triggerEvent), handler);
120 log.info("{} registered to handle {}^{} messages", new Object[] {
121 handler.getClass().getName(), messageType, triggerEvent });
122 }
123
124 /**
125 * Returns the Applications that has been registered to handle messages of
126 * the type and trigger event of the given message, or null if there are
127 * none.
128 */
129 private Application getMatchingApplication(Message message)
130 throws HL7Exception {
131 Terser t = new Terser(message);
132 String messageType = t.get("/MSH-9-1");
133 String triggerEvent = t.get("/MSH-9-2");
134 return this.getMatchingApplication(messageType, triggerEvent);
135 }
136
137 /**
138 * Returns the Applications that has been registered to handle messages of
139 * the given type and trigger event, or null if there are none. If there is
140 * not an exact match, wildcards ("*") are tried as well.
141 */
142 private synchronized Application getMatchingApplication(String messageType,
143 String triggerEvent) {
144 Application matchingApp = null;
145 Application o = this.apps.get(getKey(messageType, triggerEvent));
146 if (o == null)
147 o = this.apps.get(getKey(messageType, "*"));
148 if (o == null)
149 o = this.apps.get(getKey("*", triggerEvent));
150 if (o == null)
151 o = this.apps.get(getKey("*", "*"));
152 if (o != null)
153 matchingApp = o;
154 return matchingApp;
155 }
156
157 /**
158 * Creates reproducible hash key.
159 */
160 private String getKey(String messageType, String triggerEvent) {
161 // create hash key string by concatenating type and trigger event
162 return messageType + "|" + triggerEvent;
163 }
164
165 }