Annotation of java/classes/org/w3c/www/protocol/http/HttpManager.java, revision 1.3
1.1 abaird 1: // HttpManager.java
1.3 ! abaird 2: // $Id: HttpManager.java,v 1.2 1996/07/20 00:10:21 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.*;
13:
14: class ReplyFactory implements MimeParserFactory {
15:
16: public MimeHeaderHolder createHeaderHolder(MimeParser parser) {
17: return new Reply(parser);
18: }
19:
20: }
21:
22:
23: /**
24: * The client side HTTP request manager.
25: * This class is the user interface (along with the other public classes of
26: * this package) for the W3C client side library implementing HTTP.
27: * A typicall request is launched though the following sequence:
28: * <pre>
29: * HttpManager manager = HttpManager.getManager() ;
30: * Request request = manager.makeRequest() ;
31: * request.setMethod(HTTP.GET) ;
32: * request.setURL(new URL("http://www.w3.org/pub/WWW/"));
33: * Reply reply = manager.runRequest(request) ;
34: * // Get the reply input stream that contains the actual data:
35: * InputStream in = reply.getInputStream() ;
36: * ...
37: * </pre>
38: */
39:
40: public class HttpManager {
1.3 ! abaird 41:
1.2 abaird 42: /**
43: * The name of the property containing the ProprequestFilter to launch.
44: */
45: private static final String FILTERS_PROP = "w3c.www.protocol.http.filters";
46:
1.1 abaird 47: private static HttpManager manager = null;
48:
49: /**
50: * The server this manager knows about, indexed by FQDN of target servers.
51: */
52: protected Hashtable servers = null;
53: /**
54: * The template request (the request we will clone to create new requests)
55: */
56: Request template = null ;
57: /**
58: * The filter engine attached to this manager.
59: */
60: FilterEngine filteng = null;
61:
62:
63: /**
64: * Get an instance of the HTTP manager.
65: * This method returns an actual instance of the HTTP manager. It may
66: * return different managers, if it decides to distribute the load on
67: * different managers (avoid the HttpManager being a bottleneck).
68: * @return An application wide instance of the HTTP manager.
69: */
70:
71: public static synchronized HttpManager getManager() {
72: if ( manager == null ) {
73: manager = new HttpManager() ;
1.2 abaird 74: // Initialize this new manager:
75: String filters = System.getProperty(FILTERS_PROP);
76: if ( filters == null )
77: return manager;
78: StringTokenizer st = new StringTokenizer(filters, "|");
79: while (st.hasMoreTokens() ) {
80: String cls = (String) st.nextElement();
81: try {
82: Class c = Class.forName(cls);
83: PropRequestFilter f = (PropRequestFilter) c.newInstance();
84: f.initialize(manager);
85: } catch (Exception ex) {
86: System.err.println("Error initializing prop filters:");
87: System.err.println("Coulnd't initialize ["
88: + cls
89: + "]: " + ex.getMessage());
90: ex.printStackTrace();
91: }
92: }
1.1 abaird 93: }
94: return manager;
95: }
96:
97:
98: /**
99: * Get the appropriate server object for handling request to given target.
100: * @param key The server's identifier encoded as a <code>host:port</code>
101: * String.
102: * @return An object complying to the HttpServer interface.
103: * @exception HttpException If the given host name couldn't be resolved.
104: */
105:
106: protected synchronized HttpServer lookupServer(String host, int port)
107: throws HttpException
108: {
109: String id = ((port == 80) ? host : (host +":"+port));
110: // Check for an existing server:
111: HttpServer server = (HttpServer) servers.get(id);
112: if ( server != null )
113: return server;
114: // Create and register a new server:
115: server = new HttpBasicServer();
116: server.initialize(this, host, port);
117: servers.put(id, server);
118: return server;
119: }
120:
121: /**
122: * One of our server handler wants to open a connection.
123: * @param block A boolean indicating whether we should block the calling
124: * thread until a token is available (otherwise, the method will just
125: * peek at the connection count, and return the appropriate result).
126: * @return A boolean, <strong>true</strong> if the connection can be
127: * opened straight, <strong>false</strong> otherwise.
128: */
129:
130: protected boolean negotiateConnection(int ccount) {
131: return (ccount < 2);
132: }
133:
134: /**
135: * Run the given request, in synchronous mode.
136: * This method will launch the given request, and block the calling thread
137: * until the response headers are available.
138: * @param request The request to run.
139: * @return An instance of Reply, containing all the reply
140: * informations.
141: * @exception HTTPException If something failed during request processing.
142: */
143:
144: public Reply runRequest(Request request)
145: throws HttpException
146: {
147: URL target = request.getURL();
148: // Locate the appropriate target server:
149: int port = target.getPort();
150: HttpServer server = lookupServer(target.getHost()
151: , (port == -1) ? 80 : port);
152: // Now run through the ingoing filters:
153: RequestFilter filters[] = filteng.run(request);
154: if ( filters != null ) {
155: for (int i = 0 ; i < filters.length ; i++) {
1.3 ! abaird 156: Reply fr = filters[i].ingoingFilter(request);
! 157: if ( fr != null )
! 158: return fr;
1.1 abaird 159: }
160: }
161: // Get the server to give back a reply:
162: Reply reply = server.runRequest(request);
163: // Apply the filters on the way back:
164: if ( filters != null ) {
1.3 ! abaird 165: for (int i = 0 ; i < filters.length ; i++) {
! 166: Reply fr = filters[i].outgoingFilter(request, reply);
! 167: if ( fr != null )
! 168: return fr;
! 169: }
1.1 abaird 170: }
171: return reply;
172: }
173:
174: /**
175: * Get this manager's reply factory.
176: * The Reply factory is used when prsing incomming reply from servers, it
177: * decides what object will be created to hold the actual reply from the
178: * server.
179: * @return An object compatible with the MimeParserFactory interface.
180: */
181:
182: MimeParserFactory factory = null ;
183:
184: public synchronized MimeParserFactory getReplyFactory() {
185: if ( factory == null )
186: factory = new ReplyFactory();
187: return factory;
188: }
189:
190: /**
191: * Add a new request filter.
192: * Request filters are called <em>before</em> a request is launched, and
193: * <em>after</em> the reply headers are available. They allow applications
194: * to setup specific request headers (such as PICS, or PEP stuff) on the
195: * way in, and check the reply on the way out.
196: * <p>Request filters are application wide: if their scope matches
197: * the current request, then they will always be aplied.
198: * <p>Filter scopes are defined inclusively and exclusively
199: * @param filter The request filter to add.
200: */
201:
202: public void setFilter(URL incs[], URL exs[], RequestFilter filter) {
203: if ( incs != null ) {
204: for (int i = 0 ; i < incs.length ; i++)
205: filteng.setFilter(incs[i], true, filter);
206: }
207: if ( exs != null ) {
208: for (int i = 0 ; i < exs.length ; i++)
209: filteng.setFilter(exs[i], false, filter);
210: }
211: return;
212: }
213:
214: public void setFilter(RequestFilter filter) {
215: filteng.setFilter(filter);
216: }
217:
218: /**
219: * Add a request processor.
220: * Request processors are application wide hooks, able to answer request
221: * by querying a local cache. An application can set as many request
222: * processor as it wants, each of them will be called in trun (in the order
223: * they were registered), if any of them returns a reply, the request
224: * processing will be halted, and the generated reply returned.
225: * <p>Request processors can also be used to query distant cache, through
226: * some home-brew protocols.
227: * @param processor The request processor to be added.
228: */
229:
230: public void addProcessor(RequestProcessor processor) {
231: }
232:
233: /**
234: * Remove a request processor.
235: * Remove the given request processor.
236: * @return A boolean, <strong>true</strong> if the processor was found
237: * and removed, <strong>false</strong> otherwise.
238: */
239:
240: public boolean removeProcessor(RequestProcessor processor) {
241: return false;
242: }
243:
244: /**
245: * Create a new default outgoing request.
246: * This method should <em>always</em> be used to create outgoing requests.
247: * It will initialize the request with appropriate default values for
248: * the various headers, and make sure that the request is enhanced by
249: * the registered request filters.
250: * @return An instance of Request, suitable to be launched.
251: */
252:
253: public Request createRequest() {
254: return (Request) template.getClone() ;
255: }
256:
257: /**
258: * Global settings - Set the max number of allowed connections.
259: * Set the maximum number of simultaneous connections that can remain
260: * opened. The manager will take care of queuing requests if this number
261: * is reached.
262: * <p>This value defaults to the value of the
263: * <code>w3c.www.http.maxConnections</code> property.
264: * @param max_conn The allowed maximum simultaneous open connections.
265: */
266:
267: public void setMaxConnections(int max_conn) {
268: }
269:
270: /**
271: * Global settings - Set an optional proxy to use.
272: * Set the proxy to which all requests should be targeted. If the
273: * <code>w3c.www.http.proxy</code> property is defined, it will be
274: * used as the default value.
275: * @param proxy The URL for the proxy to use.
276: */
277:
278: public void setProxy(URL proxy) {
279: }
280:
281: /**
282: * Global settings - Set the request timeout.
283: * Once a request has been emited, the HttpManager will sit for this
284: * given number of milliseconds before the request is declared to have
285: * timed-out.
286: * <p>This timeout value defaults to the value of the
287: * <code>w3c.www.http.requestTimeout</code> property value.
288: * @param ms The timeout value in milliseconds.
289: */
290:
291: public void setRequestTimeout(int ms) {
292: }
293:
294: /**
295: * Global settings - Define a global request header.
296: * Set a default value for some request header. Once defined, the
297: * header will automatically be defined on <em>all</em> outgoing requests
298: * created through the <code>createRequest</code> request.
299: * @param name The name of the header, case insensitive.
300: * @param value It's default value.
301: */
302:
303: public void setGlobalHeader(String name, String value) {
304: template.setValue(name, value);
305: }
306:
307: public String getGlobalHeader(String name) {
308: return template.getValue(name);
309: }
310:
311: /**
312: * Create a new HttpManager.
313: * This can only be called from this package. The caller must rather
314: * use the <code>getManager</code> method.
315: * @param props The properties from which the manager should initialize
316: * itself, or <strong>null</strong> if none are available.
317: */
318:
319: HttpManager(Properties props) {
320: this.template = new Request(this);
321: this.servers = new Hashtable();
322: this.filteng = new FilterEngine();
323: }
324:
325: HttpManager() {
326: this(System.getProperties());
327: }
328:
329: /**
330: * DEBUGGING !
331: */
332:
333: public static void main(String args[]) {
334: try {
335: // Get the manager, and define some global headers:
336: HttpManager manager = HttpManager.getManager();
337: manager.setGlobalHeader("User-Agent", "Jigsaw/1.0a");
338: manager.setGlobalHeader("Accept", "*/*;q=1.0");
339: manager.setGlobalHeader("Accept-Encoding", "gzip");
340: Request request = manager.createRequest();
341: request.setURL(new URL(args[0]));
342: request.setMethod("GET");
343: Reply reply = manager.runRequest(request);
344: // Display some infos:
345: System.out.println("last-modified: "+reply.getLastModified());
346: System.out.println("length : "+reply.getContentLength());
347: // Display the returned body:
348: InputStream in = reply.getInputStream();
349: byte buf[] = new byte[4096];
350: int cnt = 0;
351: while ((cnt = in.read(buf)) > 0)
352: System.out.print(new String(buf, 0, 0, cnt));
353: System.out.println("-");
354: in.close();
355: } catch (Exception ex) {
356: ex.printStackTrace();
357: }
358: System.exit(1);
359: }
360: }
Webmaster