001: //=============================================================================
002: //=== Copyright (C) 2001-2007 Food and Agriculture Organization of the
003: //=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
004: //=== and United Nations Environment Programme (UNEP)
005: //===
006: //=== This program is free software; you can redistribute it and/or modify
007: //=== it under the terms of the GNU General Public License as published by
008: //=== the Free Software Foundation; either version 2 of the License, or (at
009: //=== your option) any later version.
010: //===
011: //=== This program is distributed in the hope that it will be useful, but
012: //=== WITHOUT ANY WARRANTY; without even the implied warranty of
013: //=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: //=== General Public License for more details.
015: //===
016: //=== You should have received a copy of the GNU General Public License
017: //=== along with this program; if not, write to the Free Software
018: //=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
019: //===
020: //=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
021: //=== Rome - Italy. email: geonetwork@osgeo.org
022: //==============================================================================
023:
024: package org.wfp.vam.intermap.http;
025:
026: import org.wfp.vam.intermap.http.cache.*;
027:
028: import java.io.*;
029: import java.util.*;
030:
031: import org.apache.commons.httpclient.*;
032: import org.apache.commons.httpclient.methods.*;
033: import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
034: import java.text.SimpleDateFormat;
035:
036: public class ConcurrentHTTPTransactionHandler {
037: private static String proxyHost;
038: private static int proxyPort;
039:
040: private int timeout = 0; // timeout in milliseconds (0 is interpreted as infinfite timeout)
041: private List<String> urisToGet = new ArrayList<String>();
042: private boolean checkIfModified = true;
043: private HashMap responses = new HashMap();
044: private HttpCache cache;
045:
046: // public static void main(String[] args) { // DEBUG
047: // ConcurrentHTTPTransactionHandler c = new ConcurrentHTTPTransactionHandler();
048: //
049: // try {
050: // c.setCache(new HttpGetFileCache("/ecchice", 1000));
051: // } catch (Exception e) { e.printStackTrace(); }
052: //
053: // c.checkIfModified(false);
054: //
055: // c.register("http://vam.wfp.org/main");
056: // c.register("http://www.apple.com");
057: //
058: // c.doTransactions();
059: // System.out.println("header: " + c.getHeaderValue("http://vam.wfp.org/main", "content-type"));
060: //
061: // try {
062: // Thread.sleep(4000);
063: // } catch (InterruptedException e) {}
064: //
065: // c.doTransactions();
066: // System.out.println("header: " + c.getHeaderValue("http://vam.wfp.org/main", "content-type"));
067: // }
068:
069: public static void setProxy(String proxyHost, int proxyPort) {
070: ConcurrentHTTPTransactionHandler.proxyHost = proxyHost;
071: ConcurrentHTTPTransactionHandler.proxyPort = proxyPort;
072: }
073:
074: /**
075: * Registers an uri to the handler
076: *
077: * @param uri a String
078: *
079: */
080: public void register(String uri) {
081: urisToGet.add(uri);
082: }
083:
084: public void setCache(HttpCache cache) {
085: this .cache = cache;
086: }
087:
088: public byte[] getResponse(String uri) {
089: return (byte[]) responses.get(uri);
090: }
091:
092: public String getHeaderValue(String uri, String header) {
093: return cache.getHeaderValue(uri, header);
094: }
095:
096: public String getResponseFilePath(String uri) {
097: return ((HttpGetFileCache) cache).getResponseFilePath(uri);
098: }
099:
100: /**
101: * Starts the transactions
102: *
103: */
104: public void doTransactions() {
105: HttpClient httpClient = new HttpClient(
106: new MultiThreadedHttpConnectionManager());
107: HostConfiguration hConf = httpClient.getHostConfiguration();
108: if (proxyHost != null)
109: hConf.setProxy(proxyHost, proxyPort);
110:
111: // create a thread for each URI
112: HttpThread[] threads = new HttpThread[urisToGet.size()];
113: for (int i = 0; i < threads.length; i++) {
114: GetMethod get = new GetMethod((String) urisToGet.get(i));
115: get.setFollowRedirects(true);
116: threads[i] = new HttpThread(httpClient, get, i + 1,
117: timeout, (String) urisToGet.get(i));
118: }
119:
120: // start the threads
121: for (int j = 0; j < threads.length; j++) {
122: threads[j].start();
123: }
124:
125: for (int j = 0; j < threads.length; j++) {
126: try {
127: (threads[j]).join();
128: } catch (InterruptedException e) {
129: }
130: }
131:
132: }
133:
134: /**
135: * Sets the connection timeout
136: *
137: * @param timeout connection timeout in milliseconds; Zero is interpreted as an infinite timeout.
138: *
139: */
140: public void setTimeout(int timeout) {
141: this .timeout = timeout;
142: }
143:
144: /**
145: * Returns the connection timeout
146: *
147: * @param timeout connection timeout in milliseconds; Zero is interpreted as an infinite timeout.
148: *
149: */
150: public int getTimeout() {
151: return timeout;
152: }
153:
154: /**
155: * If true, check if the page has changed sending an If-Modified-Since HTTP Header;<br>
156: * If false, always send the cached response.
157: *
158: * @param b a boolean
159: *
160: */
161: public void checkIfModified(boolean b) {
162: this .checkIfModified = b;
163: }
164:
165: /**
166: * A thread that performs a GET.
167: */
168: private class HttpThread extends Thread {
169:
170: private HttpClient httpClient;
171: private GetMethod method;
172: private int id;
173: private String uri;
174:
175: // private HttpThread(HttpClient httpClient, GetMethod method, int id) {
176: // this.httpClient = httpClient;
177: // this.method = method;
178: // this.id = id;
179: // }
180:
181: // private HttpThread(HttpClient httpClient, GetMethod method, int id, int timeout) {
182: // this.httpClient = httpClient;
183: // this.method = method;
184: // this.id = id;
185: // httpClient.setTimeout(timeout);
186: // }
187:
188: private HttpThread(HttpClient httpClient, GetMethod method,
189: int id, int timeout, String uri) {
190: this .httpClient = httpClient;
191: this .method = method;
192: this .id = id;
193: this .uri = uri;
194: httpClient.setTimeout(timeout);
195: }
196:
197: /**
198: * Executes the HttpMethod and prints some satus information.
199: */
200: public void run() {
201: try {
202: String uri = method.getURI().toString();
203:
204: if (cache != null) {
205: Calendar whenCached = cache.getCachedTime(uri);
206:
207: if (whenCached != null) {
208: if (!checkIfModified)
209: return;
210:
211: // the response has been cached, check if the page has been modified
212: SimpleDateFormat f = new SimpleDateFormat(
213: "EE, d MMM yyyy HH:mm:ss z");
214: Date date = whenCached.getTime();
215: method.setRequestHeader(new Header(
216: "If-Modified-Since", f.format(date)));
217: }
218: }
219:
220: long millis = System.currentTimeMillis();
221: httpClient.executeMethod(method);
222:
223: int statusCode = method.getStatusCode();
224: // System.out.println("status code: " + statusCode);
225: if (statusCode == 304) { // only possible if cache != null
226: // the page has not been modified - use cache
227: // System.out.println(id + " - using cache");
228: return;
229: } else {
230: // document not cached - fill cache first
231: InputStream is = method.getResponseBodyAsStream();
232: Header[] headers = method.getResponseHeaders();
233: cache.put(this .uri, is, headers);
234: // System.out.println(id + " - response:\n" + new String(bytes)); // DEBUG
235:
236: System.err.println("---("
237: + (System.currentTimeMillis() - millis)
238: + "ms)--> ENDED HTTP request to " + uri); // DEBUG ETj
239: return;
240: }
241:
242: } catch (Exception e) {
243: // System.out.println(id + " - error: " + e);
244: e.printStackTrace();
245: } finally {
246: // always release the connection after we're done
247: method.releaseConnection();
248: // System.out.println(id + " - connection released");
249: }
250: }
251:
252: } // GetThread class
253:
254: }
|