KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tomcat > util > http > mapper > Mapper


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.tomcat.util.http.mapper;
19
20 import javax.naming.NamingException JavaDoc;
21 import javax.naming.directory.DirContext JavaDoc;
22
23 import org.apache.tomcat.util.buf.CharChunk;
24 import org.apache.tomcat.util.buf.MessageBytes;
25 import org.apache.tomcat.util.buf.Ascii;
26 import java.util.List JavaDoc;
27 import java.util.ArrayList JavaDoc;
28
29 /**
30  * Mapper, which implements the servlet API mapping rules (which are derived
31  * from the HTTP rules).
32  *
33  * @author Remy Maucherat
34  */

35 public final class Mapper {
36
37
38     private static org.apache.commons.logging.Log logger =
39         org.apache.commons.logging.LogFactory.getLog(Mapper.class);
40     // ----------------------------------------------------- Instance Variables
41

42
43     /**
44      * Array containing the virtual hosts definitions.
45      */

46     protected Host[] hosts = new Host[0];
47
48
49     /**
50      * Default host name.
51      */

52     protected String JavaDoc defaultHostName = null;
53
54     /**
55      * Context associated with this wrapper, used for wrapper mapping.
56      */

57     protected Context JavaDoc context = new Context JavaDoc();
58
59
60     // --------------------------------------------------------- Public Methods
61

62
63     /**
64      * Get default host.
65      *
66      * @return Default host name
67      */

68     public String JavaDoc getDefaultHostName() {
69         return defaultHostName;
70     }
71
72
73     /**
74      * Set default host.
75      *
76      * @param defaultHostName Default host name
77      */

78     public void setDefaultHostName(String JavaDoc defaultHostName) {
79         this.defaultHostName = defaultHostName;
80     }
81
82     /**
83      * Add a new host to the mapper.
84      *
85      * @param name Virtual host name
86      * @param host Host object
87      */

88     public synchronized void addHost(String JavaDoc name, String JavaDoc[] aliases,
89                                      Object JavaDoc host) {
90         Host[] newHosts = new Host[hosts.length + 1];
91         Host newHost = new Host();
92         ContextList contextList = new ContextList();
93         newHost.name = name;
94         newHost.contextList = contextList;
95         newHost.object = host;
96         if (insertMap(hosts, newHosts, newHost)) {
97             hosts = newHosts;
98         }
99         for (int i = 0; i < aliases.length; i++) {
100             newHosts = new Host[hosts.length + 1];
101             newHost = new Host();
102             newHost.name = aliases[i];
103             newHost.contextList = contextList;
104             newHost.object = host;
105             if (insertMap(hosts, newHosts, newHost)) {
106                 hosts = newHosts;
107             }
108         }
109     }
110
111
112     /**
113      * Remove a host from the mapper.
114      *
115      * @param name Virtual host name
116      */

117     public synchronized void removeHost(String JavaDoc name) {
118         // Find and remove the old host
119
int pos = find(hosts, name);
120         if (pos < 0) {
121             return;
122         }
123         Object JavaDoc host = hosts[pos].object;
124         Host[] newHosts = new Host[hosts.length - 1];
125         if (removeMap(hosts, newHosts, name)) {
126             hosts = newHosts;
127         }
128         // Remove all aliases (they will map to the same host object)
129
for (int i = 0; i < newHosts.length; i++) {
130             if (newHosts[i].object == host) {
131                 Host[] newHosts2 = new Host[hosts.length - 1];
132                 if (removeMap(hosts, newHosts2, newHosts[i].name)) {
133                     hosts = newHosts2;
134                 }
135             }
136         }
137     }
138
139     public String JavaDoc[] getHosts() {
140         String JavaDoc hostN[] = new String JavaDoc[hosts.length];
141         for( int i = 0; i < hosts.length; i++ ) {
142             hostN[i] = hosts[i].name;
143         }
144         return hostN;
145     }
146
147
148     /**
149      * Set context, used for wrapper mapping (request dispatcher).
150      *
151      * @param welcomeResources Welcome files defined for this context
152      * @param resources Static resources of the context
153      */

154     public void setContext(String JavaDoc path, String JavaDoc[] welcomeResources,
155                            javax.naming.Context JavaDoc resources) {
156         context.name = path;
157         context.welcomeResources = welcomeResources;
158         context.resources = resources;
159     }
160
161
162     /**
163      * Add a new Context to an existing Host.
164      *
165      * @param hostName Virtual host name this context belongs to
166      * @param path Context path
167      * @param context Context object
168      * @param welcomeResources Welcome files defined for this context
169      * @param resources Static resources of the context
170      */

171     public void addContext
172         (String JavaDoc hostName, String JavaDoc path, Object JavaDoc context,
173          String JavaDoc[] welcomeResources, javax.naming.Context JavaDoc resources) {
174
175         Host[] hosts = this.hosts;
176         int pos = find(hosts, hostName);
177         if( pos <0 ) {
178             addHost(hostName, new String JavaDoc[0], "");
179             hosts = this.hosts;
180             pos = find(hosts, hostName);
181         }
182         if (pos < 0) {
183             logger.error("No host found: " + hostName);
184         }
185         Host host = hosts[pos];
186         if (host.name.equals(hostName)) {
187             int slashCount = slashCount(path);
188             synchronized (host) {
189                 Context JavaDoc[] contexts = host.contextList.contexts;
190                 // Update nesting
191
if (slashCount > host.contextList.nesting) {
192                     host.contextList.nesting = slashCount;
193                 }
194                 Context JavaDoc[] newContexts = new Context JavaDoc[contexts.length + 1];
195                 Context JavaDoc newContext = new Context JavaDoc();
196                 newContext.name = path;
197                 newContext.object = context;
198                 newContext.welcomeResources = welcomeResources;
199                 newContext.resources = resources;
200                 if (insertMap(contexts, newContexts, newContext)) {
201                     host.contextList.contexts = newContexts;
202                 }
203             }
204         }
205
206     }
207
208
209     /**
210      * Remove a context from an existing host.
211      *
212      * @param hostName Virtual host name this context belongs to
213      * @param path Context path
214      */

215     public void removeContext(String JavaDoc hostName, String JavaDoc path) {
216         Host[] hosts = this.hosts;
217         int pos = find(hosts, hostName);
218         if (pos < 0) {
219             return;
220         }
221         Host host = hosts[pos];
222         if (host.name.equals(hostName)) {
223             synchronized (host) {
224                 Context JavaDoc[] contexts = host.contextList.contexts;
225                 if( contexts.length == 0 ){
226                     return;
227                 }
228                 Context JavaDoc[] newContexts = new Context JavaDoc[contexts.length - 1];
229                 if (removeMap(contexts, newContexts, path)) {
230                     host.contextList.contexts = newContexts;
231                     // Recalculate nesting
232
host.contextList.nesting = 0;
233                     for (int i = 0; i < newContexts.length; i++) {
234                         int slashCount = slashCount(newContexts[i].name);
235                         if (slashCount > host.contextList.nesting) {
236                             host.contextList.nesting = slashCount;
237                         }
238                     }
239                 }
240             }
241         }
242     }
243
244
245     /**
246      * Return all contexts, in //HOST/PATH form
247      *
248      * @return The context names
249      */

250     public String JavaDoc[] getContextNames() {
251         List JavaDoc list=new ArrayList JavaDoc();
252         for( int i=0; i<hosts.length; i++ ) {
253             for( int j=0; j<hosts[i].contextList.contexts.length; j++ ) {
254                 String JavaDoc cname=hosts[i].contextList.contexts[j].name;
255                 list.add("//" + hosts[i].name +
256                         (cname.startsWith("/") ? cname : "/"));
257             }
258         }
259         String JavaDoc res[] = new String JavaDoc[list.size()];
260         return (String JavaDoc[])list.toArray(res);
261     }
262
263
264     /**
265      * Add a new Wrapper to an existing Context.
266      *
267      * @param hostName Virtual host name this wrapper belongs to
268      * @param contextPath Context path this wrapper belongs to
269      * @param path Wrapper mapping
270      * @param wrapper Wrapper object
271      */

272     public void addWrapper(String JavaDoc hostName, String JavaDoc contextPath, String JavaDoc path,
273                            Object JavaDoc wrapper) {
274         addWrapper(hostName, contextPath, path, wrapper, false);
275     }
276
277
278     public void addWrapper(String JavaDoc hostName, String JavaDoc contextPath, String JavaDoc path,
279                            Object JavaDoc wrapper, boolean jspWildCard) {
280         Host[] hosts = this.hosts;
281         int pos = find(hosts, hostName);
282         if (pos < 0) {
283             return;
284         }
285         Host host = hosts[pos];
286         if (host.name.equals(hostName)) {
287             Context JavaDoc[] contexts = host.contextList.contexts;
288             int pos2 = find(contexts, contextPath);
289             if( pos2<0 ) {
290                 logger.error("No context found: " + contextPath );
291                 return;
292             }
293             Context JavaDoc context = contexts[pos2];
294             if (context.name.equals(contextPath)) {
295                 addWrapper(context, path, wrapper, jspWildCard);
296             }
297         }
298     }
299
300
301     /**
302      * Add a wrapper to the context associated with this wrapper.
303      *
304      * @param path Wrapper mapping
305      * @param wrapper The Wrapper object
306      */

307     public void addWrapper(String JavaDoc path, Object JavaDoc wrapper) {
308         addWrapper(context, path, wrapper);
309     }
310
311
312     public void addWrapper(String JavaDoc path, Object JavaDoc wrapper, boolean jspWildCard) {
313         addWrapper(context, path, wrapper, jspWildCard);
314     }
315
316
317     protected void addWrapper(Context JavaDoc context, String JavaDoc path, Object JavaDoc wrapper) {
318         addWrapper(context, path, wrapper, false);
319     }
320
321
322     /**
323      * Adds a wrapper to the given context.
324      *
325      * @param context The context to which to add the wrapper
326      * @param path Wrapper mapping
327      * @param wrapper The Wrapper object
328      * @param jspWildCard true if the wrapper corresponds to the JspServlet
329      * and the mapping path contains a wildcard; false otherwise
330      */

331     protected void addWrapper(Context JavaDoc context, String JavaDoc path, Object JavaDoc wrapper,
332                               boolean jspWildCard) {
333
334         synchronized (context) {
335             Wrapper newWrapper = new Wrapper();
336             newWrapper.object = wrapper;
337             newWrapper.jspWildCard = jspWildCard;
338             if (path.endsWith("/*")) {
339                 // Wildcard wrapper
340
newWrapper.name = path.substring(0, path.length() - 2);
341                 Wrapper[] oldWrappers = context.wildcardWrappers;
342                 Wrapper[] newWrappers =
343                     new Wrapper[oldWrappers.length + 1];
344                 if (insertMap(oldWrappers, newWrappers, newWrapper)) {
345                     context.wildcardWrappers = newWrappers;
346                     int slashCount = slashCount(newWrapper.name);
347                     if (slashCount > context.nesting) {
348                         context.nesting = slashCount;
349                     }
350                 }
351             } else if (path.startsWith("*.")) {
352                 // Extension wrapper
353
newWrapper.name = path.substring(2);
354                 Wrapper[] oldWrappers = context.extensionWrappers;
355                 Wrapper[] newWrappers =
356                     new Wrapper[oldWrappers.length + 1];
357                 if (insertMap(oldWrappers, newWrappers, newWrapper)) {
358                     context.extensionWrappers = newWrappers;
359                 }
360             } else if (path.equals("/")) {
361                 // Default wrapper
362
newWrapper.name = "";
363                 context.defaultWrapper = newWrapper;
364             } else {
365                 // Exact wrapper
366
newWrapper.name = path;
367                 Wrapper[] oldWrappers = context.exactWrappers;
368                 Wrapper[] newWrappers =
369                     new Wrapper[oldWrappers.length + 1];
370                 if (insertMap(oldWrappers, newWrappers, newWrapper)) {
371                     context.exactWrappers = newWrappers;
372                 }
373             }
374         }
375     }
376
377
378     /**
379      * Remove a wrapper from the context associated with this wrapper.
380      *
381      * @param path Wrapper mapping
382      */

383     public void removeWrapper(String JavaDoc path) {
384         removeWrapper(context, path);
385     }
386
387
388     /**
389      * Remove a wrapper from an existing context.
390      *
391      * @param hostName Virtual host name this wrapper belongs to
392      * @param contextPath Context path this wrapper belongs to
393      * @param path Wrapper mapping
394      */

395     public void removeWrapper
396         (String JavaDoc hostName, String JavaDoc contextPath, String JavaDoc path) {
397         Host[] hosts = this.hosts;
398         int pos = find(hosts, hostName);
399         if (pos < 0) {
400             return;
401         }
402         Host host = hosts[pos];
403         if (host.name.equals(hostName)) {
404             Context JavaDoc[] contexts = host.contextList.contexts;
405             int pos2 = find(contexts, contextPath);
406             if (pos2 < 0) {
407                 return;
408             }
409             Context JavaDoc context = contexts[pos2];
410             if (context.name.equals(contextPath)) {
411                 removeWrapper(context, path);
412             }
413         }
414     }
415
416     protected void removeWrapper(Context JavaDoc context, String JavaDoc path) {
417         synchronized (context) {
418             if (path.endsWith("/*")) {
419                 // Wildcard wrapper
420
String JavaDoc name = path.substring(0, path.length() - 2);
421                 Wrapper[] oldWrappers = context.wildcardWrappers;
422                 Wrapper[] newWrappers =
423                     new Wrapper[oldWrappers.length - 1];
424                 if (removeMap(oldWrappers, newWrappers, name)) {
425                     // Recalculate nesting
426
context.nesting = 0;
427                     for (int i = 0; i < newWrappers.length; i++) {
428                         int slashCount = slashCount(newWrappers[i].name);
429                         if (slashCount > context.nesting) {
430                             context.nesting = slashCount;
431                         }
432                     }
433                     context.wildcardWrappers = newWrappers;
434                 }
435             } else if (path.startsWith("*.")) {
436                 // Extension wrapper
437
String JavaDoc name = path.substring(2);
438                 Wrapper[] oldWrappers = context.extensionWrappers;
439                 Wrapper[] newWrappers =
440                     new Wrapper[oldWrappers.length - 1];
441                 if (removeMap(oldWrappers, newWrappers, name)) {
442                     context.extensionWrappers = newWrappers;
443                 }
444             } else if (path.equals("/")) {
445                 // Default wrapper
446
context.defaultWrapper = null;
447             } else {
448                 // Exact wrapper
449
String JavaDoc name = path;
450                 Wrapper[] oldWrappers = context.exactWrappers;
451                 Wrapper[] newWrappers =
452                     new Wrapper[oldWrappers.length - 1];
453                 if (removeMap(oldWrappers, newWrappers, name)) {
454                     context.exactWrappers = newWrappers;
455                 }
456             }
457         }
458     }
459
460     public String JavaDoc getWrappersString( String JavaDoc host, String JavaDoc context ) {
461         String JavaDoc names[]=getWrapperNames(host, context);
462         StringBuffer JavaDoc sb=new StringBuffer JavaDoc();
463         for( int i=0; i<names.length; i++ ) {
464             sb.append(names[i]).append(":");
465         }
466         return sb.toString();
467     }
468
469     public String JavaDoc[] getWrapperNames( String JavaDoc host, String JavaDoc context ) {
470         List JavaDoc list=new ArrayList JavaDoc();
471         if( host==null ) host="";
472         if( context==null ) context="";
473         for( int i=0; i<hosts.length; i++ ) {
474             if( ! host.equals( hosts[i].name ))
475                 continue;
476             for( int j=0; j<hosts[i].contextList.contexts.length; j++ ) {
477                 if( ! context.equals( hosts[i].contextList.contexts[j].name))
478                     continue;
479                 // found the context
480
Context JavaDoc ctx=hosts[i].contextList.contexts[j];
481                 list.add( ctx.defaultWrapper.path);
482                 for( int k=0; k<ctx.exactWrappers.length; k++ ) {
483                     list.add( ctx.exactWrappers[k].path);
484                 }
485                 for( int k=0; k<ctx.wildcardWrappers.length; k++ ) {
486                     list.add( ctx.wildcardWrappers[k].path + "*");
487                 }
488                 for( int k=0; k<ctx.extensionWrappers.length; k++ ) {
489                     list.add( "*." + ctx.extensionWrappers[k].path);
490                 }
491             }
492         }
493         String JavaDoc res[]=new String JavaDoc[list.size()];
494         return (String JavaDoc[])list.toArray(res);
495     }
496
497
498
499     /**
500      * Map the specified host name and URI, mutating the given mapping data.
501      *
502      * @param host Virtual host name
503      * @param uri URI
504      * @param mappingData This structure will contain the result of the mapping
505      * operation
506      */

507     public void map(MessageBytes host, MessageBytes uri,
508                     MappingData mappingData)
509         throws Exception JavaDoc {
510
511         if (host.isNull()) {
512             host.getCharChunk().append(defaultHostName);
513         }
514         host.toChars();
515         uri.toChars();
516         internalMap(host.getCharChunk(), uri.getCharChunk(), mappingData);
517
518     }
519
520
521     /**
522      * Map the specified URI relative to the context,
523      * mutating the given mapping data.
524      *
525      * @param uri URI
526      * @param mappingData This structure will contain the result of the mapping
527      * operation
528      */

529     public void map(MessageBytes uri, MappingData mappingData)
530         throws Exception JavaDoc {
531
532         uri.toChars();
533         CharChunk uricc = uri.getCharChunk();
534         uricc.setLimit(-1);
535         internalMapWrapper(context, uricc, mappingData);
536
537     }
538
539
540     // -------------------------------------------------------- Private Methods
541

542
543     /**
544      * Map the specified URI.
545      */

546     private final void internalMap(CharChunk host, CharChunk uri,
547                                    MappingData mappingData)
548         throws Exception JavaDoc {
549
550         uri.setLimit(-1);
551
552         Context JavaDoc[] contexts = null;
553         Context JavaDoc context = null;
554         int nesting = 0;
555
556         // Virtual host mapping
557
if (mappingData.host == null) {
558             Host[] hosts = this.hosts;
559             int pos = findIgnoreCase(hosts, host);
560             if ((pos != -1) && (host.equalsIgnoreCase(hosts[pos].name))) {
561                 mappingData.host = hosts[pos].object;
562                 contexts = hosts[pos].contextList.contexts;
563                 nesting = hosts[pos].contextList.nesting;
564             } else {
565                 if (defaultHostName == null) {
566                     return;
567                 }
568                 pos = find(hosts, defaultHostName);
569                 if ((pos != -1) && (defaultHostName.equals(hosts[pos].name))) {
570                     mappingData.host = hosts[pos].object;
571                     contexts = hosts[pos].contextList.contexts;
572                     nesting = hosts[pos].contextList.nesting;
573                 } else {
574                     return;
575                 }
576             }
577         }
578
579         // Context mapping
580
if (mappingData.context == null) {
581             int pos = find(contexts, uri);
582             if (pos == -1) {
583                 return;
584             }
585
586             int lastSlash = -1;
587             int uriEnd = uri.getEnd();
588             int length = -1;
589             boolean found = false;
590             while (pos >= 0) {
591                 if (uri.startsWith(contexts[pos].name)) {
592                     length = contexts[pos].name.length();
593                     if (uri.getLength() == length) {
594                         found = true;
595                         break;
596                     } else if (uri.startsWithIgnoreCase("/", length)) {
597                         found = true;
598                         break;
599                     }
600                 }
601                 if (lastSlash == -1) {
602                     lastSlash = nthSlash(uri, nesting + 1);
603                 } else {
604                     lastSlash = lastSlash(uri);
605                 }
606                 uri.setEnd(lastSlash);
607                 pos = find(contexts, uri);
608             }
609             uri.setEnd(uriEnd);
610
611             if (!found) {
612                 if (contexts[0].name.equals("")) {
613                     context = contexts[0];
614                 }
615             } else {
616                 context = contexts[pos];
617             }
618             if (context != null) {
619                 mappingData.context = context.object;
620                 mappingData.contextPath.setString(context.name);
621             }
622         }
623
624         // Wrapper mapping
625
if ((context != null) && (mappingData.wrapper == null)) {
626             internalMapWrapper(context, uri, mappingData);
627         }
628
629     }
630
631
632     /**
633      * Wrapper mapping.
634      */

635     private final void internalMapWrapper(Context JavaDoc context, CharChunk path,
636                                           MappingData mappingData)
637         throws Exception JavaDoc {
638
639         int pathOffset = path.getOffset();
640         int pathEnd = path.getEnd();
641         int servletPath = pathOffset;
642         boolean noServletPath = false;
643
644         int length = context.name.length();
645         if (length != (pathEnd - pathOffset)) {
646             servletPath = pathOffset + length;
647         } else {
648             noServletPath = true;
649             path.append('/');
650             pathOffset = path.getOffset();
651             pathEnd = path.getEnd();
652             servletPath = pathOffset+length;
653         }
654
655         path.setOffset(servletPath);
656
657         // Rule 1 -- Exact Match
658
Wrapper[] exactWrappers = context.exactWrappers;
659         internalMapExactWrapper(exactWrappers, path, mappingData);
660
661         // Rule 2 -- Prefix Match
662
boolean checkJspWelcomeFiles = false;
663         Wrapper[] wildcardWrappers = context.wildcardWrappers;
664         if (mappingData.wrapper == null) {
665             internalMapWildcardWrapper(wildcardWrappers, context.nesting,
666                                        path, mappingData);
667             if (mappingData.wrapper != null && mappingData.jspWildCard) {
668                 char[] buf = path.getBuffer();
669                 if (buf[pathEnd - 1] == '/') {
670                     /*
671                      * Path ending in '/' was mapped to JSP servlet based on
672                      * wildcard match (e.g., as specified in url-pattern of a
673                      * jsp-property-group.
674                      * Force the context's welcome files, which are interpreted
675                      * as JSP files (since they match the url-pattern), to be
676                      * considered. See Bugzilla 27664.
677                      */

678                     mappingData.wrapper = null;
679                     checkJspWelcomeFiles = true;
680                 } else {
681                     // See Bugzilla 27704
682
mappingData.wrapperPath.setChars(buf, path.getStart(),
683                                                      path.getLength());
684                     mappingData.pathInfo.recycle();
685                 }
686             }
687         }
688
689         if(mappingData.wrapper == null && noServletPath) {
690             // The path is empty, redirect to "/"
691
mappingData.redirectPath.setChars
692                 (path.getBuffer(), pathOffset, pathEnd);
693             path.setEnd(pathEnd - 1);
694             return;
695         }
696
697         // Rule 3 -- Extension Match
698
Wrapper[] extensionWrappers = context.extensionWrappers;
699         if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
700             internalMapExtensionWrapper(extensionWrappers, path, mappingData);
701         }
702
703         // Rule 4 -- Welcome resources processing for servlets
704
if (mappingData.wrapper == null) {
705             boolean checkWelcomeFiles = checkJspWelcomeFiles;
706             if (!checkWelcomeFiles) {
707                 char[] buf = path.getBuffer();
708                 checkWelcomeFiles = (buf[pathEnd - 1] == '/');
709             }
710             if (checkWelcomeFiles) {
711                 for (int i = 0; (i < context.welcomeResources.length)
712                          && (mappingData.wrapper == null); i++) {
713                     path.setOffset(pathOffset);
714                     path.setEnd(pathEnd);
715                     path.append(context.welcomeResources[i], 0,
716                                 context.welcomeResources[i].length());
717                     path.setOffset(servletPath);
718
719                     // Rule 4a -- Welcome resources processing for exact macth
720
internalMapExactWrapper(exactWrappers, path, mappingData);
721
722                     // Rule 4b -- Welcome resources processing for prefix match
723
if (mappingData.wrapper == null) {
724                         internalMapWildcardWrapper
725                             (wildcardWrappers, context.nesting,
726                              path, mappingData);
727                     }
728
729                     // Rule 4c -- Welcome resources processing
730
// for physical folder
731
if (mappingData.wrapper == null
732                         && context.resources != null) {
733                         Object JavaDoc file = null;
734                         String JavaDoc pathStr = path.toString();
735                         try {
736                             file = context.resources.lookup(pathStr);
737                         } catch(NamingException JavaDoc nex) {
738                             // Swallow not found, since this is normal
739
}
740                         if (file != null && !(file instanceof DirContext JavaDoc) ) {
741                             internalMapExtensionWrapper(extensionWrappers,
742                                                         path, mappingData);
743                             if (mappingData.wrapper == null
744                                 && context.defaultWrapper != null) {
745                                 mappingData.wrapper =
746                                     context.defaultWrapper.object;
747                                 mappingData.requestPath.setChars
748                                     (path.getBuffer(), path.getStart(),
749                                      path.getLength());
750                                 mappingData.wrapperPath.setChars
751                                     (path.getBuffer(), path.getStart(),
752                                      path.getLength());
753                                 mappingData.requestPath.setString(pathStr);
754                                 mappingData.wrapperPath.setString(pathStr);
755                             }
756                         }
757                     }
758                 }
759
760                 path.setOffset(servletPath);
761                 path.setEnd(pathEnd);
762             }
763                                         
764         }
765
766
767         // Rule 7 -- Default servlet
768
if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
769             if (context.defaultWrapper != null) {
770                 mappingData.wrapper = context.defaultWrapper.object;
771                 mappingData.requestPath.setChars
772                     (path.getBuffer(), path.getStart(), path.getLength());
773                 mappingData.wrapperPath.setChars
774                     (path.getBuffer(), path.getStart(), path.getLength());
775             }
776             // Redirection to a folder
777
char[] buf = path.getBuffer();
778             if (context.resources != null && buf[pathEnd -1 ] != '/') {
779                 Object JavaDoc file = null;
780                 String JavaDoc pathStr = path.toString();
781                 try {
782                     file = context.resources.lookup(pathStr);
783                 } catch(NamingException JavaDoc nex) {
784                     // Swallow, since someone else handles the 404
785
}
786                 if (file != null && file instanceof DirContext JavaDoc) {
787                     // Note: this mutates the path: do not do any processing
788
// after this (since we set the redirectPath, there
789
// shouldn't be any)
790
path.setOffset(pathOffset);
791                     path.append('/');
792                     mappingData.redirectPath.setChars
793                         (path.getBuffer(), path.getStart(), path.getLength());
794                 } else {
795                     mappingData.requestPath.setString(pathStr);
796                     mappingData.wrapperPath.setString(pathStr);
797                 }
798             }
799         }
800
801         path.setOffset(pathOffset);
802         path.setEnd(pathEnd);
803
804     }
805
806
807     /**
808      * Exact mapping.
809      */

