Source Code Cross Referenced for Server.java in  » Web-Server » pygmy-httpd » pygmy » core » 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 » pygmy httpd » pygmy.core 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package pygmy.core;
002:
003:        import java.io.*;
004:        import java.util.*;
005:        import java.util.logging.Logger;
006:        import java.util.logging.Level;
007:        import java.util.logging.LogManager;
008:        import java.lang.reflect.Constructor;
009:        import java.lang.reflect.InvocationTargetException;
010:
011:        /**
012:         * <p>
013:         * Server is the core of the system.  A server glues together {@link Handler}s
014:         * and {@link EndPoint}s.  {@link EndPoint}s are responsible for reading the
015:         * {@link HttpRequest} from a source and sending the HttpResponse over that source.
016:         * {@link EndPoint}s then sends the request to the {@link Handler} by calling the post()
017:         * method on the server to send the request to this server's {@link Handler}s.  {@link Handler}s
018:         * process the {@link HttpRequest} and produce an appropriate {@link HttpResponse}.
019:         * </p><p>
020:         * The server contains the configuration for the entire server.  What are the expected values
021:         * in the configuration is mainly controlled by what handlers and endpoints are configured.
022:         * Depending on which handlers and endpoints have been enabled, the configuration will vary.
023:         * The only two parameters are required: <i>handler</i> and <i>&lt;handler's name&gt;.class</i>.
024:         * Here is an example configuration:
025:         * </p><pre>
026:         * <div class="code">
027:         * handler=my\ handler
028:         * my\ handler.class=pygmy.handlers.DefaultChainHandler
029:         * my\ handler.chain=handler1, handler2
030:         * my\ handler.url-prefix=/
031:         *
032:         * handler1.class=pygmy.handlers.FileHandler
033:         * handler1.root=C:\temp
034:         * handler1.url-prefix=/home-directory
035:         *
036:         * handler2.class=pygmy.handlers.ResourceHandler
037:         * handler2.url-prefix=/jar
038:         * handler2.resourceMount=/html
039:         * handler2.default=index.html
040:         * </pre>
041:         * </div
042:         * <p>
043:         * In the above configuration, <i>handler</i> property is the name of first handler.
044:         * The name is used to find all the other properties for that particular handler.
045:         * The .class property is used to tell the Server the name of the class to instantiate.
046:         * The two other properties, .chain and .url-prefix, are particular to the
047:         * {@link pygmy.handlers.DefaultChainHandler}.
048:         * </p><p>
049:         * Server's only have <b>one</b> {@link Handler}.  However, the power of
050:         * {@link Handler}s is the ability to have more than one. The
051:         * {@link pygmy.handlers.DefaultChainHandler} provides the ability to create a
052:         * chain of multiple handlers.  See {@link pygmy.handlers.DefaultChainHandler} for
053:         * information on configuring it.
054:         * </p><p>
055:         * Server also contains a set of {@link pygmy.core.EndPoint}s.  When the server initializes
056:         * itself it looks in the configuration for the <i>endpoints</i> parameter.  The <i>endpoints</i>
057:         * parameter contains a space seperated list of the names of the endpoints this server will
058:         * create.  For each name in the list it will look for a config parameter
059:         * <i>&lt;name of endpoint&gt;.class</i> in the configuration.  It will instantiate the classname
060:         * using the no-argument constructor and add it to the set of endpoints in the server.
061:         * </p><p>
062:         * If the server does not find the <i>endpoints</i> parameter, then it will create a default EndPoint
063:         * of type {@link pygmy.core.ServerSocketEndPoint} named http.  Here is an example of using the <i>endpoints</i>
064:         * parameter:
065:         * </p>
066:         * <div class="code">
067:         * <pre>
068:         * endpoints=endpoint1 endpoint2
069:         * handler=handler1
070:         *
071:         * endpoint1.class=my.package.MyEndPoint
072:         * endpoint1.param1=foo
073:         * endpoint1.param2=bar
074:         * endpoint2.class=my.package.AnotherEndPoint
075:         * endpoint2.param1=foo
076:         * endpoint2.param2=bar
077:         * endpoint2.param3=baz
078:         * ...
079:         * </pre>
080:         * </div>
081:         * <p>
082:         * Server class looks for the following properties in the configuration:
083:         * </p>
084:         * <table class="inner">
085:         * <tr class="header"><td>Parameter Name</td><td>Default Value</td><td>Required</td></tr>
086:         * <tr class="row"><td>handler</td><td>None</td><td>Yes</td></tr>
087:         * <tr class="altrow"><td>endpoints</td><td>http</td><td>No</td></tr>
088:         * <tr class="row"><td>&lt;handler name&gt;.class</td><td>None</td><td>Yes</td></tr>
089:         * <tr class="altrow"><td>&lt;endpoint name&gt;.class</td><td>None</td><td>iff endpoints param is defined</td></tr>
090:         * <tr class="row"><td>threadpool.size</td><td>5</td><td>No</td></tr>
091:         * </table>
092:         */
093:        public class Server implements  Runnable {
094:
095:            private static final Logger log = Logger.getLogger(Server.class
096:                    .getName());
097:
098:            Properties config = new ChainableProperties();
099:            HashMap endpoints = new HashMap();
100:            Handler handler = null;
101:            ResponseListener responseListener = null;
102:            ThreadPool threadPool;
103:
104:            private static final String CLAZZ = ".class";
105:
106:            /**
107:             * This creates a server using the given filename as the configuration for this server.  The configuration file
108:             * should follow format of normal {@link java.util.Properties} file.
109:             *
110:             * @param filename the path to a file to use as the configuration of this server.
111:             * @throws IOException
112:             */
113:            public Server(String filename) throws IOException {
114:                InputStream is = null;
115:                try {
116:                    is = new BufferedInputStream(new FileInputStream(filename));
117:                    config.load(is);
118:                } finally {
119:                    if (is != null) {
120:                        is.close();
121:                    }
122:                }
123:            }
124:
125:            /**
126:             * This creates a server using the given configuration.
127:             *
128:             * @param config the configuration to use for this server.
129:             */
130:            public Server(Properties config) {
131:                this .config = config;
132:            }
133:
134:            /**
135:             * This creates a server from commandline arguments.
136:             *
137:             * @param args an array of config parameters, the format of the list is a '-' followed by either 'config' or some
138:             * name of a parameter (i.e. http.port), and a space and a value for that property.  All -config will load a file
139:             * either from the filesystem or the class path if the file doesn't exist on the filesystem.
140:             */
141:            public Server(String[] args) throws IOException {
142:                config = new ChainableProperties();
143:                processArguments(args, config);
144:            }
145:
146:            /**
147:             * This method adds an {@link EndPoint} to this server.  It will be initialized once the {@link #start} method is called.
148:             * @param name The name of this EndPoint instance.
149:             * @param endpoint The instance of the endpoint to add.
150:             */
151:            public void addEndPoint(String name, EndPoint endpoint) {
152:                endpoints.put(name, endpoint);
153:            }
154:
155:            // todo delete this method.  it isn't used.
156:            //    /**
157:            //     * This sets the handler instance for the server.  The handlername is used to pass to the
158:            //     * {@link Handler#initialize} method.
159:            //     *
160:            //     * @param handlerName the name that should be assigned to this handler.
161:            //     * @param handler the instance of the handler used by this server to service requests.
162:            //     */
163:            //    public void setHandler( String handlerName, Handler handler ) {
164:            //        this.rootHandlersName = handlerName;
165:            //        this.handler = handler;
166:            //    }
167:
168:            /**
169:             * This puts a configuration property into the server's configuration.
170:             *
171:             * @param key The unique key to store the value under.
172:             * @param value The value of the key.
173:             */
174:            public void putProperty(Object key, Object value) {
175:                config.put(key, value);
176:            }
177:
178:            /**
179:             * Returns the property stored under the key.
180:             * @param key the configuration key to look up.
181:             * @return the value stored in the configuration at this key.
182:             */
183:            public String getProperty(String key) {
184:                return config.getProperty(key);
185:            }
186:
187:            /**
188:             * Returns the property stored under the key.  If there isn't a property called key, then it returns the defaultValue.
189:             * @param key the configuration key to look up.
190:             * @param defaultValue the defaultValue returned if nothing is found under the key.
191:             * @return the value stored in the configuration at this key.
192:             */
193:            public String getProperty(String key, String defaultValue) {
194:                return config.getProperty(key, defaultValue);
195:            }
196:
197:            /**
198:             * Returns true iff the key is in the configuration
199:             * @param key the name of the key.
200:             * @return true if and only if the key is contained in the configuration. False otherwise.
201:             */
202:            public boolean hasProperty(String key) {
203:                return config.containsKey(key);
204:            }
205:
206:            /**
207:             * This returns the object stored under the given key.
208:             *
209:             * @param key the key to look up the stored object.
210:             * @return the object stored at the given key.
211:             */
212:            public Object get(Object key) {
213:                return config.get(key);
214:            }
215:
216:            /**
217:             * Returns the configuration for the server.
218:             * @return the configuration for the server.
219:             */
220:            public Properties getConfig() {
221:                return config;
222:            }
223:
224:            public Object getRegisteredComponent(Class clazz) {
225:                return config.get(clazz);
226:            }
227:
228:            /**
229:             * This is called when a program wants to register a shared component for Handlers to have access to.  The objects's
230:             * class will be the defining key for identitying the object.  Registering more than one instance will not
231:             * be supported.  If you're program must differ between two instances, then register a manager and allow the
232:             * Handler's to interact with that to differentiate the individual instances.
233:             *
234:             * @param object the object the user wants to make available to Handler instances.
235:             */
236:            public void registerComponent(Object object) {
237:                config.put(object.getClass(), object);
238:            }
239:
240:            /**
241:             * This method is called to start the web server.  It will initialize the server's Handler and all the EndPoints
242:             * then call the {@link EndPoint#start} on each EndPoint.  This method will return after the above steps are
243:             * done.
244:             */
245:            public void start() {
246:                Runtime.getRuntime().addShutdownHook(
247:                        new Thread(this , "PygmyShutdown"));
248:                initializeThreads();
249:                initializeHandler();
250:                if (handler == null) {
251:                    return;
252:                }
253:
254:                constructEndPoints();
255:
256:                for (Iterator i = endpoints.values().iterator(); i.hasNext();) {
257:                    EndPoint currentEndPoint = (EndPoint) i.next();
258:                    currentEndPoint.start();
259:                }
260:            }
261:
262:            private void initializeThreads() {
263:                try {
264:                    threadPool = new ThreadPool(Integer.parseInt(config
265:                            .getProperty("threadpool.size", "5")));
266:                } catch (NumberFormatException e) {
267:                    log
268:                            .warning("threadpool.size was not a number using default of 5");
269:                    threadPool = new ThreadPool(5);
270:                }
271:            }
272:
273:            protected void initializeHandler() {
274:                if (handler == null) {
275:                    handler = (Handler) constructPygmyObject(getProperty("handler"));
276:                }
277:                handler.initialize(getProperty("handler"), this );
278:            }
279:
280:            /**
281:             * This is the method used to construct pygmy objects.  Given the object name it appends .class onto the end and
282:             * looks for the classname in the server's configuration.  It then analyzes the class's constructor parameters for
283:             * objects that it depends on.  Then it looks those objects up by class in the registered object pool.  Finally, it
284:             * calls the constructor using reflection passing any registered objects as arguments.  It returns
285:             * the newly constructed object or null if there was a problem.
286:             *
287:             * @param objectName the name of the object defined in the server's configuration.
288:             * @return the newly constructed object, or null there was a problem instantiated the object.
289:             */
290:            public Object constructPygmyObject(String objectName) {
291:                Object theObject = null;
292:                String objectClassname = getProperty(objectName + CLAZZ);
293:                try {
294:                    if (objectClassname == null)
295:                        throw new ClassNotFoundException(objectName + CLAZZ
296:                                + " configuration property not found.");
297:                    Class handlerClass = Class.forName(objectClassname);
298:                    Constructor[] constructors = handlerClass.getConstructors();
299:                    Class[] paramClass = constructors[0].getParameterTypes();
300:                    Object[] params = new Object[paramClass.length];
301:                    for (int i = 0; i < paramClass.length; i++) {
302:                        if (paramClass[i].equals(Server.class)) {
303:                            params[i] = this ;
304:                        } else if (paramClass[i].equals(String.class)) {
305:                            params[i] = objectName;
306:                        } else {
307:                            params[i] = getRegisteredComponent(paramClass[i]);
308:                        }
309:                    }
310:                    theObject = constructors[0].newInstance(params);
311:                    log.config("Pygmy object constructed. object=" + objectName
312:                            + " class=" + objectClassname);
313:                } catch (IllegalAccessException e) {
314:                    log
315:                            .log(
316:                                    Level.SEVERE,
317:                                    "Could not access constructor.  Make sure it has the constructor is public.  Service not started.  class="
318:                                            + objectClassname, e);
319:                } catch (InstantiationException e) {
320:                    log.log(Level.SEVERE,
321:                            "Could not instantiate object.  Service not started.  class="
322:                                    + objectClassname, e);
323:                } catch (ClassNotFoundException e) {
324:                    log.log(Level.SEVERE,
325:                            "Could not find class.  Service not started.  class="
326:                                    + objectClassname, e);
327:                } catch (InvocationTargetException e) {
328:                    log
329:                            .log(
330:                                    Level.SEVERE,
331:                                    "Could not instantiate object because constructor threw an exception.  Service not started.  class="
332:                                            + objectClassname, e);
333:                    log.log(Level.SEVERE, "Cause:", e.getTargetException());
334:                }
335:                return theObject;
336:            }
337:
338:            private void constructEndPoints() {
339:                String val = getProperty("endpoints");
340:                if (val != null) {
341:                    StringTokenizer tokenizer = new StringTokenizer(val);
342:                    while (tokenizer.hasMoreTokens()) {
343:                        String endPointName = tokenizer.nextToken();
344:                        try {
345:                            EndPoint endPoint = (EndPoint) constructPygmyObject(endPointName);
346:                            endPoint.initialize(endPointName, this );
347:                            addEndPoint(endPointName, endPoint);
348:                        } catch (IOException e) {
349:                            log.log(Level.SEVERE, endPointName
350:                                    + " was not initialized properly.", e);
351:                        }
352:                    }
353:                } else {
354:                    log.log(Level.SEVERE, "No endpoints defined.");
355:                }
356:            }
357:
358:            /**
359:             * This is called when the server is shutdown thread is called.
360:             */
361:            public void run() {
362:                shutdown();
363:                synchronized (this ) {
364:                    this .notify();
365:                }
366:            }
367:
368:            /**
369:             * This method will shutdown the Handler, and call {@link EndPoint#shutdown} on each EndPoint.
370:             */
371:            public void shutdown() {
372:                log.info("Starting shutdown.");
373:                try {
374:                    threadPool.shutdown();
375:                    if (handler != null) {
376:                        log.info("Shutting down handlers.");
377:                        handler.shutdown(this );
378:                    }
379:                    Collection values = endpoints.values();
380:                    if (values != null) {
381:                        for (Iterator i = values.iterator(); i.hasNext();) {
382:                            EndPoint currentEndPoint = (EndPoint) i.next();
383:                            log.info("Shutting down endpoint "
384:                                    + currentEndPoint.getName());
385:                            currentEndPoint.shutdown(this );
386:                        }
387:                    }
388:                } finally {
389:                    log.info("Shutdown complete.");
390:                }
391:            }
392:
393:            /**
394:             * This method is used to post a {@link HttpRequest} to the server's handler.  It will create a HttpResponse
395:             * for the EndPoint to send to the client.
396:             * @param request
397:             * @return A HttpResponse that corresponds to the HttpRequest being handled.
398:             * @throws IOException
399:             */
400:            public boolean post(Request request, Response response)
401:                    throws IOException {
402:                return handler.handle(request, response);
403:            }
404:
405:            /**
406:             * This method posts a Runnable onto the Server's task queue.  The server's {@link ThreadPool} will service the
407:             * runnable once a thread is freed up.
408:             * @param runnable An instance of Runnable that the user wishes to run on the server's {@link ThreadPool}.
409:             */
410:            public void post(Runnable runnable) {
411:                threadPool.execute(runnable);
412:            }
413:
414:            /**
415:             * Returns the instance of the ResponseListener for this Server.
416:             *
417:             * @return the ResponseListener for this Server, or null if there is none.
418:             */
419:            public ResponseListener getResponseListeners() {
420:                return responseListener;
421:            }
422:
423:            /**
424:             * This sets the ResponseListener for entire server.  All replys being sent to any client will
425:             * be notified to this instance.
426:             *
427:             * @param listener the instance of a ResponseListener to use for this Server.
428:             */
429:            public void setResponseListener(ResponseListener listener) {
430:                this .responseListener = listener;
431:            }
432:
433:            public static void main(String[] args) throws IOException {
434:                Server server = new Server(args);
435:                try {
436:                    server.start();
437:                    System.out
438:                            .println("Server started.  Press <Ctrl-C> to stop.");
439:                    synchronized (server) {
440:                        server.wait();
441:                    }
442:                } catch (InterruptedException e) {
443:                    log.log(Level.INFO, "Server Interupted.");
444:                }
445:            }
446:
447:            protected void processArguments(String[] args, Properties props)
448:                    throws IOException {
449:                for (int i = 0; i < args.length; i += 2) {
450:                    if (args[i].equalsIgnoreCase("-config")) {
451:                        if (i + 1 < args.length) {
452:                            loadConfiguration(args[i + 1], props);
453:                        } else {
454:                            throw new IOException(
455:                                    "-config parameter must be followed by a config file.");
456:                        }
457:                    } else if (args[i].startsWith("-")) {
458:                        props.setProperty(args[i].substring(1), args[i + 1]);
459:                    }
460:                }
461:                setDefaultProperties(props);
462:                setupLogging(props);
463:            }
464:
465:            private void setupLogging(Properties props) throws IOException {
466:                ByteArrayOutputStream stream = new ByteArrayOutputStream();
467:                props.store(stream, "");
468:                ByteArrayInputStream bais = new ByteArrayInputStream(stream
469:                        .toByteArray());
470:                LogManager.getLogManager().readConfiguration(bais);
471:            }
472:
473:            private static void setDefaultProperties(Properties props) {
474:                setDefaultProperty(props, "mime.html", "text/html");
475:                setDefaultProperty(props, "mime.zip",
476:                        "application/x-zip-compressed");
477:                setDefaultProperty(props, "mime.gif", "image/gif");
478:                setDefaultProperty(props, "mime.jpeg", "image/jpeg");
479:                setDefaultProperty(props, "mime.jpg", "image/jpeg");
480:                setDefaultProperty(props, "mime.css", "text/css");
481:                setDefaultProperty(props, "http.port", "80");
482:                setDefaultProperty(props, "handler", "chain");
483:                setDefaultProperty(props, "chain.class",
484:                        "pygmy.handlers.DefaultChainHandler");
485:                setDefaultProperty(props, "chain.chain", "root");
486:                // sets a default endpoint for http
487:                setDefaultProperty(props, "endpoints", "http");
488:                setDefaultProperty(props, "http.class",
489:                        "pygmy.core.ServerSocketEndPoint");
490:                // these are properties read by the ResourceHandler named 'root'
491:                setDefaultProperty(props, "root.class",
492:                        "pygmy.handlers.ResourceHandler");
493:                setDefaultProperty(props, "root.urlPrefix", "/");
494:                setDefaultProperty(props, "root.resourceMount", "/doc");
495:            }
496:
497:            private static void setDefaultProperty(Properties props,
498:                    String key, String value) {
499:                if (props.getProperty(key) == null) {
500:                    props.setProperty(key, value);
501:                }
502:            }
503:
504:            protected void loadConfiguration(String config, Properties props)
505:                    throws IOException {
506:                InputStream is = openInputStream(config);
507:                props.load(is);
508:                is.close();
509:            }
510:
511:            private InputStream openInputStream(String config)
512:                    throws FileNotFoundException {
513:                InputStream is;
514:                try {
515:                    is = new FileInputStream(config);
516:                } catch (FileNotFoundException e) {
517:                    is = Server.class.getResourceAsStream("/" + config);
518:                    if (is == null)
519:                        throw e;
520:                }
521:                return is;
522:            }
523:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.