001 // License: GPL. Copyright 2007 by Immanuel Scholz and others 002 package org.openstreetmap.josm.io; 003 004 import static org.openstreetmap.josm.tools.I18n.tr; 005 006 import java.io.BufferedReader; 007 import java.io.IOException; 008 import java.io.InputStream; 009 import java.io.InputStreamReader; 010 import java.net.HttpURLConnection; 011 import java.net.MalformedURLException; 012 import java.net.URL; 013 import java.util.zip.GZIPInputStream; 014 import java.util.zip.Inflater; 015 import java.util.zip.InflaterInputStream; 016 017 import org.openstreetmap.josm.Main; 018 import org.openstreetmap.josm.data.gpx.GpxData; 019 import org.openstreetmap.josm.data.osm.DataSet; 020 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 021 022 /** 023 * This DataReader reads directly from the REST API of the osm server. 024 * 025 * It supports plain text transfer as well as gzip or deflate encoded transfers; 026 * if compressed transfers are unwanted, set property osm-server.use-compression 027 * to false. 028 * 029 * @author imi 030 */ 031 public abstract class OsmServerReader extends OsmConnection { 032 private OsmApi api = OsmApi.getOsmApi(); 033 private boolean doAuthenticate = false; 034 035 /** 036 * Open a connection to the given url and return a reader on the input stream 037 * from that connection. In case of user cancel, return <code>null</code>. 038 * @param urlStr The exact url to connect to. 039 * @param pleaseWaitDlg 040 * @return An reader reading the input stream (servers answer) or <code>null</code>. 041 */ 042 protected InputStream getInputStream(String urlStr, ProgressMonitor progressMonitor) throws OsmTransferException { 043 try { 044 api.initialize(progressMonitor); 045 urlStr = urlStr.startsWith("http") ? urlStr : (getBaseUrl() + urlStr); 046 return getInputStreamRaw(urlStr, progressMonitor); 047 } finally { 048 progressMonitor.invalidate(); 049 } 050 } 051 052 protected String getBaseUrl() { 053 return api.getBaseUrl(); 054 } 055 056 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor) throws OsmTransferException { 057 try { 058 URL url = null; 059 try { 060 url = new URL(urlStr.replace(" ", "%20")); 061 } catch(MalformedURLException e) { 062 throw new OsmTransferException(e); 063 } 064 try { 065 activeConnection = (HttpURLConnection)url.openConnection(); 066 // fix #7640, see http://www.tikalk.com/java/forums/httpurlconnection-disable-keep-alive 067 activeConnection.setRequestProperty("Connection", "close"); 068 } catch(Exception e) { 069 throw new OsmTransferException(tr("Failed to open connection to API {0}.", url.toExternalForm()), e); 070 } 071 if (cancel) { 072 activeConnection.disconnect(); 073 return null; 074 } 075 076 if (doAuthenticate) { 077 addAuth(activeConnection); 078 } 079 if (cancel) 080 throw new OsmTransferCanceledException(); 081 if (Main.pref.getBoolean("osm-server.use-compression", true)) { 082 activeConnection.setRequestProperty("Accept-Encoding", "gzip, deflate"); 083 } 084 085 activeConnection.setConnectTimeout(Main.pref.getInteger("socket.timeout.connect",15)*1000); 086 087 try { 088 System.out.println("GET " + url); 089 activeConnection.connect(); 090 } catch (Exception e) { 091 e.printStackTrace(); 092 throw new OsmTransferException(tr("Could not connect to the OSM server. Please check your internet connection."), e); 093 } 094 try { 095 if (activeConnection.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED) 096 throw new OsmApiException(HttpURLConnection.HTTP_UNAUTHORIZED,null,null); 097 098 if (activeConnection.getResponseCode() == HttpURLConnection.HTTP_PROXY_AUTH) 099 throw new OsmTransferCanceledException(); 100 101 String encoding = activeConnection.getContentEncoding(); 102 if (activeConnection.getResponseCode() != HttpURLConnection.HTTP_OK) { 103 String errorHeader = activeConnection.getHeaderField("Error"); 104 StringBuilder errorBody = new StringBuilder(); 105 try 106 { 107 InputStream i = FixEncoding(activeConnection.getErrorStream(), encoding); 108 if (i != null) { 109 BufferedReader in = new BufferedReader(new InputStreamReader(i)); 110 String s; 111 while((s = in.readLine()) != null) { 112 errorBody.append(s); 113 errorBody.append("\n"); 114 } 115 } 116 } 117 catch(Exception e) { 118 errorBody.append(tr("Reading error text failed.")); 119 } 120 121 throw new OsmApiException(activeConnection.getResponseCode(), errorHeader, errorBody.toString()); 122 } 123 124 return FixEncoding(new ProgressInputStream(activeConnection, progressMonitor), encoding); 125 } catch(Exception e) { 126 if (e instanceof OsmTransferException) 127 throw (OsmTransferException)e; 128 else 129 throw new OsmTransferException(e); 130 131 } 132 } finally { 133 progressMonitor.invalidate(); 134 } 135 } 136 137 private InputStream FixEncoding(InputStream stream, String encoding) throws IOException 138 { 139 if (encoding != null && encoding.equalsIgnoreCase("gzip")) { 140 stream = new GZIPInputStream(stream); 141 } 142 else if (encoding != null && encoding.equalsIgnoreCase("deflate")) { 143 stream = new InflaterInputStream(stream, new Inflater(true)); 144 } 145 return stream; 146 } 147 148 public abstract DataSet parseOsm(final ProgressMonitor progressMonitor) throws OsmTransferException; 149 150 public DataSet parseOsmChange(final ProgressMonitor progressMonitor) throws OsmTransferException { 151 return null; 152 } 153 154 public DataSet parseOsmChangeBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException { 155 return null; 156 } 157 158 public DataSet parseOsmChangeGzip(final ProgressMonitor progressMonitor) throws OsmTransferException { 159 return null; 160 } 161 162 public GpxData parseRawGps(final ProgressMonitor progressMonitor) throws OsmTransferException { 163 return null; 164 } 165 166 public DataSet parseOsmBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException { 167 return null; 168 } 169 170 public DataSet parseOsmGzip(final ProgressMonitor progressMonitor) throws OsmTransferException { 171 return null; 172 } 173 174 /** 175 * Returns true if this reader is adding authentication credentials to the read 176 * request sent to the server. 177 * 178 * @return true if this reader is adding authentication credentials to the read 179 * request sent to the server 180 */ 181 public boolean isDoAuthenticate() { 182 return doAuthenticate; 183 } 184 185 /** 186 * Sets whether this reader adds authentication credentials to the read 187 * request sent to the server. 188 * 189 * @param doAuthenticate true if this reader adds authentication credentials to the read 190 * request sent to the server 191 */ 192 public void setDoAuthenticate(boolean doAuthenticate) { 193 this.doAuthenticate = doAuthenticate; 194 } 195 }