Annotation of java/classes/org/w3c/www/protocol/http/HttpManager.java, revision 1.22
1.1 abaird 1: // HttpManager.java
1.22 ! ylafon 2: // $Id: HttpManager.java,v 1.21 1996/12/17 14:50:18 abaird Exp $
1.1 abaird 3: // (c) COPYRIGHT MIT and INRIA, 1996.
4: // Please first read the full copyright statement in file COPYRIGHT.html
5:
6: package w3c.www.protocol.http ;
7:
8: import java.util.*;
9: import java.net.*;
10: import java.io.*; // FIXME - DEBUG
11:
12: import w3c.www.mime.*;
1.4 abaird 13: import w3c.util.*;
1.1 abaird 14:
15: class ReplyFactory implements MimeParserFactory {
16:
17: public MimeHeaderHolder createHeaderHolder(MimeParser parser) {
18: return new Reply(parser);
19: }
20:
21: }
22:
1.9 abaird 23: class HttpServerState {
24: HttpServer server = null;
25: Vector conns = null;
26:
27: final HttpServer getServer() {
28: return server;
29: }
30:
31: synchronized boolean notEnoughConnections() {
32: return (conns == null) || (conns.size() == 1);
33: }
34:
35: void registerConnection(HttpConnection conn) {
36: if ( conns == null )
37: conns = new Vector(4);
38: conns.addElement(conn);
39: }
40:
41: void unregisterConnection(HttpConnection conn) {
42: if ( conns != null )
43: conns.removeElement(conn);
44: }
45:
46: void deleteConnection(HttpConnection conn) {
47: // conn.close();
48: if ( conns != null )
49: conns.removeElement(conn);
50: }
51:
52: synchronized HttpConnection getConnection() {
53: if ((conns != null) && (conns.size() > 0)) {
54: HttpConnection conn = (HttpConnection) conns.elementAt(0);
55: conns.removeElementAt(0);
56: return conn;
57: }
58: return null;
59: }
60:
61: HttpServerState(HttpServer server) {
62: this.server = server;
63: }
64: }
1.1 abaird 65:
66: /**
67: * The client side HTTP request manager.
68: * This class is the user interface (along with the other public classes of
69: * this package) for the W3C client side library implementing HTTP.
70: * A typicall request is launched though the following sequence:
71: * <pre>
72: * HttpManager manager = HttpManager.getManager() ;
73: * Request request = manager.makeRequest() ;
74: * request.setMethod(HTTP.GET) ;
75: * request.setURL(new URL("http://www.w3.org/pub/WWW/"));
76: * Reply reply = manager.runRequest(request) ;
77: * // Get the reply input stream that contains the actual data:
78: * InputStream in = reply.getInputStream() ;
79: * ...
80: * </pre>
81: */
82:
1.13 abaird 83: public class HttpManager implements PropertyMonitoring {
1.17 abaird 84: private static final
85: String DEFAULT_SERVER_CLASS = "w3c.www.protocol.http.HttpBasicServer";
86:
87: /**
88: * The name of the property indicating the class of HttpServer to use.
89: */
90: public static final
91: String SERVER_CLASS_P = "w3c.www.protocol.http.server";
92:
1.2 abaird 93: /**
94: * The name of the property containing the ProprequestFilter to launch.
95: */
1.12 abaird 96: public static final
97: String FILTERS_PROP_P = "w3c.www.protocol.http.filters";
1.5 abaird 98: /**
1.11 abaird 99: * The maximum number of simultaneous connections.
100: */
101: public static final
1.12 abaird 102: String CONN_MAX_P = "w3c.www.protocol.http.connections.max";
1.11 abaird 103: /**
1.5 abaird 104: * Header properties - The allowed drift for getting cached resources.
105: */
106: public static final
1.12 abaird 107: String MAX_STALE_P = "w3c.www.protocol.http.cacheControl.maxStale";
1.5 abaird 108: /**
109: * Header properties - The minium freshness required on cached resources.
110: */
111: public static final
1.12 abaird 112: String MIN_FRESH_P = "w3c.www.protocol.http.cacheControl.minFresh";
1.5 abaird 113: /**
114: * Header properties - Set the only if cached flag on requests.
115: */
116: public static final
1.12 abaird 117: String ONLY_IF_CACHED_P="w3c.www.protocol.http.cacheControl.onlyIfCached";
1.5 abaird 118: /**
119: * Header properties - Set the user agent.
120: */
121: public static final
1.12 abaird 122: String USER_AGENT_P = "w3c.www.protocol.http.userAgent";
1.5 abaird 123: /**
124: * Header properties - Set the accept header.
125: */
126: public static final
1.12 abaird 127: String ACCEPT_P = "w3c.www.protocol.http.accept";
1.5 abaird 128: /**
129: * Header properties - Set the accept language.
130: */
131: public static final
1.12 abaird 132: String ACCEPT_LANGUAGE_P = "w3c.www.protocol.http.acceptLanguage";
1.5 abaird 133: /**
134: * Header properties - Set the accept encodings.
135: */
136: public static final
1.12 abaird 137: String ACCEPT_ENCODING_P = "w3c.www.protocol.http.acceptEncoding";
1.5 abaird 138: /**
139: * Header properties - Should we use a proxy ?
140: */
141: public static final
1.12 abaird 142: String PROXY_SET_P = "proxySet";
1.5 abaird 143: /**
144: * Header properties - What is the proxy host name.
145: */
146: public static final
1.12 abaird 147: String PROXY_HOST_P = "proxyHost";
1.5 abaird 148: /**
149: * Header properties - What is the proxy port number.
150: */
151: public static final
1.12 abaird 152: String PROXY_PORT_P = "proxyPort";
1.2 abaird 153:
1.7 abaird 154: /**
155: * The default value for the <code>Accept</code> header.
156: */
157: public static final
158: String DEFAULT_ACCEPT = "*/*";
159: /**
160: * The default value for the <code>User-Agent</code> header.
161: */
162: public static final
163: String DEFAULT_USER_AGENT = "Jigsaw/1.0a2";
164:
1.1 abaird 165: private static HttpManager manager = null;
166:
167: /**
1.17 abaird 168: * The class to instantiate to create new HttpServer instances.
169: */
170: protected Class serverclass = null;
171: /**
1.13 abaird 172: * The properties we initialized from.
173: */
174: ObservableProperties props = null;
175: /**
1.1 abaird 176: * The server this manager knows about, indexed by FQDN of target servers.
177: */
178: protected Hashtable servers = null;
179: /**
180: * The template request (the request we will clone to create new requests)
181: */
1.4 abaird 182: protected Request template = null ;
183: /**
1.9 abaird 184: * The LRU list of connections.
1.4 abaird 185: */
1.9 abaird 186: protected LRUList connectionsLru = null;
1.1 abaird 187: /**
188: * The filter engine attached to this manager.
189: */
190: FilterEngine filteng = null;
191:
1.9 abaird 192: protected int conn_count = 0;
193: protected int conn_max = 5;
194:
1.1 abaird 195: /**
1.13 abaird 196: * Update the proxy configuration to match current properties setting.
197: * @return A boolean, <strong>true</strong> if change was done,
198: * <strong>false</strong> otherwise.
199: */
200:
201: protected boolean updateProxy() {
202: boolean set = props.getBoolean(PROXY_SET_P, false);
203: if ( set ) {
204: // Wow using a proxy now !
205: String host = props.getString(PROXY_HOST_P, null);
206: int port = props.getInteger(PROXY_PORT_P, -1);
207: URL proxy = null;
208: try {
209: proxy = new URL("http", host, port, "/");
210: } catch (Exception ex) {
211: return false;
212: }
213: // Now if a proxy...
214: if ( proxy != null )
215: getManager().template.setProxy(proxy);
216: } else {
217: getManager().template.setProxy(null);
218: }
219: return true;
220: }
221:
222: /**
223: * PropertyMonitoring implementation - Update properties on the fly !
224: * @param name The name of the property that has changed.
225: * @return A boolean, <strong>true</strong> if change is accepted,
226: * <strong>false</strong> otherwise.
227: */
228:
229: public boolean propertyChanged(String name) {
230: Request tpl = getManager().template;
231: if ( name.equals(FILTERS_PROP_P) ) {
232: return false;
233: } else if ( name.equals(CONN_MAX_P) ) {
234: setMaxConnections(props.getInteger(CONN_MAX_P, conn_max));
235: return true;
236: } else if ( name.equals(MAX_STALE_P) ) {
237: int ival = props.getInteger(MAX_STALE_P, -1);
238: if ( ival >= 0 )
239: tpl.setMaxStale(ival);
240: return true;
241: } else if ( name.equals(MIN_FRESH_P) ) {
242: int ival = props.getInteger(MIN_FRESH_P, -1);
243: if ( ival >= 0 )
244: tpl.setMinFresh(ival);
245: return true;
246: } else if ( name.equals(ONLY_IF_CACHED_P) ) {
247: tpl.setOnlyIfCached(props.getBoolean(ONLY_IF_CACHED_P, false));
248: return true;
249: } else if ( name.equals(USER_AGENT_P) ) {
250: tpl.setValue("user-agent"
251: , props.getString(USER_AGENT_P
252: , DEFAULT_USER_AGENT));
253: return true;
254: } else if ( name.equals(ACCEPT_P) ) {
255: tpl.setValue("accept"
256: , props.getString(ACCEPT_P, DEFAULT_ACCEPT));
257: return true;
258: } else if ( name.equals(ACCEPT_LANGUAGE_P) ) {
259: String sval = props.getString(ACCEPT_LANGUAGE_P, null);
260: if ( sval != null )
261: tpl.setValue("accept-language", sval);
262: return true;
263: } else if ( name.equals(ACCEPT_ENCODING_P) ) {
264: String sval = props.getString(ACCEPT_ENCODING_P, null);
265: if ( sval != null )
266: tpl.setValue("accept-encoding", sval);
267: return true;
268: } else if ( name.equals(PROXY_SET_P)
269: || name.equals(PROXY_HOST_P)
270: || name.equals(PROXY_PORT_P) ) {
271: return updateProxy();
272: } else {
273: return true;
274: }
275: }
276:
277: /**
1.4 abaird 278: * Allow the manager to interact with the user if needed.
279: * This will, for example, allow prompting for paswords, etc.
280: * @param onoff Turn interaction on or off.
281: */
282:
283: public void setAllowUserInteraction(boolean onoff) {
284: template.setAllowUserInteraction(onoff);
285: }
286:
287: /**
1.1 abaird 288: * Get an instance of the HTTP manager.
289: * This method returns an actual instance of the HTTP manager. It may
290: * return different managers, if it decides to distribute the load on
291: * different managers (avoid the HttpManager being a bottleneck).
292: * @return An application wide instance of the HTTP manager.
293: */
294:
295: public static synchronized HttpManager getManager() {
296: if ( manager == null ) {
297: manager = new HttpManager() ;
1.11 abaird 298: // Get the props we will initialize from:
299: Properties p = System.getProperties();
300: if ( p instanceof ObservableProperties )
1.13 abaird 301: manager.props = (ObservableProperties) p;
1.11 abaird 302: else
1.13 abaird 303: manager.props = new ObservableProperties(p);
304: ObservableProperties props = manager.props;
1.9 abaird 305: // Initialize this new manager filters:
1.12 abaird 306: String filters[] = props.getStringArray(FILTERS_PROP_P, null);
1.11 abaird 307: if ( filters != null ) {
308: for (int i = 0 ; i < filters.length ; i++) {
309: try {
310: Class c = Class.forName(filters[i]);
311: PropRequestFilter f = null;
312: f = (PropRequestFilter) c.newInstance();
313: f.initialize(manager);
1.20 abaird 314: } catch (PropRequestFilterException ex) {
315: System.out.println("Couldn't initialize filter \""
316: + filters[i]
317: + "\" init failed: "
318: + ex.getMessage());
1.11 abaird 319: } catch (Exception ex) {
320: System.err.println("Error initializing prop filters:");
321: System.err.println("Coulnd't initialize ["
322: + filters[i]
323: + "]: " + ex.getMessage());
324: ex.printStackTrace();
1.17 abaird 325: System.exit(1);
1.11 abaird 326: }
1.2 abaird 327: }
328: }
1.9 abaird 329: // The factory to create MIME reply holders:
330: manager.factory = new ReplyFactory();
1.17 abaird 331: // The class to create HttpServer instances from
332: String c = props.getString(SERVER_CLASS_P, DEFAULT_SERVER_CLASS);
333: try {
334: manager.serverclass = Class.forName(c);
335: } catch (Exception ex) {
336: System.err.println("Unable to initialize HttpManager: ");
337: System.err.println("Class \""+c+"\" not found, from property "
338: + SERVER_CLASS_P);
339: ex.printStackTrace();
340: System.exit(1);
341: }
1.9 abaird 342: // Setup the template request:
1.5 abaird 343: Request tpl = manager.template;
344: // Set some default headers value (from props)
345: // Check for a proxy ?
1.13 abaird 346: manager.updateProxy();
1.5 abaird 347: // CacheControl, only-if-cached
1.12 abaird 348: tpl.setOnlyIfCached(props.getBoolean(ONLY_IF_CACHED_P, false));
1.5 abaird 349: // CacheControl, maxstale
1.12 abaird 350: int ival = props.getInteger(MAX_STALE_P, -1);
1.11 abaird 351: if ( ival >= 0 )
352: tpl.setMaxStale(ival);
1.5 abaird 353: // CacheControl, minfresh:
1.12 abaird 354: ival = props.getInteger(MIN_FRESH_P, -1);
1.11 abaird 355: if ( ival >= 0 )
356: tpl.setMinFresh(ival);
1.5 abaird 357: // General, User agent
1.11 abaird 358: tpl.setValue("user-agent"
1.12 abaird 359: , props.getString(USER_AGENT_P
1.11 abaird 360: , DEFAULT_USER_AGENT));
1.5 abaird 361: // General, Accept
1.11 abaird 362: tpl.setValue("accept"
1.12 abaird 363: , props.getString(ACCEPT_P, DEFAULT_ACCEPT));
1.5 abaird 364: // General, Accept-Language
1.12 abaird 365: String sval = props.getString(ACCEPT_LANGUAGE_P, null);
1.11 abaird 366: if ( sval != null )
367: tpl.setValue("accept-language", sval);
1.5 abaird 368: // General, Accept-Encoding
1.12 abaird 369: sval = props.getString(ACCEPT_ENCODING_P, null);
1.11 abaird 370: if ( sval != null )
371: tpl.setValue("accept-encoding", sval);
372: // Maximum number of allowed connections:
1.12 abaird 373: manager.conn_max = props.getInteger(CONN_MAX_P, 5);
1.13 abaird 374: // Register ourself as a property observer:
375: props.registerObserver(manager);
1.1 abaird 376: }
377: return manager;
378: }
379:
380:
381: /**
382: * Get the appropriate server object for handling request to given target.
383: * @param key The server's identifier encoded as a <code>host:port</code>
384: * String.
385: * @return An object complying to the HttpServer interface.
386: * @exception HttpException If the given host name couldn't be resolved.
387: */
388:
1.5 abaird 389: protected synchronized HttpServer lookupServer(String host, int port)
1.1 abaird 390: throws HttpException
391: {
1.5 abaird 392: int p = (port == -1) ? 80 : port;
393: String id = (p == 80) ? host : (host +":"+p);
1.1 abaird 394: // Check for an existing server:
395: HttpServer server = (HttpServer) servers.get(id);
396: if ( server != null )
397: return server;
398: // Create and register a new server:
1.17 abaird 399: try {
400: server = (HttpServer) serverclass.newInstance();
401: } catch (Exception ex) {
402: String msg = ("Unable to create an instance of \""
403: + serverclass.getName()
404: + "\", invalid config, check the "
405: + SERVER_CLASS_P + " property.");
1.21 abaird 406: throw new HttpException(ex, msg);
1.17 abaird 407: }
1.9 abaird 408: server.initialize(this, new HttpServerState(server), host, p);
1.1 abaird 409: servers.put(id, server);
410: return server;
411: }
1.5 abaird 412:
1.1 abaird 413: /**
1.9 abaird 414: * The given connection is about to be used.
1.4 abaird 415: * Update our list of available servers.
1.9 abaird 416: * @param conn The idle connection.
1.4 abaird 417: */
418:
1.9 abaird 419: public void notifyUse(HttpConnection conn) {
420: connectionsLru.remove(conn);
1.4 abaird 421: }
422:
423: /**
1.9 abaird 424: * The given connection can be reused, but is now idle.
425: * @param conn The connection that is now idle.
1.4 abaird 426: */
427:
1.9 abaird 428: public void notifyIdle(HttpConnection conn) {
429: connectionsLru.toHead(conn);
1.4 abaird 430: }
431:
432: /**
1.9 abaird 433: * The given connection has just been created.
434: * @param conn The newly created connection.
435: */
436:
437: protected synchronized void notifyConnection(HttpConnection conn) {
438: if ( ++conn_count > conn_max )
439: closeAnyConnection();
440: }
441:
442: /**
443: * The given connection has been deleted.
444: * @param conn The deleted connection.
445: */
446:
447: protected void deleteConnection(HttpConnection conn) {
448: HttpServerState ss = conn.getServer().getState();
449: ss.deleteConnection(conn);
450: synchronized(this) {
451: --conn_count;
452: notifyAll();
453: }
454: }
455:
456: protected synchronized boolean tooManyConnections() {
457: return conn_count > conn_max;
458: }
459:
460: /**
461: * Try reusing one of the idle connection of that server, if any.
462: * @param server The target server.
463: * @return An currently idle connection to the given server.
1.4 abaird 464: */
465:
1.9 abaird 466: protected HttpConnection getConnection(HttpServer server) {
467: HttpServerState ss = server.getState();
468: return ss.getConnection();
469: }
470:
471: protected synchronized void waitForConnection(HttpServer server)
472: throws InterruptedException
473: {
474: wait();
1.4 abaird 475: }
476:
477: /**
1.9 abaird 478: * Close one connection, but pickling the least recently used one.
479: * @return A boolean, <strong>true</strong> if a connection was closed
480: * <strong>false</strong> otherwise.
1.4 abaird 481: */
482:
1.9 abaird 483: protected boolean closeAnyConnection() {
484: HttpConnection conn = (HttpConnection) connectionsLru.removeTail();
485: if ( conn != null ) {
486: conn.close();
487: deleteConnection(conn);
488: return true;
489: } else {
490: return false;
491: }
1.4 abaird 492: }
493:
494: /**
1.1 abaird 495: * One of our server handler wants to open a connection.
496: * @param block A boolean indicating whether we should block the calling
497: * thread until a token is available (otherwise, the method will just
498: * peek at the connection count, and return the appropriate result).
499: * @return A boolean, <strong>true</strong> if the connection can be
500: * opened straight, <strong>false</strong> otherwise.
501: */
502:
1.9 abaird 503: protected boolean negotiateConnection(HttpServer server) {
504: HttpServerState ss = server.getState();
1.10 abaird 505: if ( ! tooManyConnections() ) {
1.4 abaird 506: return true;
1.10 abaird 507: } else if ( ss.notEnoughConnections() ) {
508: return closeAnyConnection();
1.9 abaird 509: } else if ( servers.size() > conn_max ) {
510: return closeAnyConnection();
1.4 abaird 511: }
1.9 abaird 512: return false;
513: }
514:
515: /**
516: * A new client connection has been established.
517: * This method will try to maintain a maximum number of established
518: * connections, by closing idle connections when possible.
519: * @param server The server that has established a new connection.
520: */
521:
522: protected final synchronized void incrConnCount(HttpServer server) {
523: if ( ++conn_count > conn_max )
524: closeAnyConnection();
525: }
526:
527: /**
528: * Decrement the number of established connections.
529: * @param server The server that has closed one connection to its target.
530: */
531:
532: protected final synchronized void decrConnCount(HttpServer server) {
533: --conn_count;
1.1 abaird 534: }
535:
536: /**
537: * Run the given request, in synchronous mode.
538: * This method will launch the given request, and block the calling thread
539: * until the response headers are available.
540: * @param request The request to run.
541: * @return An instance of Reply, containing all the reply
542: * informations.
543: * @exception HTTPException If something failed during request processing.
544: */
545:
546: public Reply runRequest(Request request)
547: throws HttpException
548: {
1.19 abaird 549: URL target = request.getURL();
550: Reply reply = null;
551: int fcalls = 0;
1.1 abaird 552: // Now run through the ingoing filters:
553: RequestFilter filters[] = filteng.run(request);
554: if ( filters != null ) {
555: for (int i = 0 ; i < filters.length ; i++) {
1.19 abaird 556: if ((reply = filters[fcalls].ingoingFilter(request)) != null)
557: break;
558: fcalls++;
1.1 abaird 559: }
560: }
1.16 abaird 561: // Locate the appropriate target server:
1.19 abaird 562: if ( reply == null ) {
1.21 abaird 563: HttpServer srv = null;
1.22 ! ylafon 564: URL proxy;
! 565: boolean rtry ;
1.21 abaird 566: do {
1.22 ! ylafon 567: rtry = false;
1.21 abaird 568: try {
1.22 ! ylafon 569: proxy = request.getProxy();
1.21 abaird 570: srv = ((proxy != null)
571: ? lookupServer(proxy.getHost(), proxy.getPort())
572: : lookupServer(target.getHost(), target.getPort()));
573: reply = srv.runRequest(request);
574: } catch (HttpException ex) {
575: for (int i = 0; i < fcalls; i++)
576: rtry = rtry || filters[i].exceptionFilter(request, ex);
1.22 ! ylafon 577: if( !rtry)
! 578: throw ex;
1.21 abaird 579: }
580: } while (rtry);
1.16 abaird 581: }
1.1 abaird 582: // Apply the filters on the way back:
583: if ( filters != null ) {
1.19 abaird 584: while (--fcalls >= 0) {
585: Reply frep = filters[fcalls].outgoingFilter(request, reply);
586: if ( frep != null ) {
587: reply = frep;
588: break;
589: }
1.3 abaird 590: }
1.1 abaird 591: }
592: return reply;
593: }
594:
595: /**
596: * Get this manager's reply factory.
597: * The Reply factory is used when prsing incomming reply from servers, it
598: * decides what object will be created to hold the actual reply from the
599: * server.
600: * @return An object compatible with the MimeParserFactory interface.
601: */
602:
603: MimeParserFactory factory = null ;
604:
1.9 abaird 605: public MimeParserFactory getReplyFactory() {
1.1 abaird 606: return factory;
607: }
608:
609: /**
610: * Add a new request filter.
611: * Request filters are called <em>before</em> a request is launched, and
612: * <em>after</em> the reply headers are available. They allow applications
613: * to setup specific request headers (such as PICS, or PEP stuff) on the
614: * way in, and check the reply on the way out.
615: * <p>Request filters are application wide: if their scope matches
616: * the current request, then they will always be aplied.
617: * <p>Filter scopes are defined inclusively and exclusively
1.15 abaird 618: * @param incs The URL domains for which the filter should be triggered.
619: * @param exs The URL domains for which the filter should not be triggered.
1.1 abaird 620: * @param filter The request filter to add.
621: */
622:
623: public void setFilter(URL incs[], URL exs[], RequestFilter filter) {
624: if ( incs != null ) {
625: for (int i = 0 ; i < incs.length ; i++)
626: filteng.setFilter(incs[i], true, filter);
627: }
628: if ( exs != null ) {
629: for (int i = 0 ; i < exs.length ; i++)
630: filteng.setFilter(exs[i], false, filter);
631: }
632: return;
633: }
634:
1.15 abaird 635: /**
636: * Add a global filter.
637: * The given filter will <em>always</em> be invoked.
638: * @param filter The filter to install.
639: */
640:
1.1 abaird 641: public void setFilter(RequestFilter filter) {
642: filteng.setFilter(filter);
643: }
644:
645: /**
1.15 abaird 646: * Find back an instance of a global filter.
647: * This methods allow external classes to get a pointer to installed
648: * filters of a given class.
649: * @param cls The class of the filter to look for.
650: * @return A RequestFilter instance, or <strong>null</strong> if not
651: * found.
1.1 abaird 652: */
653:
1.15 abaird 654: public RequestFilter getGlobalFilter(Class cls) {
655: return filteng.getGlobalFilter(cls);
1.1 abaird 656: }
657:
658: /**
659: * Create a new default outgoing request.
660: * This method should <em>always</em> be used to create outgoing requests.
661: * It will initialize the request with appropriate default values for
662: * the various headers, and make sure that the request is enhanced by
663: * the registered request filters.
664: * @return An instance of Request, suitable to be launched.
665: */
666:
667: public Request createRequest() {
668: return (Request) template.getClone() ;
669: }
670:
671: /**
672: * Global settings - Set the max number of allowed connections.
673: * Set the maximum number of simultaneous connections that can remain
674: * opened. The manager will take care of queuing requests if this number
675: * is reached.
676: * <p>This value defaults to the value of the
677: * <code>w3c.www.http.maxConnections</code> property.
678: * @param max_conn The allowed maximum simultaneous open connections.
679: */
680:
1.13 abaird 681: public synchronized void setMaxConnections(int max_conn) {
682: this.conn_max = max_conn;
1.1 abaird 683: }
684:
685: /**
686: * Global settings - Set an optional proxy to use.
687: * Set the proxy to which all requests should be targeted. If the
688: * <code>w3c.www.http.proxy</code> property is defined, it will be
689: * used as the default value.
690: * @param proxy The URL for the proxy to use.
691: */
692:
693: public void setProxy(URL proxy) {
1.5 abaird 694: template.setProxy(proxy);
1.1 abaird 695: }
696:
697: /**
698: * Global settings - Set the request timeout.
699: * Once a request has been emited, the HttpManager will sit for this
700: * given number of milliseconds before the request is declared to have
701: * timed-out.
702: * <p>This timeout value defaults to the value of the
703: * <code>w3c.www.http.requestTimeout</code> property value.
704: * @param ms The timeout value in milliseconds.
705: */
706:
707: public void setRequestTimeout(int ms) {
708: }
709:
710: /**
711: * Global settings - Define a global request header.
712: * Set a default value for some request header. Once defined, the
713: * header will automatically be defined on <em>all</em> outgoing requests
714: * created through the <code>createRequest</code> request.
715: * @param name The name of the header, case insensitive.
716: * @param value It's default value.
717: */
718:
719: public void setGlobalHeader(String name, String value) {
720: template.setValue(name, value);
721: }
722:
1.18 abaird 723: /**
724: * Global settings - Get a global request header default value.
725: * @param name The name of the header to get.
726: * @return The value for that header, as a String, or <strong>
727: * null</strong> if undefined.
728: */
729:
1.1 abaird 730: public String getGlobalHeader(String name) {
731: return template.getValue(name);
1.18 abaird 732: }
733:
734:
735: /**
736: * Dump all in-memory cached state to persistent storage.
737: */
738:
739: public void sync() {
740: filteng.sync();
1.1 abaird 741: }
742:
743: /**
744: * Create a new HttpManager.
745: * This can only be called from this package. The caller must rather
746: * use the <code>getManager</code> method.
747: * @param props The properties from which the manager should initialize
748: * itself, or <strong>null</strong> if none are available.
749: */
750:
751: HttpManager(Properties props) {
1.9 abaird 752: this.template = new Request(this);
753: this.servers = new Hashtable();
754: this.filteng = new FilterEngine();
755: this.connectionsLru = new SyncLRUList();
1.1 abaird 756: }
757:
758: HttpManager() {
759: this(System.getProperties());
760: }
761:
762: /**
763: * DEBUGGING !
764: */
765:
766: public static void main(String args[]) {
767: try {
768: // Get the manager, and define some global headers:
769: HttpManager manager = HttpManager.getManager();
770: manager.setGlobalHeader("User-Agent", "Jigsaw/1.0a");
771: manager.setGlobalHeader("Accept", "*/*;q=1.0");
772: manager.setGlobalHeader("Accept-Encoding", "gzip");
773: Request request = manager.createRequest();
774: request.setURL(new URL(args[0]));
775: request.setMethod("GET");
776: Reply reply = manager.runRequest(request);
777: // Display some infos:
778: System.out.println("last-modified: "+reply.getLastModified());
779: System.out.println("length : "+reply.getContentLength());
780: // Display the returned body:
781: InputStream in = reply.getInputStream();
782: byte buf[] = new byte[4096];
783: int cnt = 0;
784: while ((cnt = in.read(buf)) > 0)
785: System.out.print(new String(buf, 0, 0, cnt));
786: System.out.println("-");
787: in.close();
788: } catch (Exception ex) {
789: ex.printStackTrace();
790: }
791: System.exit(1);
792: }
793: }
Webmaster