810     private final void internalMapExactWrapper
811         (Wrapper[] wrappers, CharChunk path, MappingData mappingData) {
812         int pos = find(wrappers, path);
813         if ((pos != -1) && (path.equals(wrappers[pos].name))) {
814             mappingData.requestPath.setString(wrappers[pos].name);
815             mappingData.wrapperPath.setString(wrappers[pos].name);
816             mappingData.wrapper = wrappers[pos].object;
817         }
818     }
819
820
821     /**
822      * Wildcard mapping.
823      */

824     private final void internalMapWildcardWrapper
825         (Wrapper[] wrappers, int nesting, CharChunk path,
826          MappingData mappingData) {
827
828         int pathEnd = path.getEnd();
829         int pathOffset = path.getOffset();
830
831         int lastSlash = -1;
832         int length = -1;
833         int pos = find(wrappers, path);
834         if (pos != -1) {
835             boolean found = false;
836             while (pos >= 0) {
837                 if (path.startsWith(wrappers[pos].name)) {
838                     length = wrappers[pos].name.length();
839                     if (path.getLength() == length) {
840                         found = true;
841                         break;
842                     } else if (path.startsWithIgnoreCase("/", length)) {
843                         found = true;
844                         break;
845                     }
846                 }
847                 if (lastSlash == -1) {
848                     lastSlash = nthSlash(path, nesting + 1);
849                 } else {
850                     lastSlash = lastSlash(path);
851                 }
852                 path.setEnd(lastSlash);
853                 pos = find(wrappers, path);
854             }
855             path.setEnd(pathEnd);
856             if (found) {
857                 mappingData.wrapperPath.setString(wrappers[pos].name);
858                 if (path.getLength() > length) {
859                     mappingData.pathInfo.setChars
860                         (path.getBuffer(),
861                          path.getOffset() + length,
862                          path.getLength() - length);
863                 }
864                 mappingData.requestPath.setChars
865                     (path.getBuffer(), path.getOffset(), path.getLength());
866                 mappingData.wrapper = wrappers[pos].object;
867                 mappingData.jspWildCard = wrappers[pos].jspWildCard;
868             }
869         }
870     }
871
872
873     /**
874      * Extension mappings.
875      */

