Source Code Cross Referenced for SSIFrame.java in  » Web-Server » Jigsaw » org » w3c » jigsaw » ssi » 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.jigsaw.ssi 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        // Ssiframe.java
002:        // $Id: SSIFrame.java,v 1.13 2000/08/16 21:37:46 ylafon Exp $
003:        // (c) COPYRIGHT MIT and INRIA, 1996.
004:        // Please first read the full copyright statement in file COPYRIGHT.html
005:
006:        package org.w3c.jigsaw.ssi;
007:
008:        import java.io.ByteArrayOutputStream;
009:        import java.io.File;
010:        import java.io.FileInputStream;
011:        import java.io.IOException;
012:        import java.io.PrintStream;
013:        import java.io.RandomAccessFile;
014:
015:        import java.util.Dictionary;
016:        import java.util.Vector;
017:
018:        import org.w3c.www.http.HTTP;
019:        import org.w3c.www.http.HeaderValue;
020:        import org.w3c.www.http.HttpDate;
021:        import org.w3c.www.http.HttpEntityMessage;
022:        import org.w3c.www.http.HttpInteger;
023:        import org.w3c.www.http.HttpMessage;
024:        import org.w3c.www.http.HttpReplyMessage;
025:        import org.w3c.www.http.HttpRequestMessage;
026:
027:        import org.w3c.tools.resources.Attribute;
028:        import org.w3c.tools.resources.AttributeHolder;
029:        import org.w3c.tools.resources.AttributeRegistry;
030:        import org.w3c.tools.resources.BooleanAttribute;
031:        import org.w3c.tools.resources.ClassAttribute;
032:        import org.w3c.tools.resources.FileResource;
033:        import org.w3c.tools.resources.IntegerAttribute;
034:        import org.w3c.tools.resources.ProtocolException;
035:        import org.w3c.tools.resources.ReplyInterface;
036:        import org.w3c.tools.resources.RequestInterface;
037:        import org.w3c.tools.resources.Resource;
038:        import org.w3c.tools.resources.ResourceException;
039:
040:        import org.w3c.tools.resources.event.AttributeChangedEvent;
041:
042:        import org.w3c.jigsaw.http.HTTPException;
043:        import org.w3c.jigsaw.http.Reply;
044:        import org.w3c.jigsaw.http.Request;
045:
046:        import org.w3c.jigsaw.frames.HTTPFrame;
047:
048:        import org.w3c.util.ArrayDictionary;
049:
050:        import org.w3c.jigsaw.ssi.commands.CommandRegistry;
051:
052:        import org.w3c.tools.resources.ProtocolException;
053:        import org.w3c.tools.resources.ResourceException;
054:
055:        /**
056:         * This resource implements server-side parsing of HTML documents.
057:         * Any comment of the form <code>&lt;!--#commandName param1=val1
058:         * ... paramn=valn --&gt;</code> will be interpreted as an include
059:         * directive.
060:         * <p> Commands are looked up in an instance of the class
061:         * supplied in the registryClass attribute, which must be a subclass
062:         * of <code>org.w3c.jigsaw.ssi.CommandRegistry</code>.
063:         *
064:         * @author Antonio Ramirez <anto@mit.edu>
065:         * @author Benoit Mahe <bmahe@sophia.inria.fr>
066:         * @see org.w3c.jigsaw.ssi.commands.CommandRegistry
067:         * @see org.w3c.jigsaw.ssi.commands.Command
068:         */
069:
070:        public class SSIFrame extends HTTPFrame {
071:
072:            public static final boolean debug = false;
073:
074:            /** Attributes index - The segments */
075:            private static int ATTR_SEGMENTS = -1;
076:
077:            /** Attributes index - The total unparsed size */
078:            private static int ATTR_UNPARSED_SIZE = -1;
079:
080:            /** Attribute index - The class to use for making the CommandRegistry */
081:            private static int ATTR_REGISTRY_CLASS = -1;
082:
083:            /** Attributes index - The maximum recursive parsing depth */
084:            private static int ATTR_MAX_DEPTH = -1;
085:
086:            /** Attribute index - Whether or not to deny insecure commands */
087:            private static int ATTR_SECURE = -1;
088:
089:            /**
090:             * The command registry used by the resource.
091:             */
092:            private CommandRegistry commReg = null;
093:
094:            /**
095:             * The most specific class of the current command registry.
096:             */
097:            private Class regClass = null;
098:
099:            /**
100:             * Here we keep track of created registries to avoid
101:             * making more than one per registry class.
102:             */
103:            private static Dictionary regs = new ArrayDictionary(5);
104:
105:            /** Will hold the increments for finding "<!--#" */
106:            private static byte startIncrements[] = new byte[128];
107:
108:            /** Same thing for "-->" */
109:            private static byte endIncrements[] = new byte[128];
110:
111:            /** The start pattern */
112:            private static byte startPat[] = { (byte) '<', (byte) '!',
113:                    (byte) '-', (byte) '-', (byte) '#' };
114:
115:            /** The end pattern */
116:            private static byte endPat[] = { (byte) '-', (byte) '-', (byte) '>' };
117:
118:            // For value-less parameters 
119:            private static final String emptyString = "";
120:
121:            /**
122:             * Our "very global" variables
123:             */
124:            protected Dictionary vars = null;
125:
126:            /**
127:             * Message state - the current recursion depth
128:             */
129:            public static final String STATE_DEPTH = "org.w3c.jigsaw.ssi.SSIResource.depth";
130:
131:            /**
132:             * Message state - the current variables
133:             */
134:            public static final String STATE_VARIABLES = "org.w3c.jigsaw.ssi.SSIResource.variables";
135:
136:            private boolean cacheReplies = true;
137:
138:            protected void doNotCacheReply() {
139:                cacheReplies = false;
140:            }
141:
142:            protected boolean cacheReplies() {
143:                return cacheReplies;
144:            }
145:
146:            /**
147:             * Listen its resource.
148:             */
149:            public void attributeChanged(AttributeChangedEvent evt) {
150:                super .attributeChanged(evt);
151:                String name = evt.getAttribute().getName();
152:                if ((name.equals("file-stamp")) || (name.equals("file-length"))) {
153:                    setValue(ATTR_SEGMENTS, (Segment[]) null);
154:                }
155:            }
156:
157:            private final int getUnparsedSize() {
158:                return getInt(ATTR_UNPARSED_SIZE, -1);
159:            }
160:
161:            private final void setUnparsedSize(int unparsedSize) {
162:                setValue(ATTR_UNPARSED_SIZE, new Integer(unparsedSize));
163:            }
164:
165:            /**
166:             * Makes sure that checkContent() is called on _any_ HTTP method,
167:             * so that the internal representation of commands is always consistent.
168:             * @param request The HTTPRequest
169:             * @param filters The filters to apply
170:             * @return a ReplyInterface instance
171:             * @exception ProtocolException If processing the request failed.
172:             * @exception ResourceException If this resource got a fatal error.
173:             */
174:
175:            public ReplyInterface perform(RequestInterface request)
176:                    throws ProtocolException, ResourceException {
177:                if (!checkRequest(request)) {
178:                    return performFrames(request);
179:                }
180:                if (fresource != null)
181:                    fresource.checkContent();
182:                return super .perform(request);
183:            }
184:
185:            /**
186:             * Perform a get (associated with a FileResource)
187:             * @param request the HTTP request
188:             * @return a Reply instance.
189:             * @exception ProtocolException If processing the request failed.
190:             * @exception ResourceException If this resource got a fatal error.
191:             */
192:            protected Reply getFileResource(Request request)
193:                    throws ProtocolException, ResourceException {
194:                Reply reply = handle(request);
195:                return reply != null ? reply : super .getFileResource(request);
196:            }
197:
198:            /**
199:             * Perform a post.
200:             * @param request the HTTP request
201:             * @return a Reply instance.
202:             * @exception ProtocolException If processing the request failed.
203:             * @exception ResourceException If this resource got a fatal error.
204:             */
205:            public Reply post(Request request) throws ProtocolException,
206:                    ResourceException {
207:                Reply reply = handle(request);
208:                return reply != null ? reply : super .post(request);
209:            }
210:
211:            /**
212:             * Handles all relevant HTTP methods.
213:             * Merges the partial replies from each of the segments into
214:             * one global reply.
215:             * <strong>Remark</strong>: no direct relation to PostableResource.handle()
216:             * @param request The HTTP request
217:             * @return a Reply instance.
218:             * @exception ProtocolException If processing the request failed.
219:             */
220:
221:            public Reply handle(Request request) throws ProtocolException {
222:                if (fresource == null)
223:                    return null;
224:
225:                if (SSIFrame.debug)
226:                    System.out.println("@@@@ handle: "
227:                            + (request.isInternal() ? "internal" : "external"));
228:                fresource.checkContent();
229:
230:                Integer depth = (Integer) request.getState(STATE_DEPTH);
231:                if (depth == null)
232:                    depth = new Integer(0);
233:
234:                int unparsedSize = 0;
235:
236:                Segment[] segments = getSegments();
237:                if (segments == null) {
238:                    parseFirstTime();
239:                    if ((segments = getSegments()) == null)
240:                        return null; // Last resort: fall back to superclass
241:                }
242:                Reply reply = null;
243:                try {
244:                    // Obtain a command registry
245:                    updateRegistry();
246:
247:                    vars = (Dictionary) request.getState(STATE_VARIABLES);
248:
249:                    // Initialize the registry-dependent variables:
250:                    vars = commReg.initVariables(this , request, vars);
251:
252:                    // Add our "very global" variables
253:                    vars.put("secure", getValue(ATTR_SECURE, Boolean.TRUE));
254:                    vars.put("maxDepth", getValue(ATTR_MAX_DEPTH, new Integer(
255:                            10)));
256:                    vars.put("depth", depth);
257:                    vars.put("registry", commReg);
258:
259:                    // Prepare the initial reply
260:                    // (which represents the unparsed parts of the document)
261:                    // and a prototype reply for segments that return null.
262:                    reply = createDefaultReply(request, HTTP.OK);
263:                    Reply defSegReply = createDefaultReply(request, HTTP.OK);
264:
265:                    int unpSize = getUnparsedSize();
266:                    if (unpSize == -1)
267:                        reply.setHeaderValue(Reply.H_CONTENT_LENGTH, null);
268:                    else
269:                        reply.setContentLength(unpSize);
270:                    defSegReply.setHeaderValue(Reply.H_CONTENT_LENGTH, null);
271:
272:                    long ims = request.getIfModifiedSince();
273:                    long cmt = fresource.getFileStamp();
274:                    // used to be getLastModified()
275:                    // should be something better
276:                    // than either
277:                    if (SSIFrame.debug)
278:                        System.out.println("@@@@ IMS: " + cmt + " vs " + ims);
279:                    if (ims != -1 && cmt != -1 && cmt <= ims) {
280:                        reply.setStatus(HTTP.NOT_MODIFIED);
281:                        defSegReply.setStatus(HTTP.NOT_MODIFIED);
282:                    } else if (ims != -1) {
283:                        if (SSIFrame.debug)
284:                            System.out.println("@@@@ Removed NOT MODIFIED");
285:                    }
286:
287:                    if (cmt != -1)
288:                        defSegReply.setLastModified(cmt);
289:
290:                    // For each segment:
291:                    // 	. obtain a reply,
292:                    // 	. merge its headers with the global reply's headers,
293:                    Reply[] partReps = new Reply[segments.length];
294:                    for (int i = 0; i < segments.length; i++) {
295:                        if (!segments[i].isUnparsed()) {
296:                            if (SSIFrame.debug)
297:                                System.out.println("@@@@ Analyzing segment "
298:                                        + segments[i]);
299:
300:                            partReps[i] = segments[i].init(this , request, vars,
301:                                    commReg, i);
302:
303:                            if (SSIFrame.debug) {
304:                                if (partReps[i] == null)
305:                                    System.out.println("@@@@ (null segment)");
306:                                System.out.println("@@@@ cacheReplies : "
307:                                        + cacheReplies());
308:                            }
309:
310:                            merge(reply, partReps[i] != null ? partReps[i]
311:                                    : defSegReply);
312:                        }
313:                    }
314:
315:                    // Set a stream, unless we're not supposed to.
316:                    // Also handle the case of no command segments.
317:                    switch (reply.getStatus()) {
318:                    default:
319:                        reply.setStream(new SSIStream(cacheReplies(), segments,
320:                                partReps, new RandomAccessFile(fresource
321:                                        .getFile(), "r")));
322:                    case HTTP.NO_CONTENT:
323:                    case HTTP.NOT_MODIFIED:
324:                    }
325:
326:                    if (SSIFrame.debug)
327:                        System.out.println("@@@@ Last-modified: "
328:                                + reply.getLastModified());
329:
330:                    reply.setDate(System.currentTimeMillis());
331:                    return reply;
332:
333:                } catch (SSIException ex) {
334:                    reply = createDefaultReply(request,
335:                            HTTP.INTERNAL_SERVER_ERROR);
336:                    reply.setContent("SSIFrame is misconfigured: "
337:                            + ex.getMessage());
338:                    throw new HTTPException(reply);
339:                } catch (Exception ex) {
340:                    ex.printStackTrace();
341:                    if (SSIFrame.debug) {
342:                        if (SSIFrame.debug)
343:                            System.out.println("@@@@ Fallback to FileResource");
344:                    }
345:                    return null; // Last resort: fall back to superclass
346:                }
347:            }
348:
349:            // The headers to merge and their corresponding callbacks
350:            // (more to come)
351:            private static final int mergeHeaders[] = { Reply.H_AGE,
352:                    Reply.H_CONTENT_LENGTH, Reply.H_EXPIRES,
353:                    Reply.H_LAST_MODIFIED, };
354:
355:            private static final Merger mergers[] = { new IntMaximizer(), // 	Reply.H_AGE
356:                    new IntAdder(), // 	Reply.H_CONTENT_LENGTH
357:                    new DateMinimizer(), // 	Reply.H_EXPIRES
358:                    new DateMaximizer() // 	Reply.H_LAST_MODIFIED
359:            };
360:
361:            /**
362:             * Merges the headers (and status code) of a segment's reply with
363:             * those of the global reply.
364:             *
365:             * @param glob the global reply
366:             * @param part the segment's partial reply
367:             */
368:            private void merge(Reply glob, Reply part) {
369:                // Deal with status code first
370:                int pstat = part.getStatus();
371:                int gstat = glob.getStatus();
372:
373:                if (pstat == HTTP.NOT_MODIFIED) {
374:                    switch (gstat) {
375:                    default:
376:                        glob.setStatus(HTTP.OK);
377:                    case HTTP.NOT_MODIFIED:
378:                    }
379:                } else if (gstat == HTTP.NOT_MODIFIED) {
380:                    if (SSIFrame.debug)
381:                        System.out.println("**** removed NOT MODIFIED");
382:                    glob.setStatus(HTTP.OK);
383:                }
384:
385:                // Now handle headers
386:                // "pointers to methods" would make this simpler
387:                for (int i = 0; i < mergeHeaders.length; i++)
388:                    glob.setHeaderValue(mergeHeaders[i], mergers[i].merge(glob
389:                            .getHeaderValue(mergeHeaders[i]), part
390:                            .getHeaderValue(mergeHeaders[i])));
391:
392:                // Now handle annoying quasi-headers:
393:                int pint, gint;
394:
395:                // Cache-Control: max-age=n
396:                // (don't merge if set as attribute)
397:                if (getMaxAge() != -1 && (pint = part.getMaxAge()) != -1) {
398:                    if ((gint = glob.getMaxAge()) != -1)
399:                        pint = Math.min(gint, pint);
400:                    glob.setMaxAge(pint);
401:                }
402:            }
403:
404:            /**
405:             * Retrieves the segments from the attribute
406:             * @return An array of segments
407:             */
408:            private final Segment[] getSegments() {
409:                return (Segment[]) getValue(ATTR_SEGMENTS, null);
410:            }
411:
412:            /**
413:             * Updates the working command registry if either the registryClass
414:             * attribute has changed or it has never been created before.
415:             * <p>To avoid unnecessarily creating command registry
416:             * instances, this method will keep track of which kinds of command
417:             * registries have been created, and avoid making duplicates.
418:             * @exception SSIException If the operation can't be performed.
419:             */
420:            private void updateRegistry() throws SSIException {
421:                try {
422:                    Class attrRegClass = (Class) getValue(ATTR_REGISTRY_CLASS,
423:                            null);
424:                    if (attrRegClass == null)
425:                        attrRegClass = Class
426:                                .forName("org.w3c.jigsaw.ssi.commands.DefaultCommandRegistry");
427:
428:                    if (regClass == null || !attrRegClass.equals(regClass)) {
429:                        regClass = attrRegClass;
430:                        commReg = fetchRegistry(regClass);
431:                    }
432:                } catch (ClassNotFoundException ex) {
433:                    throw new SSIException("Cannot make registry: "
434:                            + ex.getMessage());
435:                }
436:            }
437:
438:            /**
439:             * Returns an instance of the given command registry class,
440:             * either a new instance, or an old one if it exists in the dictionary.
441:             * @exception SSIException If the operation can't be performed.
442:             */
443:            private CommandRegistry fetchRegistry(Class regClass)
444:                    throws SSIException {
445:                try {
446:                    CommandRegistry reg = (CommandRegistry) regs.get(regClass);
447:                    if (reg != null)
448:                        return reg;
449:                    else {
450:                        reg = (CommandRegistry) regClass.newInstance();
451:                        regs.put(regClass, reg);
452:                        return reg;
453:                    }
454:                } catch (Exception ex) {
455:                    throw new SSIException("Cannot fetch command registry: "
456:                            + ex.getMessage());
457:                }
458:            }
459:
460:            /** Reads the unparsed file into memory, if not already done */
461:            private byte[] readUnparsed() throws IOException {
462:                File file = fresource.getFile();
463:                ByteArrayOutputStream out = new ByteArrayOutputStream(
464:                        (int) file.length());
465:
466:                FileInputStream in = new FileInputStream(file);
467:
468:                byte[] buf = new byte[4096];
469:                int len = 0;
470:
471:                while ((len = in.read(buf)) != -1)
472:                    out.write(buf, 0, len);
473:
474:                in.close();
475:                out.close();
476:
477:                byte[] unparsed = out.toByteArray();
478:                return unparsed;
479:            }
480:
481:            /**
482:             * Does a first-time parse and sets the segment list attribute
483:             * accordingly.
484:             */
485:            private void parseFirstTime() {
486:                if (debug)
487:                    System.out.println("@@@ parseFirstTime");
488:                cacheReplies = true;
489:                byte[] unparsed = null;
490:                try {
491:                    unparsed = readUnparsed();
492:                } catch (IOException ex) {
493:                    setValue(ATTR_SEGMENTS, null);
494:                    return;
495:                }
496:
497:                // The parsing code was adapted from phttpd 
498:
499:                int byteIdx = 0, startInc, endInc, startParam, endParam, paramIdx, i;
500:                byte ch, quote;
501:                int max, length = 0;
502:                boolean valueFound;
503:
504:                int unparsedSize = 0;
505:
506:                // For maintaining the segment list 
507:                Vector buildSegments = new Vector(20);
508:
509:                StringBuffer cmdBuf = null;
510:                String cmdName = null;
511:                Vector /*<String>*/parNames = null;
512:                Vector /*<String>*/parValues = null;
513:                String name = null, value = null;
514:
515:                // To store where the last segment ended
516:                int lastSegEnd = 0;
517:
518:                do {
519:                    byteIdx += 4;
520:                    while (byteIdx < unparsed.length) {
521:                        if ((ch = unparsed[byteIdx]) == (byte) '#')
522:                            if (byteArrayNEquals(unparsed, byteIdx - 4,
523:                                    startPat, 0, 4)) {
524:                                break;
525:                            }
526:
527:                        // This is an ugly work-around to the
528:                        // absence of unsigned bytes in Java.
529:                        byteIdx += startIncrements[ch >= 0 ? ch : 0];
530:                    }
531:
532:                    if (++byteIdx >= unparsed.length)
533:                        break; // Nothing found
534:
535:                    // Record the start of the command name and parameter list
536:                    startInc = (startParam = paramIdx = byteIdx) - 5;
537:
538:                    // Add the previous segment of unparsed text
539:                    // (Unless empty)
540:                    if (startInc > lastSegEnd) {
541:                        buildSegments.addElement(new Segment(lastSegEnd,
542:                                startInc));
543:                        unparsedSize += startInc - lastSegEnd;
544:                        lastSegEnd = startInc;
545:                    }
546:
547:                    // Now find the end of the comment
548:                    byteIdx += 2;
549:                    while (byteIdx < unparsed.length) {
550:                        if ((ch = unparsed[byteIdx]) == (byte) '>')
551:                            if (unparsed[byteIdx - 2] == (byte) '-'
552:                                    && unparsed[byteIdx - 1] == (byte) '-')
553:                                break;
554:
555:                        // This is an ugly work-around to the absence of
556:                        // unsigned bytes in Java:
557:                        byteIdx += endIncrements[ch >= 0 ? ch : 0];
558:                    }
559:                    if (++byteIdx >= unparsed.length)
560:                        break; // No end found
561:
562:                    // The end of the parameter list is 3 bytes earlier
563:                    endParam = byteIdx - 3;
564:
565:                    // Record the nominal end of the command segment
566:                    endInc = byteIdx;
567:
568:                    // Skip white space before command 
569:                    while (paramIdx < endParam && isSpace(unparsed[paramIdx]))
570:                        paramIdx++;
571:                    if (paramIdx >= endParam)
572:                        continue; // No command name
573:
574:                    max = endParam - paramIdx;
575:
576:                    cmdName = parseCmdName(unparsed, paramIdx, max);
577:
578:                    // If not found, take this one as unparsed and
579:                    // search for the next include.
580:                    if (cmdName == null) {
581:                        buildSegments.addElement(new Segment(startInc, endInc));
582:                        unparsedSize += endInc - startInc;
583:                        lastSegEnd = endInc;
584:                        continue;
585:                    }
586:
587:                    parNames = new Vector(5);
588:                    parValues = new Vector(5);
589:
590:                    parseCmdParams(unparsed, paramIdx + cmdName.length(),
591:                            endParam, parNames, parValues);
592:
593:                    buildSegments.addElement(new Segment(this , cmdName,
594:                            new ArrayDictionary(parNames, parValues),
595:                            lastSegEnd, endInc));
596:                    lastSegEnd = endInc;
597:
598:                } while (byteIdx < unparsed.length);
599:
600:                // Add the last chunk of unparsed text as a segment
601:                buildSegments.addElement(new Segment(lastSegEnd,
602:                        unparsed.length));
603:                unparsedSize += unparsed.length - lastSegEnd;
604:
605:                setUnparsedSize(unparsedSize);
606:
607:                Segment[] segs = new Segment[buildSegments.size()];
608:                buildSegments.copyInto(segs);
609:                setValue(ATTR_SEGMENTS, segs);
610:            }
611:
612:            private final String parseCmdName(byte[] unparsed, int start,
613:                    int max) {
614:                StringBuffer cmdBuf = new StringBuffer(80);
615:                char ch;
616:                for (int i = 0; i < max; i++) {
617:                    ch = (char) unparsed[start + i];
618:                    if (Character.isWhitespace(ch))
619:                        break;
620:                    cmdBuf.append(ch);
621:                }
622:                return cmdBuf.length() == 0 ? null : cmdBuf.toString();
623:            }
624:
625:            private final void parseCmdParams(byte[] unparsed, int start,
626:                    int end, Vector names, Vector values) {
627:                String name = null;
628:                String value = null;
629:                int startParam = -1;
630:
631:                int paramIdx = start;
632:                while (paramIdx < end) {
633:                    while (isSpace(unparsed[paramIdx++]))
634:                        ;
635:                    if (paramIdx >= end)
636:                        break;
637:
638:                    byte ch = unparsed[--paramIdx];
639:                    startParam = paramIdx;
640:                    while (paramIdx < end && !isSpace(ch) && ch != (byte) '=')
641:                        ch = unparsed[++paramIdx];
642:
643:                    int length = paramIdx - startParam;
644:                    if (length <= 0)
645:                        break;
646:
647:                    name = new String(unparsed, 0, startParam, length);
648:                    value = emptyString;
649:
650:                    boolean valueFound = false;
651:                    while (isSpace(ch) || ch == (byte) '=') {
652:                        if (ch == (byte) '=')
653:                            valueFound = true;
654:                        ch = unparsed[++paramIdx];
655:                    }
656:
657:                    if (paramIdx >= end)
658:                        valueFound = false;
659:
660:                    byte quote;
661:                    if (valueFound)
662:                        if (ch == '"' || ch == '\'') {
663:                            quote = ch;
664:                            ch = unparsed[++paramIdx];
665:
666:                            startParam = paramIdx;
667:                            while (paramIdx < end && ch != quote)
668:                                ch = unparsed[++paramIdx];
669:                            length = paramIdx - startParam;
670:                            value = new String(unparsed, 0, startParam, length);
671:                            paramIdx++;
672:                        } else {
673:                            startParam = paramIdx;
674:                            while (paramIdx < end && !isSpace(ch))
675:                                ch = unparsed[++paramIdx];
676:                            length = paramIdx - startParam;
677:                            value = new String(unparsed, 0, startParam, length);
678:                        }
679:                    names.addElement(name);
680:                    values.addElement(value);
681:                }
682:
683:            }
684:
685:            /**
686:             * Analogous to standard C's <code>strncmp</code>, for byte arrays.
687:             * (Should be in some utility package, I'll put it here for now)
688:             * @param ba1 the first byte array
689:             * @param off1 where to start in the first array
690:             * @param ba2 the second byte array
691:             * @param off2 where to start in the second array
692:             * @param n the length to compare up to
693:             * @return <strong>true</strong> if both specified parts of the arrays are
694:             *           equal, <strong>false</strong> if they aren't .
695:             */
696:            public static final boolean byteArrayNEquals(byte[] ba1, int off1,
697:                    byte[] ba2, int off2, int n) {
698:                // So that only one addition is needed inside loop
699:                int corr = off2 - off1;
700:                int max = n + off1;
701:                for (int i = off1; i < max; i++)
702:                    if (ba1[i] != ba2[i + corr])
703:                        return false;
704:                return true;
705:            }
706:
707:            /**
708:             * Does the same as Character.isSpace, without need to cast the
709:             * byte into a char.
710:             * @param ch the character
711:             * @return whether or not ch is ASCII white space
712:             * @see java.lang.Character#isSpace
713:             */
714:            private final boolean isSpace(byte ch) {
715:                return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
716:            }
717:
718:            public long getLastModified()
719:            //FIXME
720:            {
721:                long a = super .getLastModified();
722:                return a - a % 1000;
723:            }
724:
725:            public final Reply createDefaultReply(Request request, int status) {
726:                Reply reply = super .createDefaultReply(request, status);
727:                reply.setHeaderValue(Reply.H_LAST_MODIFIED, null);
728:                reply.setKeepConnection(false);
729:                return reply;
730:            }
731:
732:            public final Reply createCommandReply(Request request, int status) {
733:                return createDefaultReply(request, status);
734:            }
735:
736:            static {
737:                // Initialize search increments first
738:                for (int i = 0; i < 128; i++) {
739:                    startIncrements[i] = 5;
740:                    endIncrements[i] = 3;
741:                }
742:                startIncrements[(int) ('<')] = 4;
743:                startIncrements[(int) ('!')] = 3;
744:                startIncrements[(int) ('-')] = 1;
745:                endIncrements[(int) ('-')] = 1;
746:
747:                // Initialize attributes
748:                Attribute a = null;
749:                Class cls = null;
750:                Class regClass = null;
751:
752:                try {
753:                    cls = Class.forName("org.w3c.jigsaw.ssi.SSIFrame");
754:                    regClass = Class
755:                            .forName("org.w3c.jigsaw.ssi.commands.DefaultCommandRegistry");
756:                } catch (Exception ex) {
757:                    ex.printStackTrace();
758:                    System.exit(0);
759:                }
760:
761:                // The maxDepth attribute
762:                a = new IntegerAttribute("maxDepth", new Integer(10),
763:                        Attribute.EDITABLE);
764:                ATTR_MAX_DEPTH = AttributeRegistry.registerAttribute(cls, a);
765:
766:                // The secure attribute
767:                a = new BooleanAttribute("secure", Boolean.TRUE,
768:                        Attribute.EDITABLE);
769:                ATTR_SECURE = AttributeRegistry.registerAttribute(cls, a);
770:
771:                // The segments attribute
772:                a = new SegmentArrayAttribute("segments", null,
773:                        Attribute.COMPUTED);
774:                ATTR_SEGMENTS = AttributeRegistry.registerAttribute(cls, a);
775:
776:                // The unparsedSize attribute
777:                a = new IntegerAttribute("unparsedSize", null,
778:                        Attribute.COMPUTED);
779:                ATTR_UNPARSED_SIZE = AttributeRegistry
780:                        .registerAttribute(cls, a);
781:
782:                // The registryClass attribute
783:                a = new ClassAttribute("registryClass", regClass,
784:                        Attribute.EDITABLE);
785:                ATTR_REGISTRY_CLASS = AttributeRegistry.registerAttribute(cls,
786:                        a);
787:
788:            }
789:
790:        }
791:
792:        /**
793:         * Merger classes are used to provide callbacks and make
794:         * header merging more uniform. (Though it may be overkill...)
795:         */
796:        abstract class Merger {
797:            abstract HeaderValue merge(HeaderValue g, HeaderValue p);
798:        }
799:
800:        class IntMaximizer extends Merger {
801:            HeaderValue merge(HeaderValue g, HeaderValue p) {
802:                if (p != null) {
803:                    if (g != null) {
804:                        ((HttpInteger) g).setValue(Math.max(((Integer) g
805:                                .getValue()).intValue(), ((Integer) p
806:                                .getValue()).intValue()));
807:                    } else
808:                        return p;
809:                }
810:                return g;
811:            }
812:        }
813:
814:        class IntMinimizer extends Merger {
815:            HeaderValue merge(HeaderValue g, HeaderValue p) {
816:                if (p != null) {
817:                    if (g != null) {
818:                        ((HttpInteger) g).setValue(Math.min(((Integer) g
819:                                .getValue()).intValue(), ((Integer) p
820:                                .getValue()).intValue()));
821:                    } else
822:                        return p;
823:                }
824:                return g;
825:            }
826:        }
827:
828:        class IntAdder extends Merger {
829:            HeaderValue merge(HeaderValue g, HeaderValue p) {
830:                if (SSIFrame.debug)
831:                    System.out.println("&&&& Adder: g=" + g + ", p=" + p);
832:                if (g != null) {
833:                    if (p != null) {
834:                        int b = ((Integer) g.getValue()).intValue()
835:                                + ((Integer) p.getValue()).intValue();
836:
837:                        ((HttpInteger) g).setValue(b);
838:                    } else
839:                        return null;
840:                }
841:                return g;
842:            }
843:        }
844:
845:        class DateMinimizer extends Merger {
846:            HeaderValue merge(HeaderValue g, HeaderValue p) {
847:                if (p != null) {
848:                    if (g != null) {
849:                        ((HttpDate) g).setValue(Math
850:                                .min(((Long) g.getValue()).longValue(),
851:                                        ((Long) p.getValue()).longValue()));
852:                    } else
853:                        return p;
854:                }
855:                return g;
856:            }
857:        }
858:
859:        class DateMaximizer extends Merger {
860:            HeaderValue merge(HeaderValue g, HeaderValue p) {
861:                if (p != null) {
862:                    if (g != null) {
863:                        ((HttpDate) g).setValue(Math
864:                                .max(((Long) g.getValue()).longValue(),
865:                                        ((Long) p.getValue()).longValue()));
866:                    } else
867:                        return p;
868:                }
869:                return g;
870:            }
871:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.