001/* 002The 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. 004You may obtain a copy of the License at http://www.mozilla.org/MPL/ 005Software distributed under the License is distributed on an "AS IS" basis, 006WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the 007specific language governing rights and limitations under the License. 008 009The Original Code is "URLTransport.java". Description: 010"A TransportLayer that reads and writes from an URL." 011 012The Initial Developer of the Original Code is University Health Network. Copyright (C) 0132004. All Rights Reserved. 014 015Contributor(s): ______________________________________. 016 017Alternatively, the contents of this file may be used under the terms of the 018GNU General Public License (the "GPL"), in which case the provisions of the GPL are 019applicable instead of those above. If you wish to allow use of your version of this 020file only under the terms of the GPL and not to allow others to use your version 021of this file under the MPL, indicate your decision by deleting the provisions above 022and replace them with the notice and other provisions required by the GPL License. 023If you do not delete the provisions above, a recipient may use your version of 024this file under either the MPL or the GPL. 025*/ 026 027package ca.uhn.hl7v2.protocol.impl; 028 029import java.io.BufferedInputStream; 030import java.io.BufferedOutputStream; 031import java.io.IOException; 032import java.io.InputStreamReader; 033import java.io.OutputStreamWriter; 034import java.io.Reader; 035import java.io.Writer; 036import java.net.URL; 037import java.net.URLConnection; 038 039import org.slf4j.Logger; 040import org.slf4j.LoggerFactory; 041 042import ca.uhn.hl7v2.protocol.TransportException; 043import ca.uhn.hl7v2.protocol.TransportLayer; 044import 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 */ 054public 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}