876     private final void internalMapExtensionWrapper
877         (Wrapper[] wrappers, CharChunk path, MappingData mappingData) {
878         char[] buf = path.getBuffer();
879         int pathEnd = path.getEnd();
880         int servletPath = path.getOffset();
881         int slash = -1;
882         for (int i = pathEnd - 1; i >= servletPath; i--) {
883             if (buf[i] == '/') {
884                 slash = i;
885                 break;
886             }
887         }
888         if (slash >= 0) {
889             int period = -1;
890             for (int i = pathEnd - 1; i > slash; i--) {
891                 if (buf[i] == '.') {
892                     period = i;
893                     break;
894                 }
895             }
896             if (period >= 0) {
897                 path.setOffset(period + 1);
898                 path.setEnd(pathEnd);
899                 int pos = find(wrappers, path);
900                 if ((pos != -1)
901                     && (path.equals(wrappers[pos].name))) {
902                     mappingData.wrapperPath.setChars
903                         (buf, servletPath, pathEnd - servletPath);
904                     mappingData.requestPath.setChars
905                         (buf, servletPath, pathEnd - servletPath);
906                     mappingData.wrapper = wrappers[pos].object;
907                 }
908                 path.setOffset(servletPath);
909                 path.setEnd(pathEnd);
910             }
911         }
912     }
913
914
915     /**
916      * Find a map elemnt given its name in a sorted array of map elements.
917      * This will return the index for the closest inferior or equal item in the
918      * given array.
919      */

