1 | // License: GPL. For details, see LICENSE file.
|
---|
2 | package org.openstreetmap.josm.io.imagery;
|
---|
3 |
|
---|
4 | import static org.openstreetmap.josm.tools.I18n.tr;
|
---|
5 |
|
---|
6 | import java.awt.image.BufferedImage;
|
---|
7 | import java.io.BufferedReader;
|
---|
8 | import java.io.IOException;
|
---|
9 | import java.io.InputStream;
|
---|
10 | import java.io.InputStreamReader;
|
---|
11 | import java.net.HttpURLConnection;
|
---|
12 | import java.net.MalformedURLException;
|
---|
13 | import java.net.URL;
|
---|
14 | import java.net.URLConnection;
|
---|
15 | import java.text.DecimalFormat;
|
---|
16 | import java.text.DecimalFormatSymbols;
|
---|
17 | import java.text.NumberFormat;
|
---|
18 | import java.util.Locale;
|
---|
19 | import java.util.regex.Matcher;
|
---|
20 | import java.util.regex.Pattern;
|
---|
21 |
|
---|
22 | import javax.imageio.ImageIO;
|
---|
23 | import javax.swing.JOptionPane;
|
---|
24 |
|
---|
25 | import org.openstreetmap.josm.Main;
|
---|
26 | import org.openstreetmap.josm.data.Version;
|
---|
27 | import org.openstreetmap.josm.data.coor.EastNorth;
|
---|
28 | import org.openstreetmap.josm.data.coor.LatLon;
|
---|
29 | import org.openstreetmap.josm.data.imagery.ImageryInfo;
|
---|
30 | import org.openstreetmap.josm.data.imagery.GeorefImage.State;
|
---|
31 | import org.openstreetmap.josm.data.projection.Mercator;
|
---|
32 | import org.openstreetmap.josm.gui.MapView;
|
---|
33 | import org.openstreetmap.josm.gui.layer.WMSLayer;
|
---|
34 | import org.openstreetmap.josm.io.CacheFiles;
|
---|
35 | import org.openstreetmap.josm.io.OsmTransferException;
|
---|
36 | import org.openstreetmap.josm.io.ProgressInputStream;
|
---|
37 |
|
---|
38 |
|
---|
39 | public class WMSGrabber extends Grabber {
|
---|
40 |
|
---|
41 | protected String baseURL;
|
---|
42 | private final boolean urlWithPatterns;
|
---|
43 |
|
---|
44 | public WMSGrabber(MapView mv, WMSLayer layer, CacheFiles cache) {
|
---|
45 | super(mv, layer, cache);
|
---|
46 | this.baseURL = layer.getInfo().getURL();
|
---|
47 | /* URL containing placeholders? */
|
---|
48 | urlWithPatterns = ImageryInfo.isUrlWithPatterns(baseURL);
|
---|
49 | }
|
---|
50 |
|
---|
51 | @Override
|
---|
52 | void fetch(WMSRequest request) throws Exception{
|
---|
53 | URL url = null;
|
---|
54 | try {
|
---|
55 | url = getURL(
|
---|
56 | b.min.east(), b.min.north(),
|
---|
57 | b.max.east(), b.max.north(),
|
---|
58 | width(), height());
|
---|
59 | request.finish(State.IMAGE, grab(url));
|
---|
60 |
|
---|
61 | } catch(Exception e) {
|
---|
62 | e.printStackTrace();
|
---|
63 | throw new Exception(e.getMessage() + "\nImage couldn't be fetched: " + (url != null ? url.toString() : ""));
|
---|
64 | }
|
---|
65 | }
|
---|
66 |
|
---|
67 | public static final NumberFormat latLonFormat = new DecimalFormat("###0.0000000",
|
---|
68 | new DecimalFormatSymbols(Locale.US));
|
---|
69 |
|
---|
70 | protected URL getURL(double w, double s,double e,double n,
|
---|
71 | int wi, int ht) throws MalformedURLException {
|
---|
72 | String myProj = Main.proj.toCode();
|
---|
73 | if(Main.proj instanceof Mercator) // don't use mercator code directly
|
---|
74 | {
|
---|
75 | LatLon sw = Main.proj.eastNorth2latlon(new EastNorth(w, s));
|
---|
76 | LatLon ne = Main.proj.eastNorth2latlon(new EastNorth(e, n));
|
---|
77 | myProj = "EPSG:4326";
|
---|
78 | s = sw.lat();
|
---|
79 | w = sw.lon();
|
---|
80 | n = ne.lat();
|
---|
81 | e = ne.lon();
|
---|
82 | }
|
---|
83 |
|
---|
84 | String str = baseURL;
|
---|
85 | String bbox = latLonFormat.format(w) + ","
|
---|
86 | + latLonFormat.format(s) + ","
|
---|
87 | + latLonFormat.format(e) + ","
|
---|
88 | + latLonFormat.format(n);
|
---|
89 |
|
---|
90 | if (urlWithPatterns) {
|
---|
91 | str = str.replaceAll("\\{proj\\}", myProj)
|
---|
92 | .replaceAll("\\{bbox\\}", bbox)
|
---|
93 | .replaceAll("\\{w\\}", latLonFormat.format(w))
|
---|
94 | .replaceAll("\\{s\\}", latLonFormat.format(s))
|
---|
95 | .replaceAll("\\{e\\}", latLonFormat.format(e))
|
---|
96 | .replaceAll("\\{n\\}", latLonFormat.format(n))
|
---|
97 | .replaceAll("\\{width\\}", String.valueOf(wi))
|
---|
98 | .replaceAll("\\{height\\}", String.valueOf(ht));
|
---|
99 | } else {
|
---|
100 | str += "bbox=" + bbox
|
---|
101 | + getProjection(baseURL, false)
|
---|
102 | + "&width=" + wi + "&height=" + ht;
|
---|
103 | if (!(baseURL.endsWith("&") || baseURL.endsWith("?"))) {
|
---|
104 | System.out.println(tr("Warning: The base URL ''{0}'' for a WMS service doesn't have a trailing '&' or a trailing '?'.", baseURL));
|
---|
105 | System.out.println(tr("Warning: Fetching WMS tiles is likely to fail. Please check you preference settings."));
|
---|
106 | System.out.println(tr("Warning: The complete URL is ''{0}''.", str));
|
---|
107 | }
|
---|
108 | }
|
---|
109 | return new URL(str.replace(" ", "%20"));
|
---|
110 | }
|
---|
111 |
|
---|
112 | static public String getProjection(String baseURL, Boolean warn)
|
---|
113 | {
|
---|
114 | String projname = Main.proj.toCode();
|
---|
115 | if(Main.proj instanceof Mercator) {
|
---|
116 | projname = "EPSG:4326";
|
---|
117 | }
|
---|
118 | String res = "";
|
---|
119 | try
|
---|
120 | {
|
---|
121 | Matcher m = Pattern.compile(".*srs=([a-z0-9:]+).*").matcher(baseURL.toLowerCase());
|
---|
122 | if(m.matches())
|
---|
123 | {
|
---|
124 | projname = projname.toLowerCase();
|
---|
125 | if(!projname.equals(m.group(1)) && warn)
|
---|
126 | {
|
---|
127 | JOptionPane.showMessageDialog(Main.parent,
|
---|
128 | tr("The projection ''{0}'' in URL and current projection ''{1}'' mismatch.\n"
|
---|
129 | + "This may lead to wrong coordinates.",
|
---|
130 | m.group(1), projname),
|
---|
131 | tr("Warning"),
|
---|
132 | JOptionPane.WARNING_MESSAGE);
|
---|
133 | }
|
---|
134 | } else {
|
---|
135 | res ="&srs="+projname;
|
---|
136 | }
|
---|
137 | }
|
---|
138 | catch(Exception e)
|
---|
139 | {
|
---|
140 | }
|
---|
141 | return res;
|
---|
142 | }
|
---|
143 |
|
---|
144 | @Override
|
---|
145 | public boolean loadFromCache(WMSRequest request) {
|
---|
146 | URL url = null;
|
---|
147 | try{
|
---|
148 | url = getURL(
|
---|
149 | b.min.east(), b.min.north(),
|
---|
150 | b.max.east(), b.max.north(),
|
---|
151 | width(), height());
|
---|
152 | } catch(Exception e) {
|
---|
153 | return false;
|
---|
154 | }
|
---|
155 | BufferedImage cached = cache.getImg(url.toString());
|
---|
156 | if((!request.isReal() && !layer.hasAutoDownload()) || cached != null){
|
---|
157 | if(cached == null){
|
---|
158 | request.finish(State.NOT_IN_CACHE, null);
|
---|
159 | return true;
|
---|
160 | }
|
---|
161 | request.finish(State.IMAGE, cached);
|
---|
162 | return true;
|
---|
163 | }
|
---|
164 | return false;
|
---|
165 | }
|
---|
166 |
|
---|
167 | protected BufferedImage grab(URL url) throws IOException, OsmTransferException {
|
---|
168 | System.out.println("Grabbing WMS " + url);
|
---|
169 |
|
---|
170 | HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
---|
171 | if(layer.getInfo().getCookies() != null && !layer.getInfo().getCookies().equals("")) {
|
---|
172 | conn.setRequestProperty("Cookie", layer.getInfo().getCookies());
|
---|
173 | }
|
---|
174 | conn.setRequestProperty("User-Agent", Main.pref.get("imagery.wms.user_agent", Version.getInstance().getAgentString()));
|
---|
175 | conn.setConnectTimeout(Main.pref.getInteger("imagery.wms.timeout.connect", 30) * 1000);
|
---|
176 | conn.setReadTimeout(Main.pref.getInteger("imagery.wms.timeout.read", 30) * 1000);
|
---|
177 |
|
---|
178 | String contentType = conn.getHeaderField("Content-Type");
|
---|
179 | if( conn.getResponseCode() != 200
|
---|
180 | || contentType != null && !contentType.startsWith("image") )
|
---|
181 | throw new IOException(readException(conn));
|
---|
182 |
|
---|
183 | InputStream is = new ProgressInputStream(conn, null);
|
---|
184 | BufferedImage img = ImageIO.read(is);
|
---|
185 | is.close();
|
---|
186 |
|
---|
187 | cache.saveImg(url.toString(), img);
|
---|
188 | return img;
|
---|
189 | }
|
---|
190 |
|
---|
191 | protected String readException(URLConnection conn) throws IOException {
|
---|
192 | StringBuilder exception = new StringBuilder();
|
---|
193 | InputStream in = conn.getInputStream();
|
---|
194 | BufferedReader br = new BufferedReader(new InputStreamReader(in));
|
---|
195 |
|
---|
196 | String line = null;
|
---|
197 | while( (line = br.readLine()) != null) {
|
---|
198 | // filter non-ASCII characters and control characters
|
---|
199 | exception.append(line.replaceAll("[^\\p{Print}]", ""));
|
---|
200 | exception.append('\n');
|
---|
201 | }
|
---|
202 | return exception.toString();
|
---|
203 | }
|
---|
204 | }
|
---|