Source Code Cross Referenced for PrefixResolver.java in  » Web-Server » simple » simple » http » load » 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 » simple » simple.http.load 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * PrefixResolver.java July 2003
003:         *
004:         * Copyright (C) 2003, Niall Gallagher <niallg@users.sf.net>
005:         *
006:         * This library is free software; you can redistribute it and/or
007:         * modify it under the terms of the GNU Lesser General Public
008:         * License as published by the Free Software Foundation.
009:         *
010:         * This library is distributed in the hope that it will be useful,
011:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
012:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
013:         * GNU Lesser General Public License for more details.
014:         *
015:         * You should have received a copy of the GNU Lesser General 
016:         * Public License along with this library; if not, write to the 
017:         * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
018:         * Boston, MA  02111-1307  USA
019:         */
020:
021:        package simple.http.load;
022:
023:        import simple.util.xml.Node;
024:        import simple.util.xml.Traverser;
025:        import simple.http.serve.Locator;
026:        import simple.util.PriorityQueue;
027:        import java.io.IOException;
028:        import java.util.Properties;
029:        import java.util.HashMap;
030:        import java.util.Map;
031:        import java.util.Set;
032:        import java.io.File;
033:
034:        /**
035:         * The <code>PrefixResolver</code> is used to extract service names
036:         * and types from an XML configuration file. Each service name can
037:         * be associated with match and prepare XML elements, which can be 
038:         * used to determine the URI targets used to locate the services 
039:         * and the properties that are be used to initialize the service. 
040:         * <p> 
041:         * This is used to implement a scheme similar to the Java Servlet
042:         * context path mapping scheme. In this scheme a prefix path is 
043:         * used to resolve a Servlet, and the remaining path part is then
044:         * used to acquire a resource relative the the Servlet context.
045:         *
046:         * @author Niall Gallagher
047:         */
048:        public class PrefixResolver extends Traverser {
049:
050:            /**
051:             * This is the configuration setup for a service instance.
052:             */
053:            private Configuration setup;
054:
055:            /**
056:             * This is used to collect properties taken from the document.
057:             */
058:            private Properties table;
059:
060:            /**
061:             * This contains the paths ordered by length decreasing.
062:             */
063:            private String[] list;
064:
065:            /**
066:             * This contains a list of offsets used for optimization.
067:             */
068:            private int[] skip;
069:
070:            /**
071:             * This is used to store the properties for each service.
072:             */
073:            private Map data;
074:
075:            /**
076:             * This map contains the service name to class name pairs.
077:             */
078:            private Map load;
079:
080:            /**
081:             * This map that contains the prefix to service name pairs.
082:             */
083:            private Map map;
084:
085:            /**
086:             * Constructor for the <code>PrefixResolver</code>. This uses
087:             * a configuration file located with the <code>Locator</code>
088:             * object supplied. Once the configuration file is located the 
089:             * service names can be resolved for arbitrary URI paths.
090:             *
091:             * @param lookup the locator used to find the configuration
092:             */
093:            public PrefixResolver(Locator lookup) {
094:                this (lookup, 256);
095:            }
096:
097:            /**
098:             * Constructor for the <code>PrefixResolver</code>. This uses
099:             * a configuration file located with the <code>Locator</code>
100:             * object supplied. Once the configuration file is located the 
101:             * service names can be resolved for arbitrary URI paths. 
102:             * <p>
103:             * This includes a parameter that enables a maximum expected
104:             * path length to be entered. This helps to optimize the
105:             * resolution of a path prefix. This should typically be at
106:             * least big enough to include the maximum possible path.
107:             *
108:             * @param lookup the object used to perform configuration
109:             * @param max this is the maximum path length expected
110:             */
111:            public PrefixResolver(Locator lookup, int max) {
112:                this .setup = new Configuration();
113:                this .table = new Properties();
114:                this .data = new HashMap();
115:                this .load = new HashMap();
116:                this .map = new HashMap();
117:                this .skip = new int[max];
118:                this .init(lookup);
119:            }
120:
121:            /** 
122:             * This will attempt to acquire an XML configuration file that 
123:             * is used to resolve relative URI paths to service names. The 
124:             * configuration file is located using the <code>Locator</code>
125:             * supplied. This will search for the file using the names
126:             * "Mapper.xml" and "mapper.xml" in that sequence.
127:             *
128:             * @param lookup the locator used to find the configuration
129:             */
130:            private void init(Locator lookup) {
131:                try {
132:                    load(lookup);
133:                } catch (Exception e) {
134:                    e.printStackTrace();
135:                }
136:            }
137:
138:            /** 
139:             * This <code>load</code> method attempts to load the XML file
140:             * file <code>Mapper.xml</code> using the given locator. If
141:             * the configuration file exists then it is used to describe
142:             * mappings used to load the service instances.
143:             * <p>
144:             * This will attempt to load the file using the UTF-8 charset
145:             * so that international characters can be used for prefixes 
146:             * that can be used. This is compatible with ISO-8859-1.
147:             *
148:             * @param lookup this is the locator used to find the file
149:             *
150:             * @exception Exception thrown if there is an I/O problem
151:             */
152:            private void load(Locator lookup) throws Exception {
153:                try {
154:                    load(lookup, "Mapper.xml");
155:                } catch (IOException e) {
156:                    load(lookup, "mapper.xml");
157:                }
158:            }
159:
160:            /**
161:             * This will load the named file from within the given path. This
162:             * is used so that a configuration file can be loaded by a locator
163:             * using the specified file name. If the XML configuration file
164:             * cannot be loaded this will throw an <code>Exception</code>. 
165:             *
166:             * @param lookup this is the locator used to discover the file
167:             * @param name this is the name of the configuration file loaded
168:             *
169:             * @exception Exception thrown if there is an I/O problem
170:             */
171:            private void load(Locator lookup, String name) throws Exception {
172:                parse(lookup.getFile(name), "utf-8");
173:            }
174:
175:            /** 
176:             * This method is used retrieve properties for a service by
177:             * using the service name. This will acquire the properties
178:             * if any for the named service instance. The properties will
179:             * contain zero or more name value pairs. If no properties
180:             * are associated with the service the instance returned
181:             * will be an empty map rather than a null object.
182:             *
183:             * @param name this is the name of the service instance
184:             *
185:             * @return returns a properties object for configuration
186:             */
187:            public Configuration getConfiguration(String name) {
188:                return (Configuration) data.get(name);
189:            }
190:
191:            /**
192:             * Used to resolve the class name using a service name. This is
193:             * required to resolve the class name once the service name has
194:             * been acquired from the <code>getName</code> method. If there
195:             * is no match for the service name then null is returned. 
196:             *
197:             * @param name this is the service name to get a class name for
198:             *
199:             * @return the class name that matches the service name given
200:             */
201:            public String getClass(String name) {
202:                return (String) load.get(name);
203:            }
204:
205:            /**
206:             * Used to resolve the service name using a path prefix. This is
207:             * required to resolve the service name once the prefix of the
208:             * path is acquired from the <code>getPrefix</code> method. If
209:             * there is no match for the prefix then null is returned. 
210:             *
211:             * @param prefix the path prefix to acquire a service name for
212:             *
213:             * @return the service name that matches the prefix path given
214:             */
215:            public String getName(String prefix) {
216:                return (String) map.get(prefix);
217:            }
218:
219:            /**
220:             * Used to get the prefix path for the given relative URI path,
221:             * which must be normalized. This will attempt to match the
222:             * start of the given path to the highest directory path. For
223:             * example, given the URI path <code>/pub/bin/README</code>,
224:             * the start of the path will be compared for a prefix. So it
225:             * should match <code>/pub/bin/</code>, <code>/bin/</code>,
226:             * and finally <code>/</code> in that order. 
227:             *
228:             * @param normal the normalized URI path to get a prefix for
229:             *
230:             * @return the highest matched directory for the given path
231:             */
232:            public String getPrefix(String normal) {
233:                int size = normal.length();
234:                int off = 0;
235:
236:                if (size < skip.length) {
237:                    off = skip[size];
238:                }
239:                for (int i = off; i < list.length; i++) {
240:                    if (normal.startsWith(list[i])) {
241:                        return list[i];
242:                    }
243:                }
244:                return "/";
245:            }
246:
247:            /**
248:             * Used to acquire the path relative to the prefix. This will
249:             * return the path as it is relative to the prefix resolved 
250:             * for the given normalized path. This will remove the start
251:             * of the given normalized path if it matches a prefix path.
252:             *
253:             * @param normal the normalized URI path to get a path for
254:             *
255:             * @return the full path once its prefix has been removed 
256:             */
257:            public String getPath(String normal) {
258:                String prefix = getPrefix(normal);
259:                int size = prefix.length() - 1;
260:
261:                return normal.substring(size);
262:            }
263:
264:            /**
265:             * This method is used to initialize this resolver. This will
266:             * clear out all data structures used in the parsing process. 
267:             * It is invoked before the <code>process</code> method is used.
268:             * to evaluate the element nodes extracted from the XML document.
269:             */
270:            protected void start() {
271:                setup.clear();
272:                table.clear();
273:                load.clear();
274:                map.clear();
275:                data.clear();
276:            }
277:
278:            /**
279:             * This is used to process a element node extracted from the XML
280:             * document. It will be given each element that exists within
281:             * the document. The elements of interest to this implementation
282:             * are the "property", "match", "section", and "service" elements.
283:             *
284:             * @param node this is the node to be evaluated by this method
285:             */
286:            protected void process(Node node) {
287:                String name = node.getName();
288:
289:                if (name.equals("match")) {
290:                    match(node);
291:                }
292:                if (name.equals("service")) {
293:                    setup.clear();
294:                    table.clear();
295:                }
296:                if (name.equals("section")) {
297:                    setup.putAll(table);
298:                    table.clear();
299:                }
300:            }
301:
302:            /**
303:             * This is used to commit any data that has been collected during
304:             * the processing of an element node. The elements of interest to
305:             * this method are the "service" and "property" elements. This
306:             * will save the properties collected for each "service" element.
307:             *
308:             * @param node this is the node to be committed by this method
309:             */
310:            protected void commit(Node node) {
311:                String name = node.getName();
312:
313:                if (name.equals("service")) {
314:                    service(node);
315:                }
316:                if (name.equals("property")) {
317:                    property(node);
318:                }
319:                if (name.equals("section")) {
320:                    section(node);
321:                }
322:            }
323:
324:            /**
325:             * This method is used to add the collected properties into the
326:             * configuration using a section identity. This allows properties
327:             * to be grouped, which enables services to use certain property
328:             * values to perform specific configuration operations.
329:             *
330:             * @param node this is the node that represents a section 
331:             */
332:            private void section(Node node) {
333:                String name = node.getAttribute("id");
334:
335:                if (name != null) {
336:                    setup.put(name, table.clone());
337:                    table.clear();
338:                }
339:            }
340:
341:            /**
342:             * This method is used to save a service definition along with 
343:             * all properties collected for that service. This will collect
344:             * the "name" and "type" attributes from the "service" element
345:             * before saving all properties collected and then storing the
346:             * properties and type under the service "name" attribute.
347:             *
348:             * @param node this is the node that represents a service
349:             */
350:            private void service(Node node) {
351:                String name = node.getAttribute("name");
352:                String type = node.getAttribute("type");
353:
354:                if (name != null) {
355:                    setup.putAll(table);
356:                    data.put(name, setup.clone());
357:                    load.put(name, type);
358:                }
359:            }
360:
361:            /**
362:             * This is used to store the matches extracted from the document.
363:             * The attributes taken from the provided element are the "name"
364:             * and "path" attributes. The path represents the prefix used to
365:             * resolve to a specific service. The "name" attribute represents
366:             * an identifier for the service instance.
367:             *
368:             * @param node this represents a match element from the XML tree
369:             */
370:            private void match(Node node) {
371:                String name = node.getAttribute("name");
372:                String path = node.getAttribute("path");
373:
374:                if (path != null) {
375:                    map.put(path, name);
376:                }
377:            }
378:
379:            /**
380:             * This method will extract property XML tags from the provided
381:             * text. This expression must contain a key attribute and must
382:             * also contain a value to be extracted sucessfully. The node,
383:             * should look like the XML BNF expression described below.
384:             * <pre>
385:             * 
386:             *    node = "&lt;property" key "&gt;" *TEXT "&lt;/property&gt;"
387:             *    key  = "key" "=" token
388:             *
389:             * </pre>
390:             * If the element does not contain text between the opening
391:             * and closing tags then the property will not be saved. Also
392:             * if the key attribute is null the entry is not committed.
393:             *
394:             * @param node the node that represents a property element
395:             */
396:            private void property(Node node) {
397:                String name = node.getAttribute("key");
398:
399:                if (name != null) {
400:                    table.put(name, node.getProperty());
401:                }
402:            }
403:
404:            /**
405:             * Used to prepare the prefix paths so that they can be matched
406:             * with relative URI paths quickly. The XML configuration file
407:             * used to specify the prefix paths with the service and class 
408:             * names will be loaded unordered into a <code>HashMap</code>.
409:             * This ensures the acquired keys are sorted for searching.
410:             */
411:            protected void finish() {
412:                index(map.keySet());
413:            }
414:
415:            /**
416:             * Used to prepare the prefix paths so that they can be matched
417:             * with relative URI paths quickly. The XML configuration file
418:             * used to specify the prefix paths with the service and class 
419:             * names will be loaded unordered into a <code>HashMap</code>.
420:             * This ensures the acquired keys are sorted for searching. 
421:             *
422:             * @param set this contains the acquired keys to be sorted
423:             */
424:            private void index(Set set) {
425:                list = new String[set.size()];
426:                set.toArray(list);
427:                prepare(list);
428:                sort(list);
429:                optimize(skip);
430:            }
431:
432:            /**
433:             * This is used to prepare the prefix paths so that they all
434:             * end with the <code>/</code> character. If the prefix paths
435:             * within the XML configuration file do not correspond to a
436:             * directory path this will simply append a <code>/</code>.
437:             * For example if the configuration file was as follows.
438:             *
439:             * <pre>
440:             * &lt;resolve match="/demo" name="demo" type="demo.Demo"/&gt;
441:             * &lt;resolve match="/test/" name="test" type="test.Test"/&gt;
442:             * </pre>
443:             *
444:             * The prefix <code>/demo</code>, which does not end in the
445:             * <code>/</code> character, becomes <code>/path/</code>. 
446:             * This ensures that relative paths will be predictable.
447:             *
448:             * @param list this is the list of prefix paths to be fixed  
449:             */
450:            private void prepare(String[] list) {
451:                for (int i = 0; i < list.length; i++) {
452:                    Object data = map.remove(list[i]);
453:
454:                    if (!list[i].endsWith("/")) {
455:                        list[i] += "/";
456:                    }
457:                    map.put(list[i], data);
458:                }
459:            }
460:
461:            /**
462:             * This method is used to sort the list of strings by length. 
463:             * Sorting the strings by length is done so that the selection 
464:             * of a suitable path prefix will match the highest matching
465:             * directory. For example if <code>/path/bin/index.html</code>
466:             * was the path and the prefix paths loaded were as follows.
467:             *
468:             * <pre>
469:             *    "/path/"="package.PathService"
470:             *    "/path/bin/"="package.BinSerivce"
471:             *    "/path/doc/"="package.DocService"
472:             * </pre>
473:             *
474:             * Then the path prefix match should be the highest directory,
475:             * which would be <code>/path/bin/</code>. In order to make
476:             * the match rapidly then the paths should be searched in
477:             * order of length, so that when a prefix matches it is used.
478:             *
479:             * @param list contains the strings that are to be sorted
480:             */
481:            private void sort(String[] list) {
482:                PriorityQueue queue = new PriorityQueue();
483:
484:                for (int i = 0; i < list.length; i++) {
485:                    queue.add(list[i], list[i].length());
486:                }
487:                for (int i = 0; i < list.length; i++) {
488:                    list[i] = (String) queue.remove();
489:                }
490:            }
491:
492:            /**
493:             * This method is used to optimize the searching for prefixes
494:             * by setting a list of offsets within a skip list. The skip
495:             * list contains an offset within each index. Each index in
496:             * the skip list corrosponds to a path length and the offset
497:             * within that index corrosponds to an offset into the list
498:             * of prefix paths. Setting up a skip list in this manner is
499:             * useful in determining where to start resolutions.
500:             * <p>
501:             * Taking the path <code>/pub/index.html</code> for example.
502:             * This path cannot possibly have a prefix path that has a
503:             * length larger than it, like <code>/pub/bin/example/</code>
504:             * as it is longer than it. So the skip list will basically
505:             * allow a path to determine how many prefixes it can skip
506:             * before the prefix size is less than or equal to its size.
507:             *
508:             * @param skip this is the list of offsets to be prepared
509:             */
510:            private void optimize(int[] skip) {
511:                int size = skip.length - 1;
512:                int off = 0;
513:
514:                while (off < list.length) {
515:                    if (list[off].length() < size) {
516:                        skip[size--] = off;
517:                    } else {
518:                        while (off < list.length) {
519:                            if (list[off].length() < size) {
520:                                break;
521:                            }
522:                            skip[size] = off++;
523:                        }
524:                        size--;
525:                    }
526:                }
527:                while (size > 0) {
528:                    skip[size--] = off - 1;
529:                }
530:            }
531:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.