920     private static final int find(MapElement[] map, CharChunk name) {
921         return find(map, name, name.getStart(), name.getEnd());
922     }
923
924
925     /**
926      * Find a map elemnt given its name in a sorted array of map elements.
927      * This will return the index for the closest inferior or equal item in the
928      * given array.
929      */

930     private static final int find(MapElement[] map, CharChunk name,
931                                   int start, int end) {
932
933         int a = 0;
934         int b = map.length - 1;
935
936         // Special cases: -1 and 0
937
if (b == -1) {
938             return -1;
939         }
940         
941         if (compare(name, start, end, map[0].name) < 0 ) {
942             return -1;
943         }
944         if (b == 0) {
945             return 0;
946         }
947
948         int i = 0;
949         while (true) {
950             i = (b + a) / 2;
951             int result = compare(name, start, end, map[i].name);
952             if (result == 1) {
953                 a = i;
954             } else if (result == 0) {
955                 return i;
956             } else {
957                 b = i;
958             }
959             if ((b - a) == 1) {
960                 int result2 = compare(name, start, end, map[b].name);
961                 if (result2 < 0) {
962                     return a;
963                 } else {
964                     return b;
965                 }
966             }
967         }
968
969     }
970
971     /**
972      * Find a map elemnt given its name in a sorted array of map elements.
973      * This will return the index for the closest inferior or equal item in the
974      * given array.
975      */

