1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.qedeq.base.io;
17
18 import java.io.File;
19 import java.io.FileNotFoundException;
20 import java.io.FileOutputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.UnsupportedEncodingException;
24 import java.lang.reflect.InvocationTargetException;
25 import java.net.HttpURLConnection;
26 import java.net.MalformedURLException;
27 import java.net.URL;
28 import java.net.URLConnection;
29 import java.net.URLDecoder;
30
31 import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
32 import org.apache.commons.httpclient.HttpClient;
33 import org.apache.commons.httpclient.HttpStatus;
34 import org.apache.commons.httpclient.methods.GetMethod;
35 import org.apache.commons.httpclient.params.HttpMethodParams;
36 import org.qedeq.base.trace.Trace;
37 import org.qedeq.base.utility.YodaUtility;
38
39
40
41
42
43
44
45 public final class UrlUtility {
46
47
48 private static final Class CLASS = UrlUtility.class;
49
50
51
52
53 private UrlUtility() {
54
55 }
56
57
58
59
60
61
62
63 public static URL toUrl(final File file) {
64 try {
65 return file.getAbsoluteFile().toURI().toURL();
66 } catch (MalformedURLException e) {
67 throw new RuntimeException(e);
68 }
69 }
70
71
72
73
74
75
76
77 public static File transformURLPathToFilePath(final URL url) {
78 try {
79 return new File(URLDecoder.decode(url.getFile(), "UTF-8"));
80 } catch (UnsupportedEncodingException e) {
81 throw new RuntimeException(e);
82 }
83 }
84
85
86
87
88
89
90
91
92
93
94
95 public static final String createRelativePath(final File origin, final File next) {
96 if (origin.equals(next)) {
97 return "";
98 }
99 final Path org = new Path(origin.getPath().replace(File.separatorChar, '/'), "");
100 final Path ne = new Path(next.getPath().replace(File.separatorChar, '/'), "");
101 return org.createRelative(ne.toString()).toString();
102 }
103
104
105
106
107
108
109
110 public static String easyUrl(final String url) {
111 String result = url;
112 try {
113 final URL u = new URL(url);
114
115 if (u.getProtocol().equalsIgnoreCase("file")) {
116 return transformURLPathToFilePath(u).getCanonicalPath();
117 }
118 } catch (RuntimeException e) {
119
120 } catch (IOException e) {
121
122 }
123 return result;
124 }
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139 public static void saveUrlToFile(final String url, final File f, final String proxyHost,
140 final String proxyPort, final String nonProxyHosts, final int connectTimeout,
141 final int readTimeout, final LoadingListener listener)
142 throws IOException {
143 final String method = "saveUrlToFile()";
144 Trace.begin(CLASS, method);
145
146
147
148 if (!isSetConnectionTimeOutSupported()
149 && !IoUtility.isWebStarted()) {
150 saveQedeqFromWebToBufferApache(url, f, proxyHost, proxyPort, nonProxyHosts, connectTimeout,
151 readTimeout, listener);
152 Trace.end(CLASS, method);
153 return;
154 }
155
156
157 if (!IoUtility.isWebStarted()) {
158 if (proxyHost != null) {
159 System.setProperty("http.proxyHost", proxyHost);
160 }
161 if (proxyPort != null) {
162 System.setProperty("http.proxyPort", proxyPort);
163 }
164 if (nonProxyHosts != null) {
165 System.setProperty("http.nonProxyHosts", nonProxyHosts);
166 }
167 }
168
169 FileOutputStream out = null;
170 InputStream in = null;
171 try {
172 final URLConnection connection = new URL(url).openConnection();
173
174 if (connection instanceof HttpURLConnection) {
175 final HttpURLConnection httpConnection = (HttpURLConnection) connection;
176
177 if (isSetConnectionTimeOutSupported()) {
178 try {
179 YodaUtility.executeMethod(httpConnection, "setConnectTimeout",
180 new Class[] {Integer.TYPE}, new Object[] {new Integer(
181 connectTimeout)});
182 } catch (NoSuchMethodException e) {
183 Trace.fatal(CLASS, method,
184 "URLConnection.setConnectTimeout was previously found", e);
185 } catch (InvocationTargetException e) {
186 Trace.fatal(CLASS, method,
187 "URLConnection.setConnectTimeout throwed an error", e);
188 }
189 }
190
191 if (isSetReadTimeoutSupported()) {
192 try {
193 YodaUtility.executeMethod(httpConnection, "setReadTimeout",
194 new Class[] {Integer.TYPE}, new Object[] {new Integer(
195 readTimeout)});
196 } catch (NoSuchMethodException e) {
197 Trace.fatal(CLASS, method,
198 "URLConnection.setReadTimeout was previously found", e);
199 } catch (InvocationTargetException e) {
200 Trace.fatal(CLASS, method,
201 "URLConnection.setReadTimeout throwed an error", e);
202 }
203 }
204 int responseCode = httpConnection.getResponseCode();
205 if (responseCode == 200) {
206 in = httpConnection.getInputStream();
207 } else {
208 in = httpConnection.getErrorStream();
209 final String errorText = IoUtility.loadStreamWithoutException(in, 1000);
210 throw new IOException("Response code from HTTP server was " + responseCode
211 + (errorText.length() > 0 ? "\nResponse text from HTTP server was:\n"
212 + errorText : ""));
213 }
214 } else {
215 Trace.paramInfo(CLASS, method, "connection.getClass", connection.getClass()
216 .toString());
217 in = connection.getInputStream();
218 }
219
220 if (!url.equals(connection.getURL().toString())) {
221 throw new FileNotFoundException("\"" + url + "\" was substituted by "
222 + "\"" + connection.getURL() + "\" from server");
223 }
224 final double maximum = connection.getContentLength();
225 IoUtility.createNecessaryDirectories(f);
226 out = new FileOutputStream(f);
227 final byte[] buffer = new byte[4096];
228 int bytesRead;
229 int position = 0;
230
231 while ((bytesRead = in.read(buffer)) != -1) {
232 position += bytesRead;
233 out.write(buffer, 0, bytesRead);
234 if (maximum > 0) {
235 double completeness = position / maximum;
236 if (completeness < 0) {
237 completeness = 0;
238 }
239 if (completeness > 100) {
240 completeness = 1;
241 }
242 listener.loadingCompletenessChanged(completeness);
243 }
244 }
245 listener.loadingCompletenessChanged(1);
246 } finally {
247 IoUtility.close(out);
248 out = null;
249 IoUtility.close(in);
250 in = null;
251 Trace.end(CLASS, method);
252 }
253 }
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270 private static void saveQedeqFromWebToBufferApache(final String url, final File f,
271 final String proxyHost, final String proxyPort,
272 final String nonProxyHosts, final int connectTimeout, final int readTimeout,
273 final LoadingListener listener)
274 throws IOException {
275 final String method = "saveQedeqFromWebToBufferApache()";
276 Trace.begin(CLASS, method);
277
278
279 HttpClient client = new HttpClient();
280
281
282 if (!IoUtility.isWebStarted() && proxyHost != null && proxyHost.length() > 0) {
283 final String pHost = proxyHost;
284 int pPort = 80;
285 if (proxyPort != null) {
286 try {
287 pPort = Integer.parseInt(proxyPort);
288 } catch (RuntimeException e) {
289 Trace.fatal(CLASS, method, "proxy port not numeric: "
290 + proxyPort, e);
291 }
292 }
293 if (pHost.length() > 0) {
294 client.getHostConfiguration().setProxy(pHost, pPort);
295 }
296 }
297
298
299 GetMethod httpMethod = new GetMethod(url);
300
301 try {
302
303 httpMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
304 new DefaultHttpMethodRetryHandler(3, false));
305
306 httpMethod.getParams().setSoTimeout(connectTimeout);
307
308
309 int statusCode = client.executeMethod(httpMethod);
310
311 if (statusCode != HttpStatus.SC_OK) {
312 throw new FileNotFoundException("Problems loading: " + url + "\n"
313 + httpMethod.getStatusLine());
314 }
315
316
317 byte[] responseBody = httpMethod.getResponseBody();
318 IoUtility.saveFileBinary(f, responseBody);
319 listener.loadingCompletenessChanged(1);
320 } finally {
321
322 httpMethod.releaseConnection();
323 Trace.end(CLASS, method);
324 }
325 }
326
327
328
329
330
331
332
333 private static final class LazyHolderTimeoutMethods {
334
335
336
337
338 private LazyHolderTimeoutMethods() {
339
340 }
341
342
343
344
345 private static final boolean IS_SET_CONNECTION_TIMEOUT_SUPPORTED = YodaUtility.existsMethod(
346 URLConnection.class, "setConnectTimeout",
347 new Class[] {Integer.TYPE});
348
349
350
351
352 private static final boolean IS_SET_READ_TIMEOUT_SUSPPORTED = YodaUtility.existsMethod(
353 URLConnection.class, "setReadTimeout",
354 new Class[] {Integer.TYPE});
355
356 }
357
358
359
360
361
362
363 public static boolean isSetConnectionTimeOutSupported() {
364 return LazyHolderTimeoutMethods.IS_SET_CONNECTION_TIMEOUT_SUPPORTED;
365 }
366
367
368
369
370
371
372 public static boolean isSetReadTimeoutSupported() {
373 return LazyHolderTimeoutMethods.IS_SET_READ_TIMEOUT_SUSPPORTED;
374 }
375
376 }