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 "URLTransport.java". Description:
010 "A TransportLayer that reads and writes from an URL."
011
012 The Initial Developer of the Original Code is University Health Network. Copyright (C)
013 2004. All Rights Reserved.
014
015 Contributor(s): ______________________________________.
016
017 Alternatively, the contents of this file may be used under the terms of the
018 GNU General Public License (the "GPL"), in which case the provisions of the GPL are
019 applicable instead of those above. If you wish to allow use of your version of this
020 file only under the terms of the GPL and not to allow others to use your version
021 of this file under the MPL, indicate your decision by deleting the provisions above
022 and replace them with the notice and other provisions required by the GPL License.
023 If you do not delete the provisions above, a recipient may use your version of
024 this file under either the MPL or the GPL.
025 */
026
027 package ca.uhn.hl7v2.protocol.impl;
028
029 import java.io.BufferedInputStream;
030 import java.io.BufferedOutputStream;
031 import java.io.IOException;
032 import java.io.InputStreamReader;
033 import java.io.OutputStreamWriter;
034 import java.io.Reader;
035 import java.io.Writer;
036 import java.net.URL;
037 import java.net.URLConnection;
038
039 import org.slf4j.Logger;
040 import org.slf4j.LoggerFactory;
041
042 import ca.uhn.hl7v2.protocol.TransportException;
043 import ca.uhn.hl7v2.protocol.TransportLayer;
044 import ca.uhn.hl7v2.protocol.Transportable;
045
046 /**
047 * A <code>TransportLayer</code> that reads and writes from an URL (for example
048 * over HTTP).
049 *
050 * @author <a href="mailto:bryan.tripp@uhn.on.ca">Bryan Tripp</a>
051 * @author <a href="mailto:alexei.guevara@uhn.on.ca">Alexei Guevara</a>
052 * @version $Revision: 1.1 $ updated on $Date: 2007-02-19 02:24:26 $ by $Author: jamesagnew $
053 */
054 public class URLTransport extends AbstractTransport implements TransportLayer {
055
056 private static final Logger log = LoggerFactory.getLogger(URLTransport.class);
057
058 /**
059 * Key in Transportable metadata map under which URL is stored.
060 */
061 public static final String URL_KEY = "URL";
062
063 private String myContentType = "application/hl7+doc+xml";
064 private URL myURL;
065 private URLConnection myConnection;
066 protected int myBufferSize = 3000;
067
068 private final boolean myConnectOnSend;
069 private final boolean myConnectOnReceive;
070 private final boolean myConnectOnConnect;
071
072 /**
073 * The boolean configuration flags determine when new connections are made. For example if this
074 * transport is being used for query/response, you might set connectOnSend to true and
075 * the others to false, so that each query/response is done over a fresh connection. If
076 * you are using a transport just to read data from a URL, you might set connectOnReceive to
077 * true and the others to false.
078 *
079 * @param theURL the URL at which messages are to be read and written
080 * @param connectOnSend makes a new connection before each send
081 * @param connectOnReceive makes a new connection before each receive
082 * @param connectOnConnect makes a new connection when connect() is called
083 */
084 public URLTransport(URL theURL, boolean connectOnSend, boolean connectOnReceive, boolean connectOnConnect) {
085 myURL = theURL;
086 getCommonMetadata().put(URL_KEY, theURL);
087
088 myConnectOnSend = connectOnSend;
089 myConnectOnReceive = connectOnReceive;
090 myConnectOnConnect = connectOnConnect;
091 }
092
093 /**
094 * Writes the given message to the URL.
095 *
096 * @param theMessage the message to send
097 * @see ca.uhn.hl7v2.protocol.AbstractTransport#doSend(ca.uhn.hl7v2.protocol.Transportable)
098 */
099 public void doSend(Transportable theMessage) throws TransportException {
100 if (myConnectOnSend) {
101 makeConnection();
102 }
103
104 try {
105 Writer out = new OutputStreamWriter(new BufferedOutputStream(myConnection.getOutputStream()));
106 out.write(theMessage.getMessage());
107 out.flush();
108 } catch (IOException e) {
109 throw new TransportException(e);
110 }
111 }
112
113 /**
114 * @see ca.uhn.hl7v2.protocol.AbstractTransport#doReceive()
115 */
116 public Transportable doReceive() throws TransportException {
117
118 if (myConnectOnReceive) {
119 makeConnection();
120 }
121
122 StringBuffer response = new StringBuffer();
123
124 try {
125 log.debug("Getting InputStream from URLConnection");
126 Reader in = new InputStreamReader(new BufferedInputStream(myConnection.getInputStream()));
127 log.debug("Got InputStream from URLConnection");
128
129 char[] buf = new char[myBufferSize];
130 int bytesRead = 0;
131
132 IntRef bytesReadRef = new IntRef();
133
134 while (bytesRead >= 0) {
135
136 try {
137 ReaderThread readerThread = new ReaderThread(in, buf, bytesReadRef);
138 readerThread.start();
139 readerThread.join(10000);
140
141 bytesRead = bytesReadRef.getValue();
142
143 if (bytesRead == 0) {
144 throw new TransportException("Timeout waiting for response");
145 }
146 }
147 catch (InterruptedException x) {
148 }
149
150 if (bytesRead > 0) {
151 response.append(buf, 0, bytesRead);
152 }
153
154 }
155
156 in.close();
157 } catch (IOException e) {
158 log.error(e.getMessage(), e);
159 }
160
161 if (response.length() == 0) {
162 throw new TransportException("Timeout waiting for response");
163 }
164
165 return new TransportableImpl(response.toString());
166 }
167
168
169 /**
170 * Calls openConnection() on the underlying URL and configures the connection,
171 * if this transport is configured to connect when connect() is called (see
172 * constructor params).
173 *
174 * @see ca.uhn.hl7v2.protocol.AbstractTransport#doConnect()
175 */
176 public void doConnect() throws TransportException {
177 if (myConnectOnConnect) {
178 makeConnection();
179 }
180 }
181
182 //makes new connection
183 private void makeConnection() throws TransportException {
184 try {
185 myConnection = myURL.openConnection();
186 myConnection.setDoOutput(true);
187 myConnection.setDoInput(true);
188 myConnection.setRequestProperty("Content-Type", getContentType());
189 myConnection.connect();
190 } catch (IOException e) {
191 throw new TransportException(e);
192 }
193 log.debug("Made connection to {}", myURL.toExternalForm());
194 }
195
196 /**
197 * @return the string used in the request property "Content-Type" (defaults to
198 * "application/hl7+doc+xml")
199 */
200 public String getContentType() {
201 return myContentType;
202 }
203
204 /**
205 * @param theContentType the string to be used in the request property "Content-Type"
206 * (defaults to "application/hl7+doc+xml")
207 */
208 public void setContentType(String theContentType) {
209 myContentType = theContentType;
210 }
211
212 /**
213 * @see ca.uhn.hl7v2.protocol.TransportLayer#disconnect()
214 */
215 public void doDisconnect() throws TransportException {
216 myConnection = null;
217 }
218
219 }