976     private static final int findIgnoreCase(MapElement[] map, CharChunk name) {
977         return findIgnoreCase(map, name, name.getStart(), name.getEnd());
978     }
979
980
981     /**
982      * Find a map elemnt given its name in a sorted array of map elements.
983      * This will return the index for the closest inferior or equal item in the
984      * given array.
985      */

986     private static final int findIgnoreCase(MapElement[] map, CharChunk name,
987                                   int start, int end) {
988
989         int a = 0;
990         int b = map.length - 1;
991
992         // Special cases: -1 and 0
993
if (b == -1) {
994             return -1;
995         }
996         if (compareIgnoreCase(name, start, end, map[0].name) < 0 ) {
997             return -1;
998         }
999         if (b == 0) {
1000            return 0;
1001        }
1002
1003        int i = 0;
1004        while (true) {
1005            i = (b + a) / 2;
1006            int result = compareIgnoreCase(name, start, end, map[i].name);
1007            if (result == 1) {
1008                a = i;
1009            } else if (result == 0) {
1010                return i;
1011            } else {
1012                b = i;
1013            }
1014            if ((b - a) == 1) {
1015                int result2 = compareIgnoreCase(name, start, end, map[b].name);
1016                if (result2 < 0) {
1017                    return a;
1018                } else {
1019                    return b;
1020                }
1021            }
1022        }
1023
1024    }
1025
1026
1027    /**
1028     * Find a map elemnt given its name in a sorted array of map elements.
1029     * This will return the index for the closest inferior or equal item in the
1030     * given array.
1031     */

