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 final URL myURL; 065 private URLConnection myConnection; 066 protected final 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 */ 098 public void doSend(Transportable theMessage) throws TransportException { 099 if (myConnectOnSend) { 100 makeConnection(); 101 } 102 103 try { 104 Writer out = new OutputStreamWriter(new BufferedOutputStream(myConnection.getOutputStream())); 105 out.write(theMessage.getMessage()); 106 out.flush(); 107 } catch (IOException e) { 108 throw new TransportException(e); 109 } 110 } 111 112 public Transportable doReceive() throws TransportException { 113 114 if (myConnectOnReceive) { 115 makeConnection(); 116 } 117 118 StringBuilder response = new StringBuilder(); 119 120 try { 121 log.debug("Getting InputStream from URLConnection"); 122 Reader in = new InputStreamReader(new BufferedInputStream(myConnection.getInputStream())); 123 log.debug("Got InputStream from URLConnection"); 124 125 char[] buf = new char[myBufferSize]; 126 int bytesRead = 0; 127 128 IntRef bytesReadRef = new IntRef(); 129 130 while (bytesRead >= 0) { 131 132 try { 133 ReaderThread readerThread = new ReaderThread(in, buf, bytesReadRef); 134 readerThread.start(); 135 readerThread.join(10000); 136 137 bytesRead = bytesReadRef.getValue(); 138 139 if (bytesRead == 0) { 140 throw new TransportException("Timeout waiting for response"); 141 } 142 } 143 catch (InterruptedException ignored) { 144 } 145 146 if (bytesRead > 0) { 147 response.append(buf, 0, bytesRead); 148 } 149 150 } 151 152 in.close(); 153 } catch (IOException e) { 154 log.error(e.getMessage(), e); 155 } 156 157 if (response.length() == 0) { 158 throw new TransportException("Timeout waiting for response"); 159 } 160 161 return new TransportableImpl(response.toString()); 162 } 163 164 165 /** 166 * Calls openConnection() on the underlying URL and configures the connection, 167 * if this transport is configured to connect when connect() is called (see 168 * constructor params). 169 */ 170 public void doConnect() throws TransportException { 171 if (myConnectOnConnect) { 172 makeConnection(); 173 } 174 } 175 176 //makes new connection 177 private void makeConnection() throws TransportException { 178 try { 179 myConnection = myURL.openConnection(); 180 myConnection.setDoOutput(true); 181 myConnection.setDoInput(true); 182 myConnection.setRequestProperty("Content-Type", getContentType()); 183 myConnection.connect(); 184 } catch (IOException e) { 185 throw new TransportException(e); 186 } 187 log.debug("Made connection to {}", myURL.toExternalForm()); 188 } 189 190 /** 191 * @return the string used in the request property "Content-Type" (defaults to 192 * "application/hl7+doc+xml") 193 */ 194 public String getContentType() { 195 return myContentType; 196 } 197 198 /** 199 * @param theContentType the string to be used in the request property "Content-Type" 200 * (defaults to "application/hl7+doc+xml") 201 */ 202 public void setContentType(String theContentType) { 203 myContentType = theContentType; 204 } 205 206 /** 207 * @see ca.uhn.hl7v2.protocol.TransportLayer#disconnect() 208 */ 209 public void doDisconnect() { 210 myConnection = null; 211 } 212 213}