Source Code Cross Referenced for HttpManager.java in  » Web-Server » Jigsaw » org » w3c » www » protocol » http » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Server » Jigsaw » org.w3c.www.protocol.http 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        // HttpManager.java
0002:        // $Id: HttpManager.java,v 1.90 2007/04/10 13:22:22 ylafon Exp $
0003:        // (c) COPYRIGHT MIT and INRIA, 1996.
0004:        // Please first read the full copyright statement in file COPYRIGHT.html
0005:
0006:        package org.w3c.www.protocol.http;
0007:
0008:        import java.util.Enumeration;
0009:        import java.util.Hashtable;
0010:        import java.util.Properties;
0011:
0012:        import java.net.URL;
0013:
0014:        import java.io.InputStream;
0015:        import java.io.PrintStream;
0016:
0017:        import org.w3c.www.mime.MimeHeaderHolder;
0018:        import org.w3c.www.mime.MimeParser;
0019:        import org.w3c.www.mime.MimeParserFactory;
0020:
0021:        import org.w3c.util.LRUList;
0022:        import org.w3c.util.ObservableProperties;
0023:        import org.w3c.util.PropertyMonitoring;
0024:        import org.w3c.util.SyncLRUList;
0025:
0026:        class ManagerDescription {
0027:            HttpManager manager = null;
0028:            Properties properties = null;
0029:
0030:            final HttpManager getManager() {
0031:                return manager;
0032:            }
0033:
0034:            final boolean sameProperties(Properties props) {
0035:                if (props.size() != properties.size())
0036:                    return false;
0037:                Enumeration e = props.propertyNames();
0038:                while (e.hasMoreElements()) {
0039:                    String name = (String) e.nextElement();
0040:                    String prop = properties.getProperty(name);
0041:                    if ((prop == null)
0042:                            || (!prop.equals(props.getProperty(name))))
0043:                        return false;
0044:                }
0045:                return true;
0046:            }
0047:
0048:            ManagerDescription(HttpManager manager, Properties props) {
0049:                this .manager = manager;
0050:                this .properties = (Properties) props.clone();
0051:            }
0052:        }
0053:
0054:        class ReplyFactory implements  MimeParserFactory {
0055:
0056:            public MimeHeaderHolder createHeaderHolder(MimeParser parser) {
0057:                return new Reply(parser);
0058:            }
0059:
0060:        }
0061:
0062:        /**
0063:         * The client side HTTP request manager.
0064:         * This class is the user interface (along with the other public classes of
0065:         * this package) for the W3C client side library implementing HTTP. 
0066:         * A typical request is launched though the following sequence:
0067:         * <pre>
0068:         * HttpManager     manager = HttpManager.getManager() ;
0069:         * Request request = manager.createRequest() ;
0070:         * request.setMethod(HTTP.GET) ;
0071:         * request.setURL(new URL("http://www.w3.org/pub/WWW/"));
0072:         * Reply    reply = manager.runRequest(request) ;
0073:         * // Get the reply input stream that contains the actual data:
0074:         * InputStream in = reply.getInputStream() ;
0075:         * ...
0076:         * </pre>
0077:         */
0078:
0079:        public class HttpManager implements  PropertyMonitoring {
0080:
0081:            private static final boolean debug = false;
0082:
0083:            private static final String DEFAULT_SERVER_CLASS = "org.w3c.www.protocol.http.HttpBasicServer";
0084:
0085:            /**
0086:             * The name of the property indicating the class of HttpServer to use.
0087:             */
0088:            public static final String SERVER_CLASS_P = "org.w3c.www.protocol.http.server";
0089:
0090:            /**
0091:             * The name of the property containing the ProprequestFilter to launch.
0092:             */
0093:            public static final String FILTERS_PROP_P = "org.w3c.www.protocol.http.filters";
0094:            /**
0095:             * The maximum number of simultaneous connectionlrus.
0096:             */
0097:            public static final String CONN_MAX_P = "org.w3c.www.protocol.http.connections.max";
0098:            /**
0099:             * The SO_TIMEOUT of the client socket.
0100:             */
0101:            public static final String TIMEOUT_P = "org.w3c.www.protocol.http.connections.timeout";
0102:            /**
0103:             * The connection timeout of the client socket.
0104:             */
0105:            public static final String CONN_TIMEOUT_P = "org.w3c.www.protocol.http.connections.connTimeout";
0106:            /**
0107:             * Header properties - The allowed drift for getting cached resources.
0108:             */
0109:            public static final String MAX_STALE_P = "org.w3c.www.protocol.http.cacheControl.maxStale";
0110:            /**
0111:             * Header properties - The minium freshness required on cached resources.
0112:             */
0113:            public static final String MIN_FRESH_P = "org.w3c.www.protocol.http.cacheControl.minFresh";
0114:            /**
0115:             * Header properties - Set the only if cached flag on requests.
0116:             */
0117:            public static final String ONLY_IF_CACHED_P = "org.w3c.www.protocol.http.cacheControl.onlyIfCached";
0118:            /**
0119:             * Header properties - Set the user agent.
0120:             */
0121:            public static final String USER_AGENT_P = "org.w3c.www.protocol.http.userAgent";
0122:            /**
0123:             * Header properties - Set the accept header.
0124:             */
0125:            public static final String ACCEPT_P = "org.w3c.www.protocol.http.accept";
0126:            /**
0127:             * Header properties - Set the accept language.
0128:             */
0129:            public static final String ACCEPT_LANGUAGE_P = "org.w3c.www.protocol.http.acceptLanguage";
0130:            /**
0131:             * Header properties - Set the accept encodings.
0132:             */
0133:            public static final String ACCEPT_ENCODING_P = "org.w3c.www.protocol.http.acceptEncoding";
0134:            /**
0135:             * Header properties - are we parsing answers in a lenient way?
0136:             */
0137:            public static final String LENIENT_P = "org.w3c.www.protocol.http.lenient";
0138:            /**
0139:             * Header properties - should we reuse a connection for POST?
0140:             */
0141:            public static final String KEEPBODY_P = "org.w3c.www.protocol.http.keepbody";
0142:            /**
0143:             * Header properties - Should we use a proxy ?
0144:             */
0145:            public static final String PROXY_SET_P = "proxySet";
0146:            /**
0147:             * Header properties - What is the proxy host name.
0148:             */
0149:            public static final String PROXY_HOST_P = "proxyHost";
0150:            /**
0151:             * Header properties - What is the proxy port number.
0152:             */
0153:            public static final String PROXY_PORT_P = "proxyPort";
0154:
0155:            /**
0156:             * The default value for the <code>Accept</code> header.
0157:             */
0158:            public static final String DEFAULT_ACCEPT = "*/*";
0159:            /**
0160:             * The default value for the <code>User-Agent</code> header.
0161:             */
0162:            public static final String DEFAULT_USER_AGENT = "Jigsaw/2.2.6";
0163:
0164:            /**
0165:             * This array keeps track of all the created managers.
0166:             * A new manager (kind of HTTP client side context) is created for each
0167:             * diffferent set of properties.
0168:             */
0169:            private static ManagerDescription managers[] = new ManagerDescription[4];
0170:
0171:            /**
0172:             * The class to instantiate to create new HttpServer instances.
0173:             */
0174:            protected Class serverclass = null;
0175:            /**
0176:             * The properties we initialized from.
0177:             */
0178:            ObservableProperties props = null;
0179:            /**
0180:             * The server this manager knows about, indexed by FQDN of target servers.
0181:             */
0182:            protected Hashtable servers = null;
0183:            /**
0184:             * The template request (the request we will clone to create new requests)
0185:             */
0186:            protected Request template = null;
0187:            /**
0188:             * The LRU list of connections.
0189:             */
0190:            protected LRUList connectionsLru = null;
0191:            /**
0192:             * The filter engine attached to this manager.
0193:             */
0194:            FilterEngine filteng = null;
0195:
0196:            protected int timeout = 300000;
0197:            protected int conn_timeout = 3000;
0198:            protected int conn_count = 0;
0199:            protected int conn_max = 5;
0200:            protected boolean lenient = true;
0201:            protected boolean keepbody = false;
0202:
0203:            protected Hashtable _tmp_servers = null; // synced during creation
0204:
0205:            /**
0206:             * Update the proxy configuration to match current properties setting.
0207:             * @return A boolean, <strong>true</strong> if change was done,
0208:             * <strong>false</strong> otherwise.
0209:             */
0210:
0211:            protected boolean updateProxy() {
0212:                boolean set = props.getBoolean(PROXY_SET_P, false);
0213:                if (set) {
0214:                    // Wow using a proxy now !
0215:                    String host = props.getString(PROXY_HOST_P, null);
0216:                    int port = props.getInteger(PROXY_PORT_P, -1);
0217:                    URL proxy = null;
0218:                    try {
0219:                        proxy = new URL("http", host, port, "/");
0220:                    } catch (Exception ex) {
0221:                        return false;
0222:                    }
0223:                    // Now if a proxy...
0224:                    if ((proxy != null) && (proxy.getHost() != null))
0225:                        template.setProxy(proxy);
0226:                } else {
0227:                    template.setProxy(null);
0228:                }
0229:                return true;
0230:            }
0231:
0232:            /**
0233:             * Get this manager properties.
0234:             * @return An ObservableProperties instance.
0235:             */
0236:
0237:            public final ObservableProperties getProperties() {
0238:                return props;
0239:            }
0240:
0241:            /**
0242:             * PropertyMonitoring implementation - Update properties on the fly !
0243:             * @param name The name of the property that has changed.
0244:             * @return A boolean, <strong>true</strong> if change is accepted,
0245:             * <strong>false</strong> otherwise.
0246:             */
0247:
0248:            public boolean propertyChanged(String name) {
0249:                Request tpl = template;
0250:                if (name.equals(FILTERS_PROP_P)) {
0251:                    // FIXME
0252:                    return true;
0253:                    // return false;
0254:                } else if (name.equals(TIMEOUT_P)) {
0255:                    setTimeout(props.getInteger(TIMEOUT_P, timeout));
0256:                    return true;
0257:                } else if (name.equals(CONN_TIMEOUT_P)) {
0258:                    setConnTimeout(props.getInteger(CONN_TIMEOUT_P,
0259:                            conn_timeout));
0260:                    return true;
0261:                } else if (name.equals(CONN_MAX_P)) {
0262:                    setMaxConnections(props.getInteger(CONN_MAX_P, conn_max));
0263:                    return true;
0264:                } else if (name.equals(MAX_STALE_P)) {
0265:                    int ival = props.getInteger(MAX_STALE_P, -1);
0266:                    if (ival >= 0)
0267:                        tpl.setMaxStale(ival);
0268:                    return true;
0269:                } else if (name.equals(MIN_FRESH_P)) {
0270:                    int ival = props.getInteger(MIN_FRESH_P, -1);
0271:                    if (ival >= 0)
0272:                        tpl.setMinFresh(ival);
0273:                    return true;
0274:                } else if (name.equals(LENIENT_P)) {
0275:                    lenient = props.getBoolean(LENIENT_P, lenient);
0276:                    return true;
0277:                } else if (name.equals(KEEPBODY_P)) {
0278:                    keepbody = props.getBoolean(KEEPBODY_P, keepbody);
0279:                    return true;
0280:                }
0281:                if (name.equals(ONLY_IF_CACHED_P)) {
0282:                    tpl.setOnlyIfCached(props.getBoolean(ONLY_IF_CACHED_P,
0283:                            false));
0284:                    return true;
0285:                } else if (name.equals(USER_AGENT_P)) {
0286:                    tpl.setValue("user-agent", props.getString(USER_AGENT_P,
0287:                            DEFAULT_USER_AGENT));
0288:                    return true;
0289:                } else if (name.equals(ACCEPT_P)) {
0290:                    tpl.setValue("accept", props.getString(ACCEPT_P,
0291:                            DEFAULT_ACCEPT));
0292:                    return true;
0293:                } else if (name.equals(ACCEPT_LANGUAGE_P)) {
0294:                    String sval = props.getString(ACCEPT_LANGUAGE_P, null);
0295:                    if (sval != null)
0296:                        tpl.setValue("accept-language", sval);
0297:                    return true;
0298:                } else if (name.equals(ACCEPT_ENCODING_P)) {
0299:                    String sval = props.getString(ACCEPT_ENCODING_P, null);
0300:                    if (sval != null)
0301:                        tpl.setValue("accept-encoding", sval);
0302:                    return true;
0303:                } else if (name.equals(PROXY_SET_P)
0304:                        || name.equals(PROXY_HOST_P)
0305:                        || name.equals(PROXY_PORT_P)) {
0306:                    return updateProxy();
0307:                } else {
0308:                    return true;
0309:                }
0310:            }
0311:
0312:            /**
0313:             * Allow the manager to interact with the user if needed.
0314:             * This will, for example, allow prompting for paswords, etc.
0315:             * @param onoff Turn interaction on or off.
0316:             */
0317:
0318:            public void setAllowUserInteraction(boolean onoff) {
0319:                template.setAllowUserInteraction(onoff);
0320:            }
0321:
0322:            protected static synchronized HttpManager getManager(
0323:                    Class managerclass, Properties p) {
0324:                // Does such a manager exists already ?
0325:                for (int i = 0; i < managers.length; i++) {
0326:                    if (managers[i] == null)
0327:                        continue;
0328:                    if (managers[i].sameProperties(p))
0329:                        return managers[i].getManager();
0330:                }
0331:                // Get the props we will initialize from:
0332:                ObservableProperties props = null;
0333:                if (p instanceof  ObservableProperties)
0334:                    props = (ObservableProperties) p;
0335:                else
0336:                    props = new ObservableProperties(p);
0337:                // Create a new manager for this set of properties:
0338:                HttpManager manager = null;
0339:                ;
0340:                try {
0341:                    Object o = managerclass.newInstance();
0342:                    if (o instanceof  HttpManager) {
0343:                        manager = (HttpManager) o;
0344:                    } else { // default value
0345:                        manager = new HttpManager();
0346:                    }
0347:                } catch (Exception ex) {
0348:                    ex.printStackTrace();
0349:                    manager = new HttpManager();
0350:                }
0351:                manager.props = props;
0352:                // Initialize this new manager filters:
0353:                String filters[] = props.getStringArray(FILTERS_PROP_P, null);
0354:                if (filters != null) {
0355:                    for (int i = 0; i < filters.length; i++) {
0356:                        try {
0357:                            Class c = Class.forName(filters[i]);
0358:                            PropRequestFilter f = null;
0359:                            f = (PropRequestFilter) c.newInstance();
0360:                            f.initialize(manager);
0361:                        } catch (PropRequestFilterException ex) {
0362:                            System.out.println("Couldn't initialize filter \""
0363:                                    + filters[i] + "\" init failed: "
0364:                                    + ex.getMessage());
0365:                        } catch (Exception ex) {
0366:                            System.err
0367:                                    .println("Error initializing prop filters:");
0368:                            System.err.println("Coulnd't initialize ["
0369:                                    + filters[i] + "]: " + ex.getMessage());
0370:                            ex.printStackTrace();
0371:                            System.exit(1);
0372:                        }
0373:                    }
0374:                }
0375:                // The factory to create MIME reply holders:
0376:                manager.factory = manager.getReplyFactory();
0377:                // The class to create HttpServer instances from
0378:                String c = props
0379:                        .getString(SERVER_CLASS_P, DEFAULT_SERVER_CLASS);
0380:                try {
0381:                    manager.serverclass = Class.forName(c);
0382:                } catch (Exception ex) {
0383:                    System.err.println("Unable to initialize HttpManager: ");
0384:                    System.err.println("Class \"" + c
0385:                            + "\" not found, from property " + SERVER_CLASS_P);
0386:                    ex.printStackTrace();
0387:                    System.exit(1);
0388:                }
0389:                // Setup the template request:
0390:                Request tpl = manager.template;
0391:                // Set some default headers value (from props)
0392:                // Check for a proxy ?
0393:                manager.updateProxy();
0394:                // CacheControl, only-if-cached
0395:                tpl.setOnlyIfCached(props.getBoolean(ONLY_IF_CACHED_P, false));
0396:                // CacheControl, maxstale
0397:                int ival = props.getInteger(MAX_STALE_P, -1);
0398:                if (ival >= 0)
0399:                    tpl.setMaxStale(ival);
0400:                // CacheControl, minfresh:
0401:                ival = props.getInteger(MIN_FRESH_P, -1);
0402:                if (ival >= 0)
0403:                    tpl.setMinFresh(ival);
0404:                // general, lenient
0405:                manager.lenient = props.getBoolean(LENIENT_P, true);
0406:                manager.keepbody = props.getBoolean(KEEPBODY_P, false);
0407:                // General, User agent
0408:                String sval;
0409:                tpl.setValue("user-agent", props.getString(USER_AGENT_P,
0410:                        DEFAULT_USER_AGENT));
0411:                // General, Accept
0412:                tpl.setValue("accept", props
0413:                        .getString(ACCEPT_P, DEFAULT_ACCEPT));
0414:                // General, Accept-Language
0415:                sval = props.getString(ACCEPT_LANGUAGE_P, null);
0416:                if (sval != null) {
0417:                    if (sval.trim().length() > 0) {
0418:                        tpl.setValue("accept-language", sval);
0419:                    }
0420:                }
0421:                // General, Accept-Encoding
0422:                sval = props.getString(ACCEPT_ENCODING_P, null);
0423:                if (sval != null) {
0424:                    if (sval.trim().length() > 0) {
0425:                        tpl.setValue("accept-encoding", sval);
0426:                    }
0427:                }
0428:                // Maximum number of allowed connections:
0429:                manager.conn_max = props.getInteger(CONN_MAX_P, 5);
0430:                // timeout value
0431:                manager.timeout = props.getInteger(TIMEOUT_P, manager.timeout);
0432:                // connection timeout
0433:                manager.conn_timeout = props.getInteger(CONN_TIMEOUT_P,
0434:                        manager.conn_timeout);
0435:                // Register ourself as a property observer:
0436:                props.registerObserver(manager);
0437:                // Register that manager in our knwon managers:
0438:                for (int i = 0; i < managers.length; i++) {
0439:                    if (managers[i] == null) {
0440:                        managers[i] = new ManagerDescription(manager, p);
0441:                        return manager;
0442:                    }
0443:                }
0444:                ManagerDescription nm[] = new ManagerDescription[managers.length << 1];
0445:                System.arraycopy(managers, 0, nm, 0, managers.length);
0446:                nm[managers.length] = new ManagerDescription(manager, p);
0447:                managers = nm;
0448:                return manager;
0449:            }
0450:
0451:            /**
0452:             * Get an instance of the HTTP manager.
0453:             * This method returns an actual instance of the HTTP manager. It may
0454:             * return different managers, if it decides to distribute the load on
0455:             * different managers (avoid the HttpManager being a bottleneck).
0456:             * @return An application wide instance of the HTTP manager.
0457:             */
0458:
0459:            public static synchronized HttpManager getManager(Properties p) {
0460:                return getManager(HttpManager.class, p);
0461:            }
0462:
0463:            public static HttpManager getManager() {
0464:                return getManager(System.getProperties());
0465:            }
0466:
0467:            /**
0468:             * Get the String key for the server instance handling that request.
0469:             * This method takes care of any proxy setting (it will return the key
0470:             * to the proxy when required.)
0471:             * @return A uniq identifier for the handling server, as a String.
0472:             */
0473:
0474:            public final String getServerKey(Request request) {
0475:                URL proxy = request.getProxy();
0476:                URL target = request.getURL();
0477:                String key = null;
0478:                if (proxy != null) {
0479:                    return ((proxy.getPort() == 80) ? proxy.getHost()
0480:                            .toLowerCase() : (proxy.getHost().toLowerCase()
0481:                            + ":" + proxy.getPort()));
0482:                } else {
0483:                    return ((target.getPort() == 80) ? target.getHost()
0484:                            .toLowerCase() : (target.getHost().toLowerCase()
0485:                            + ":" + target.getPort()));
0486:                }
0487:            }
0488:
0489:            /**
0490:             * Get the appropriate server object for handling request to given target.
0491:             * @param key The server's key, as returned by <code>getServerKey</code>.
0492:             * @return An object complying to the HttpServer interface.
0493:             * @exception HttpException If the given host name couldn't be resolved.
0494:             */
0495:
0496:            protected HttpServer lookupServer(String host, int port)
0497:                    throws HttpException {
0498:                int p = (port == -1) ? 80 : port;
0499:                String id = ((p == 80) ? host.toLowerCase() : (host
0500:                        .toLowerCase()
0501:                        + ":" + p));
0502:                // Check for an existing server:
0503:                HttpServer server = (HttpServer) servers.get(id);
0504:                if (server != null) {
0505:                    return server;
0506:                }
0507:                // Create and register a new server:
0508:                synchronized (_tmp_servers) {
0509:                    if (_tmp_servers.containsKey(id)) {
0510:                        server = (HttpServer) _tmp_servers.get(id);
0511:                        synchronized (server) {
0512:                            while (server.state == null
0513:                                    || server.state.state != HttpServerState.PREINIT) {
0514:                                try {
0515:                                    wait(100);
0516:                                } catch (InterruptedException ex) {
0517:                                } catch (IllegalMonitorStateException ex) {
0518:                                    break;
0519:                                }
0520:                            }
0521:                        }
0522:                        if (server.state.state == HttpServerState.OK) {
0523:                            return server;
0524:                        } else if (server.state.ex != null) {
0525:                            throw server.state.ex;
0526:                        } else {
0527:                            throw new RuntimeException("Unexpected error "
0528:                                    + "in lookupServer");
0529:                        }
0530:                    } else {
0531:                        try {
0532:                            server = (HttpServer) serverclass.newInstance();
0533:                        } catch (Exception ex) {
0534:                            String msg = ("Unable to create an instance of \""
0535:                                    + serverclass.getName()
0536:                                    + "\", invalid config, check the "
0537:                                    + SERVER_CLASS_P + " property.");
0538:                            throw new HttpException(ex, msg);
0539:                        }
0540:                    }
0541:                }
0542:                try {
0543:                    synchronized (server) {
0544:                        server.initialize(this , new HttpServerState(server),
0545:                                host, p, timeout, conn_timeout);
0546:                        try {
0547:                            notifyAll();
0548:                        } catch (IllegalMonitorStateException imse) {
0549:                        }
0550:                        ;
0551:                    }
0552:                    // FIXME for long running servers the growing hashtable  is
0553:                    // a potential leak. This is a hard way of taking care of that
0554:                    //	    if (servers.size() > conn_max) {
0555:                    //		closeAnyConnection();
0556:                    //		servers = new Hashtable(conn_max);
0557:                    //	    }
0558:                } finally {
0559:                    synchronized (_tmp_servers) {
0560:                        if (server.state.state == HttpServerState.OK) {
0561:                            if (!servers.containsKey(id)) {
0562:                                servers.put(id, server);
0563:                            }
0564:                        } else {
0565:                            //		    System.err.println("ERROR State is "+server.state.state
0566:                            //				       +" for " + server);
0567:                        }
0568:                        _tmp_servers.remove(id);
0569:                    }
0570:                }
0571:                return server;
0572:            }
0573:
0574:            /**
0575:             * The given connection is about to be used.
0576:             * Update our list of available servers.
0577:             * @param conn The idle connection.
0578:             */
0579:
0580:            public synchronized void notifyUse(HttpConnection conn) {
0581:                if (debug)
0582:                    System.out.println("+++ connection used");
0583:                connectionsLru.remove(conn);
0584:            }
0585:
0586:            /**
0587:             * The given connection can be reused, but is now idle.
0588:             * @param conn The connection that is now idle.
0589:             */
0590:
0591:            public synchronized void notifyIdle(HttpConnection conn) {
0592:                if (debug)
0593:                    System.out.println("+++ connection idle");
0594:                connectionsLru.toHead(conn);
0595:                notifyAll();
0596:            }
0597:
0598:            /**
0599:             * The given connection has just been created.
0600:             * @param conn The newly created connection.
0601:             */
0602:
0603:            protected synchronized void notifyConnection(HttpConnection conn) {
0604:                if (debug)
0605:                    System.out.println("+++ notify conn_count "
0606:                            + (conn_count + 1) + " / " + conn_max);
0607:                if (++conn_count > conn_max)
0608:                    closeAnyConnection();
0609:            }
0610:
0611:            /**
0612:             * The given connection has been deleted.
0613:             * @param conn The deleted connection.
0614:             */
0615:
0616:            protected synchronized void deleteConnection(HttpConnection conn) {
0617:                --conn_count;
0618:                connectionsLru.remove(conn);
0619:                if (debug)
0620:                    System.out.println("+++ delete conn_count: " + conn_count);
0621:                notifyAll();
0622:            }
0623:
0624:            protected synchronized boolean tooManyConnections() {
0625:                return conn_count >= conn_max;
0626:            }
0627:
0628:            /**
0629:             * Try reusing one of the idle connection of that server, if any.
0630:             * @param server The target server.
0631:             * @return An currently idle connection to the given server.
0632:             */
0633:
0634:            protected synchronized HttpConnection getConnection(
0635:                    HttpServer server) {
0636:                HttpServerState ss = server.getState();
0637:                HttpConnection hcn = ss.getConnection();
0638:                if (hcn != null) {
0639:                    notifyUse(hcn);
0640:                }
0641:                return hcn;
0642:            }
0643:
0644:            /**
0645:             * Wait for a connection to come up.
0646:             * @param server, the target server.
0647:             * @exception InterruptedException If interrupted..
0648:             */
0649:
0650:            protected synchronized void waitForConnection(HttpServer server)
0651:                    throws InterruptedException {
0652:                wait(30000); // FIXME should be tunable, now set to 30s
0653:            }
0654:
0655:            /**
0656:             * Close some connections, but pickling the least recently used ones.
0657:             * One third of the max number of connection is cut. This is done to 
0658:             * eliminate the old connections that should be broken already.
0659:             * (no Socket.isAlive());
0660:             * @return A boolean, <strong>true</strong> if a connection was closed
0661:             * <strong>false</strong> otherwise.
0662:             */
0663:
0664:            protected synchronized boolean closeAnyConnection() {
0665:                boolean saved = false;
0666:                int max = Math.max(conn_max / 3, 1);
0667:                for (int i = 0; i < max; i++) {
0668:                    HttpConnection conn = (HttpConnection) connectionsLru
0669:                            .removeTail();
0670:                    if (conn != null) {
0671:                        conn.close();
0672:                        if (debug)
0673:                            System.out.println("+++ close request");
0674:                        saved = true;
0675:                    } else {
0676:                        break;
0677:                    }
0678:                }
0679:                // now purge the server Hashtable
0680:                synchronized (servers) {
0681:                    Enumeration e = servers.keys();
0682:                    if (debug) {
0683:                        System.out.println("+++ hashtable purge starting: "
0684:                                + servers.size() + " entries");
0685:                    }
0686:                    int nbconn = 0;
0687:                    int rnbconn = 0;
0688:                    int nbkept = 0;
0689:                    while (e.hasMoreElements()) {
0690:                        String id = (String) e.nextElement();
0691:                        if (id != null) {
0692:                            HttpServer server = (HttpServer) servers.get(id);
0693:                            int conn_count = server.state.getConnectionCount();
0694:                            if (conn_count <= 0) {
0695:                                if (debug) {
0696:                                    System.out.println("+++ hashtable purge: "
0697:                                            + id);
0698:                                }
0699:                                servers.remove(id);
0700:                            } else {
0701:                                if (debug) {
0702:                                    nbkept++;
0703:                                    nbconn += server.state.getConnectionCount();
0704:                                    if (server.state.conns != null) {
0705:                                        rnbconn += server.state.conns.size();
0706:                                    }
0707:                                    System.out.println("+++ hashtable keep: "
0708:                                            + id + " ( "
0709:                                            + server.state.getConnectionCount()
0710:                                            + " )");
0711:                                }
0712:                            }
0713:                        }
0714:                    }
0715:                    if (debug) {
0716:                        System.out.println("+++ hashtable purge done, keeping "
0717:                                + servers.size() + " entries");
0718:                        System.out.println("+++ hashtable stats, keeping "
0719:                                + nbconn + " ( " + rnbconn
0720:                                + " ) connections for " + nbkept
0721:                                + " servers ( "
0722:                                + ((float) nbconn / (float) nbkept) + " )");
0723:                    }
0724:
0725:                }
0726:                return saved;
0727:            }
0728:
0729:            /**
0730:             * One of our server handler wants to open a connection.
0731:             * @param block A boolean indicating whether we should block the calling
0732:             * thread until a token is available (otherwise, the method will just
0733:             * peek at the connection count, and return the appropriate result).
0734:             * @return A boolean, <strong>true</strong> if the connection can be
0735:             * opened straight, <strong>false</strong> otherwise.
0736:             */
0737:
0738:            protected boolean negotiateConnection(HttpServer server) {
0739:                HttpServerState ss = server.getState();
0740:                if (!tooManyConnections()) {
0741:                    return true;
0742:                } else if (ss.notEnoughConnections()) {
0743:                    return closeAnyConnection();
0744:                } else if (servers.size() > conn_max) {
0745:                    return closeAnyConnection();
0746:                }
0747:                return false;
0748:            }
0749:
0750:            /**
0751:             * A new client connection has been established.
0752:             * This method will try to maintain a maximum number of established
0753:             * connections, by closing idle connections when possible.
0754:             * @param server The server that has established a new connection.
0755:             */
0756:
0757:            protected final synchronized void incrConnCount(HttpServer server) {
0758:                if (++conn_count > conn_max)
0759:                    closeAnyConnection();
0760:                if (debug)
0761:                    System.out.println("+++ incr conn_count: " + conn_count);
0762:            }
0763:
0764:            /**
0765:             * Decrement the number of established connections.
0766:             * @param server The server that has closed one connection to its target.
0767:             */
0768:
0769:            protected final synchronized void decrConnCount(HttpServer server) {
0770:                --conn_count;
0771:                if (debug)
0772:                    System.out.println("+++ decr conn_count: " + conn_count);
0773:                if (conn_count < 0) {
0774:                    System.err.println(this );
0775:                }
0776:            }
0777:
0778:            /**
0779:             * Run the given request, in synchronous mode.
0780:             * This method will launch the given request, and block the calling thread
0781:             * until the response headers are available.
0782:             * @param request The request to run.
0783:             * @return An instance of Reply, containing all the reply 
0784:             * informations.
0785:             * @exception HttpException If something failed during request processing.
0786:             */
0787:
0788:            public Reply runRequest(Request request) throws HttpException {
0789:                Reply reply = null;
0790:                int fcalls = 0;
0791:                // Now run through the ingoing filters:
0792:                RequestFilter filters[] = filteng.run(request);
0793:                if (filters != null) {
0794:                    for (int i = 0; i < filters.length; i++) {
0795:                        if ((reply = filters[fcalls].ingoingFilter(request)) != null)
0796:                            break;
0797:                        fcalls++;
0798:                    }
0799:                }
0800:                // Locate the appropriate target server:
0801:                URL target = request.getURL();
0802:                if (reply == null) {
0803:                    HttpServer srv = null;
0804:                    boolean rtry;
0805:                    do {
0806:                        rtry = false;
0807:                        try {
0808:                            URL proxy = request.getProxy();
0809:                            if (proxy != null)
0810:                                srv = lookupServer(proxy.getHost(), proxy
0811:                                        .getPort());
0812:                            else
0813:                                srv = lookupServer(target.getHost(), target
0814:                                        .getPort());
0815:                            request.setServer(srv);
0816:                            reply = srv.runRequest(request);
0817:                        } catch (HttpException ex) {
0818:                            for (int i = 0; i < fcalls; i++)
0819:                                rtry = rtry
0820:                                        || filters[i].exceptionFilter(request,
0821:                                                ex);
0822:                            if (!rtry)
0823:                                throw ex;
0824:                        } finally {
0825:                            //		    request.unsetServer();
0826:                        }
0827:                    } while (rtry);
0828:                }
0829:                // Apply the filters on the way back:
0830:                if (filters != null) {
0831:                    while (--fcalls >= 0) {
0832:                        Reply frep = filters[fcalls].outgoingFilter(request,
0833:                                reply);
0834:                        if (frep != null) {
0835:                            reply = frep;
0836:                            break;
0837:                        }
0838:                    }
0839:                }
0840:                return reply;
0841:            }
0842:
0843:            /**
0844:             * Get this manager's reply factory.
0845:             * The Reply factory is used when prsing incomming reply from servers, it
0846:             * decides what object will be created to hold the actual reply from the 
0847:             * server.
0848:             * @return An object compatible with the MimeParserFactory interface.
0849:             */
0850:
0851:            MimeParserFactory factory = null;
0852:
0853:            public MimeParserFactory getReplyFactory() {
0854:                if (factory == null) {
0855:                    factory = new ReplyFactory();
0856:                }
0857:                return factory;
0858:            }
0859:
0860:            /**
0861:             * Add a new request filter.
0862:             * Request filters are called <em>before</em> a request is launched, and
0863:             * <em>after</em> the reply headers are available. They allow applications
0864:             * to setup specific request headers (such as PICS, or PEP stuff) on the
0865:             * way in, and check the reply on the way out.
0866:             * <p>Request filters are application wide: if their scope matches
0867:             * the current request, then they will always be aplied.
0868:             * <p>Filter scopes are defined inclusively and exclusively
0869:             * @param incs The URL domains for which the filter should be triggered.
0870:             * @param exs The URL domains for which the filter should not be triggered.
0871:             * @param filter The request filter to add.
0872:             */
0873:
0874:            public void setFilter(URL incs[], URL exs[], RequestFilter filter) {
0875:                if (incs != null) {
0876:                    for (int i = 0; i < incs.length; i++)
0877:                        filteng.setFilter(incs[i], true, filter);
0878:                }
0879:                if (exs != null) {
0880:                    for (int i = 0; i < exs.length; i++)
0881:                        filteng.setFilter(exs[i], false, filter);
0882:                }
0883:                return;
0884:            }
0885:
0886:            /**
0887:             * Add a global filter.
0888:             * The given filter will <em>always</em> be invoked.
0889:             * @param filter The filter to install.
0890:             */
0891:
0892:            public void setFilter(RequestFilter filter) {
0893:                filteng.setFilter(filter);
0894:            }
0895:
0896:            /**
0897:             * Find back an instance of a global filter.
0898:             * This methods allow external classes to get a pointer to installed
0899:             * filters of a given class.
0900:             * @param cls The class of the filter to look for.
0901:             * @return A RequestFilter instance, or <strong>null</strong> if not
0902:             * found.
0903:             */
0904:
0905:            public RequestFilter getGlobalFilter(Class cls) {
0906:                return filteng.getGlobalFilter(cls);
0907:            }
0908:
0909:            /**
0910:             * Create a new default outgoing request.
0911:             * This method should <em>always</em> be used to create outgoing requests.
0912:             * It will initialize the request with appropriate default values for 
0913:             * the various headers, and make sure that the request is enhanced by
0914:             * the registered request filters.
0915:             * @return An instance of Request, suitable to be launched.
0916:             */
0917:
0918:            public Request createRequest() {
0919:                return (Request) template.getDeeperClone();
0920:            }
0921:
0922:            /**
0923:             * Global settings - Set the max number of allowed connections.
0924:             * Set the maximum number of simultaneous connections that can remain
0925:             * opened. The manager will take care of queuing requests if this number
0926:             * is reached.
0927:             * <p>This value defaults to the value of the 
0928:             * <code>org.w3c.www.http.connections.max</code> property.
0929:             * @param max_conn The allowed maximum simultaneous open connections.
0930:             */
0931:
0932:            public synchronized void setMaxConnections(int max_conn) {
0933:                this .conn_max = max_conn;
0934:            }
0935:
0936:            /**
0937:             * Global settings - Set the timeout on the socket
0938:             *
0939:             * <p>This value defaults to the value of the 
0940:             * <code>org.w3c.www.http.connections.timeout</code> property.
0941:             * @param timeout The allowed maximum microsecond before a timeout.
0942:             */
0943:
0944:            public synchronized void setTimeout(int timeout) {
0945:                this .timeout = timeout;
0946:                Enumeration e = servers.elements();
0947:                while (e.hasMoreElements()) {
0948:                    ((HttpServer) e.nextElement()).setTimeout(timeout);
0949:                }
0950:            }
0951:
0952:            /**
0953:             * Global settings - Set the connection timeout for the socket
0954:             *
0955:             * <p>This value defaults to the value of the 
0956:             * <code>org.w3c.www.protocol.http.connections.connTimeout</code> property
0957:             * @param timeout The allowed maximum microsecond before a timeout.
0958:             */
0959:
0960:            public synchronized void setConnTimeout(int conn_timeout) {
0961:                this .conn_timeout = conn_timeout;
0962:                Enumeration e = servers.elements();
0963:                while (e.hasMoreElements()) {
0964:                    ((HttpServer) e.nextElement()).setConnTimeout(conn_timeout);
0965:                }
0966:            }
0967:
0968:            /**
0969:             * Global settings - set the HTTP parsing lenient or not.
0970:             * @param lenient, true by default, false to detect wrong servers
0971:             */
0972:            public void setLenient(boolean lenient) {
0973:                this .lenient = lenient;
0974:            }
0975:
0976:            /**
0977:             * Is this manager parsing headers in a lenient way?
0978:             * @return A boolean.
0979:             */
0980:            public boolean isLenient() {
0981:                return lenient;
0982:            }
0983:
0984:            /**
0985:             * Global settings - Set an optional proxy to use.
0986:             * Set the proxy to which all requests should be targeted. If the
0987:             * <code>org.w3c.www.http.proxy</code> property is defined, it will be
0988:             * used as the default value.
0989:             * @param proxy The URL for the proxy to use.
0990:             */
0991:
0992:            public void setProxy(URL proxy) {
0993:                template.setProxy(proxy);
0994:            }
0995:
0996:            /**
0997:             * Does this manager uses a proxy to fulfill requests ?
0998:             * @return A boolean.
0999:             */
1000:
1001:            public boolean usingProxy() {
1002:                return template.hasProxy();
1003:            }
1004:
1005:            /**
1006:             * Global settings - Set the request timeout.
1007:             * Once a request has been emited, the HttpManager will sit for this 
1008:             * given number of milliseconds before the request is declared to have
1009:             * timed-out.
1010:             * <p>This timeout value defaults to the value of the
1011:             * <code>org.w3c.www.http.requestTimeout</code> property value.
1012:             * @param ms The timeout value in milliseconds.
1013:             */
1014:
1015:            public void setRequestTimeout(int ms) {
1016:            }
1017:
1018:            /**
1019:             * Global settings - Define a global request header.
1020:             * Set a default value for some request header. Once defined, the
1021:             * header will automatically be defined on <em>all</em> outgoing requests
1022:             * created through the <code>createRequest</code> request.
1023:             * @param name The name of the header, case insensitive.
1024:             * @param value It's default value.
1025:             */
1026:
1027:            public void setGlobalHeader(String name, String value) {
1028:                org.w3c.util.Trace.showTrace();
1029:                System.err.println("**** " + name + " : " + value);
1030:                template.setValue(name, value);
1031:            }
1032:
1033:            /**
1034:             * Global settings - Get a global request header default value.
1035:             * @param name The name of the header to get.
1036:             * @return The value for that header, as a String, or <strong>
1037:             * null</strong> if undefined.
1038:             */
1039:
1040:            public String getGlobalHeader(String name) {
1041:                return template.getValue(name);
1042:            }
1043:
1044:            /**
1045:             * Dump all in-memory cached state to persistent storage.
1046:             */
1047:
1048:            public void sync() {
1049:                filteng.sync();
1050:            }
1051:
1052:            /**
1053:             * Create a new HttpManager.
1054:             * FIXME Making this method protected breaks the static method
1055:             * to create HttpManager instances (should use a factory here)
1056:             * @param props The properties from which the manager should initialize 
1057:             * itself, or <strong>null</strong> if none are available.
1058:             */
1059:
1060:            protected HttpManager() {
1061:                this .template = new Request(this );
1062:                this .servers = new Hashtable();
1063:                this ._tmp_servers = new Hashtable();
1064:                this .filteng = new FilterEngine();
1065:                this .connectionsLru = new SyncLRUList();
1066:            }
1067:
1068:            /**
1069:             * DEBUGGING !
1070:             */
1071:
1072:            public synchronized String toString() {
1073:                StringBuffer sb = new StringBuffer();
1074:                HttpConnection hcn = (HttpConnection) connectionsLru.getHead();
1075:                sb.append("Connections: ");
1076:                sb.append(conn_count);
1077:                sb.append(" out of ");
1078:                sb.append(conn_max);
1079:                sb.append("\n\n");
1080:                if (hcn != null) {
1081:                    sb.append("**** Idle Connections list ****\n");
1082:                    while (hcn != null) {
1083:                        sb.append("      ");
1084:                        sb.append(hcn.toString());
1085:                        sb.append('\n');
1086:                        try {
1087:                            hcn = (HttpConnection) hcn.getNext();
1088:                        } catch (ClassCastException ccex) {
1089:                            break;
1090:                        }
1091:                    }
1092:                } else {
1093:                    sb.append("*** NO IDLE CONNECTIONS ***\n");
1094:                }
1095:                sb.append(servers);
1096:                return sb.toString();
1097:            }
1098:
1099:            public static void main(String args[]) {
1100:                try {
1101:                    // Get the manager, and define some global headers:
1102:                    HttpManager manager = HttpManager.getManager();
1103:                    manager.setGlobalHeader("User-Agent", DEFAULT_USER_AGENT);
1104:                    manager.setGlobalHeader("Accept", "*/*;q=1.0");
1105:                    manager.setGlobalHeader("Accept-Encoding", "gzip");
1106:                    PropRequestFilter filter = new org.w3c.www.protocol.http.cookies.CookieFilter();
1107:                    filter.initialize(manager);
1108:                    PropRequestFilter pdebug = new org.w3c.www.protocol.http.DebugFilter();
1109:                    pdebug.initialize(manager);
1110:                    Request request = manager.createRequest();
1111:                    request.setURL(new URL(args[0]));
1112:                    request.setMethod("GET");
1113:                    Reply reply = manager.runRequest(request);
1114:                    //Display some infos:
1115:                    System.out.println("last-modified: "
1116:                            + reply.getLastModified());
1117:                    System.out.println("length       : "
1118:                            + reply.getContentLength());
1119:                    // Display the returned body:
1120:                    InputStream in = reply.getInputStream();
1121:                    byte buf[] = new byte[4096];
1122:                    int cnt = 0;
1123:                    while ((cnt = in.read(buf)) >= 0) {
1124:                        //	      System.out.print(new String(buf, 0, cnt));
1125:                    }
1126:                    System.out.println("-");
1127:                    in.close();
1128:                    manager.sync();
1129:                    System.err.println(manager);
1130:                } catch (Exception ex) {
1131:                    ex.printStackTrace();
1132:                    if (ex instanceof  HttpException) {
1133:                        ((HttpException) ex).getException().printStackTrace();
1134:                    }
1135:                }
1136:                System.exit(1);
1137:            }
1138:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.