1032    private static final int find(MapElement[] map, String JavaDoc name) {
1033
1034        int a = 0;
1035        int b = map.length - 1;
1036
1037        // Special cases: -1 and 0
1038
if (b == -1) {
1039            return -1;
1040        }
1041        
1042        if (name.compareTo(map[0].name) < 0) {
1043            return -1;
1044        }
1045        if (b == 0) {
1046            return 0;
1047        }
1048
1049        int i = 0;
1050        while (true) {
1051            i = (b + a) / 2;
1052            int result = name.compareTo(map[i].name);
1053            if (result > 0) {
1054                a = i;
1055            } else if (result == 0) {
1056                return i;
1057            } else {
1058                b = i;
1059            }
1060            if ((b - a) == 1) {
1061                int result2 = name.compareTo(map[b].name);
1062                if (result2 < 0) {
1063                    return a;
1064                } else {
1065                    return b;
1066                }
1067            }
1068        }
1069
1070    }
1071
1072
1073    /**
1074     * Compare given char chunk with String.
1075     * Return -1, 0 or +1 if inferior, equal, or superior to the String.
1076     */

1077    private static final int compare(CharChunk name, int start, int end,
1078                                     String JavaDoc compareTo) {
1079        int result = 0;
1080        char[] c = name.getBuffer();
1081        int len = compareTo.length();
1082        if ((end - start) < len) {
1083            len = end - start;
1084        }
1085        for (int i = 0; (i < len) && (result == 0); i++) {
1086            if (c[i + start] > compareTo.charAt(i)) {
1087                result = 1;
1088            } else if (c[i + start] < compareTo.charAt(i)) {
1089                result = -1;
1090            }
1091        }
1092        if (result == 0) {
1093            if (compareTo.length() > (end - start)) {
1094                result = -1;
1095            } else if (compareTo.length() < (end - start)) {
1096                result = 1;
1097            }
1098        }
1099        return result;
1100    }
1101
1102
1103    /**
1104     * Compare given char chunk with String ignoring case.
1105     * Return -1, 0 or +1 if inferior, equal, or superior to the String.
1106     */

1107    private static final int compareIgnoreCase(CharChunk name, int start, int end,
1108                                     String JavaDoc compareTo) {
1109        int result = 0;
1110        char[] c = name.getBuffer();
1111        int len = compareTo.length();
1112        if ((end - start) < len) {
1113            len = end - start;
1114        }
1115        for (int i = 0; (i < len) && (result == 0); i++) {
1116            if (Ascii.toLower(c[i + start]) > Ascii.toLower(compareTo.charAt(i))) {
1117                result = 1;
1118            } else if (Ascii.toLower(c[i + start]) < Ascii.toLower(compareTo.charAt(i))) {
1119                result = -1;
1120            }
1121        }
1122        if (result == 0) {
1123            if (compareTo.length() > (end - start)) {
1124                result = -1;
1125            } else if (compareTo.length() < (end - start)) {
1126                result = 1;
1127            }
1128        }
1129        return result;
1130    }
1131
1132
1133    /**
1134     * Find the position of the last slash in the given char chunk.
1135     */

1136    private static final int lastSlash(CharChunk name) {
1137
1138        char[] c = name.getBuffer();
1139        int end = name.getEnd();
1140        int start = name.getStart();
1141        int pos = end;
1142
1143        while (pos > start) {
1144            if (c[--pos] == '/') {
1145                break;
1146            }
1147        }
1148
1149        return (pos);
1150
1151    }
1152
1153
1154    /**
1155     * Find the position of the nth slash, in the given char chunk.
1156     */

1157    private static final int nthSlash(CharChunk name, int n) {
1158
1159        char[] c = name.getBuffer();
1160        int end = name.getEnd();
1161        int start = name.getStart();
1162        int pos = start;
1163        int count = 0;
1164
1165        while (pos < end) {
1166            if ((c[pos++] == '/') && ((++count) == n)) {
1167                pos--;
1168                break;
1169            }
1170        }
1171
1172        return (pos);
1173
1174    }
1175
1176
1177    /**
1178     * Return the slash count in a given string.
1179     */

1180    private static final int slashCount(String JavaDoc name) {
1181        int pos = -1;
1182        int count = 0;
1183        while ((pos = name.indexOf('/', pos + 1)) != -1) {
1184            count++;
1185        }
1186        return count;
1187    }
1188
1189
1190    /**
1191     * Insert into the right place in a sorted MapElement array, and prevent
1192     * duplicates.
1193     */

1194    private static final boolean insertMap
1195        (MapElement[] oldMap, MapElement[] newMap, MapElement newElement) {
1196        int pos = find(oldMap, newElement.name);
1197        if ((pos != -1) && (newElement.name.equals(oldMap[pos].name))) {
1198            return false;
1199        }
1200        System.arraycopy(oldMap, 0, newMap, 0, pos + 1);
1201        newMap[pos + 1] = newElement;
1202        System.arraycopy
1203            (oldMap, pos + 1, newMap, pos + 2, oldMap.length - pos - 1);
1204        return true;
1205    }
1206
1207
1208    /**
1209     * Insert into the right place in a sorted MapElement array.
1210     */

1211    private static final boolean removeMap
1212        (MapElement[] oldMap, MapElement[] newMap, String JavaDoc name) {
1213        int pos = find(oldMap, name);
1214        if ((pos != -1) && (name.equals(oldMap[pos].name))) {
1215            System.arraycopy(oldMap, 0, newMap, 0, pos);
1216            System.arraycopy(oldMap, pos + 1, newMap, pos,
1217                             oldMap.length - pos - 1);
1218            return true;
1219        }
1220        return false;
1221    }
1222
1223
1224    // ------------------------------------------------- MapElement Inner Class
1225

1226
1227    protected static abstract class MapElement {
1228
1229        public String JavaDoc name = null;
1230        public Object JavaDoc object = null;
1231
1232    }
1233
1234
1235    // ------------------------------------------------------- Host Inner Class
1236

1237
1238    protected static final class Host
1239        extends MapElement {
1240
1241        public ContextList contextList = null;
1242
1243    }
1244
1245
1246    // ------------------------------------------------ ContextList Inner Class
1247

1248
1249    protected static final class ContextList {
1250
1251        public Context JavaDoc[] contexts = new Context JavaDoc[0];
1252        public int nesting = 0;
1253
1254    }
1255
1256
1257    // ---------------------------------------------------- Context Inner Class
1258

1259
1260    protected static final class Context
1261        extends MapElement {
1262
1263        public String JavaDoc path = null;
1264        public String JavaDoc[] welcomeResources = new String JavaDoc[0];
1265        public javax.naming.Context JavaDoc resources = null;
1266        public Wrapper defaultWrapper = null;
1267        public Wrapper[] exactWrappers = new Wrapper[0];
1268        public Wrapper[] wildcardWrappers = new Wrapper[0];
1269        public Wrapper[] extensionWrappers = new Wrapper[0];
1270        public int nesting = 0;
1271
1272    }
1273
1274
1275    // ---------------------------------------------------- Wrapper Inner Class
1276

1277
1278    protected static class Wrapper
1279        extends MapElement {
1280
1281        public String JavaDoc path = null;
1282        public boolean jspWildCard = false;
1283    }
1284
1285
1286    // -------------------------------------------------------- Testing Methods
1287

1288    // FIXME: Externalize this
1289
/*
1290    public static void main(String args[]) {
1291
1292        try {
1293
1294        Mapper mapper = new Mapper();
1295        System.out.println("Start");
1296
1297        mapper.addHost("sjbjdvwsbvhrb", new String[0], "blah1");
1298        mapper.addHost("sjbjdvwsbvhr/", new String[0], "blah1");
1299        mapper.addHost("wekhfewuifweuibf", new String[0], "blah2");
1300        mapper.addHost("ylwrehirkuewh", new String[0], "blah3");
1301        mapper.addHost("iohgeoihro", new String[0], "blah4");
1302        mapper.addHost("fwehoihoihwfeo", new String[0], "blah5");
1303        mapper.addHost("owefojiwefoi", new String[0], "blah6");
1304        mapper.addHost("iowejoiejfoiew", new String[0], "blah7");
1305        mapper.addHost("iowejoiejfoiew", new String[0], "blah17");
1306        mapper.addHost("ohewoihfewoih", new String[0], "blah8");
1307        mapper.addHost("fewohfoweoih", new String[0], "blah9");
1308        mapper.addHost("ttthtiuhwoih", new String[0], "blah10");
1309        mapper.addHost("lkwefjwojweffewoih", new String[0], "blah11");
1310        mapper.addHost("zzzuyopjvewpovewjhfewoih", new String[0], "blah12");
1311        mapper.addHost("xxxxgqwiwoih", new String[0], "blah13");
1312        mapper.addHost("qwigqwiwoih", new String[0], "blah14");
1313
1314        System.out.println("Map:");
1315        for (int i = 0; i < mapper.hosts.length; i++) {
1316            System.out.println(mapper.hosts[i].name);
1317        }
1318
1319        mapper.setDefaultHostName("ylwrehirkuewh");
1320
1321        String[] welcomes = new String[2];
1322        welcomes[0] = "boo/baba";
1323        welcomes[1] = "bobou";
1324
1325        mapper.addContext("iowejoiejfoiew", "", "context0", new String[0], null);
1326        mapper.addContext("iowejoiejfoiew", "/foo", "context1", new String[0], null);
1327        mapper.addContext("iowejoiejfoiew", "/foo/bar", "context2", welcomes, null);
1328        mapper.addContext("iowejoiejfoiew", "/foo/bar/bla", "context3", new String[0], null);
1329
1330        mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/fo/*", "wrapper0");
1331        mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/", "wrapper1");
1332        mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blh", "wrapper2");
1333        mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "*.jsp", "wrapper3");
1334        mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blah/bou/*", "wrapper4");
1335        mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blah/bobou/*", "wrapper5");
1336        mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "*.htm", "wrapper6");
1337
1338        MappingData mappingData = new MappingData();
1339        MessageBytes host = MessageBytes.newInstance();
1340        host.setString("iowejoiejfoiew");
1341        MessageBytes uri = MessageBytes.newInstance();
1342        uri.setString("/foo/bar/blah/bobou/foo");
1343        uri.toChars();
1344        uri.getCharChunk().setLimit(-1);
1345
1346        mapper.map(host, uri, mappingData);
1347        System.out.println("MD Host:" + mappingData.host);
1348        System.out.println("MD Context:" + mappingData.context);
1349        System.out.println("MD Wrapper:" + mappingData.wrapper);
1350
1351        System.out.println("contextPath:" + mappingData.contextPath);
1352        System.out.println("wrapperPath:" + mappingData.wrapperPath);
1353        System.out.println("pathInfo:" + mappingData.pathInfo);
1354        System.out.println("redirectPath:" + mappingData.redirectPath);
1355
1356        mappingData.recycle();
1357        mapper.map(host, uri, mappingData);
1358        System.out.println("MD Host:" + mappingData.host);
1359        System.out.println("MD Context:" + mappingData.context);
1360        System.out.println("MD Wrapper:" + mappingData.wrapper);
1361
1362        System.out.println("contextPath:" + mappingData.contextPath);
1363        System.out.println("wrapperPath:" + mappingData.wrapperPath);
1364        System.out.println("pathInfo:" + mappingData.pathInfo);
1365        System.out.println("redirectPath:" + mappingData.redirectPath);
1366
1367        for (int i = 0; i < 1000000; i++) {
1368            mappingData.recycle();
1369            mapper.map(host, uri, mappingData);
1370        }
1371
1372        long time = System.currentTimeMillis();
1373        for (int i = 0; i < 1000000; i++) {
1374            mappingData.recycle();
1375            mapper.map(host, uri, mappingData);
1376        }
1377        System.out.println("Elapsed:" + (System.currentTimeMillis() - time));
1378
1379        System.out.println("MD Host:" + mappingData.host);
1380        System.out.println("MD Context:" + mappingData.context);
1381        System.out.println("MD Wrapper:" + mappingData.wrapper);
1382
1383        System.out.println("contextPath:" + mappingData.contextPath);
1384        System.out.println("wrapperPath:" + mappingData.wrapperPath);
1385        System.out.println("requestPath:" + mappingData.requestPath);
1386        System.out.println("pathInfo:" + mappingData.pathInfo);
1387        System.out.println("redirectPath:" + mappingData.redirectPath);
1388
1389        } catch (Exception e) {
1390            e.printStackTrace();
1391        }
1392
1393    }
1394    */

1395
1396
1397}
1398
Popular Tags