View Javadoc

1   /*
2    * $Id: ResourceProxyHandlerImpl.java,v 1.2 2010/03/19 14:53:48 oeuillot Exp $
3    */
4   package org.rcfaces.core.internal.contentProxy;
5   
6   import java.io.IOException;
7   import java.io.InputStream;
8   import java.net.InetAddress;
9   import java.net.UnknownHostException;
10  import java.util.ArrayList;
11  import java.util.Collections;
12  import java.util.HashMap;
13  import java.util.List;
14  import java.util.Map;
15  import java.util.StringTokenizer;
16  import java.util.regex.Matcher;
17  import java.util.regex.Pattern;
18  
19  import javax.faces.FacesException;
20  import javax.faces.context.ExternalContext;
21  import javax.faces.context.FacesContext;
22  import javax.servlet.ServletRequest;
23  
24  import org.apache.commons.digester.Digester;
25  import org.apache.commons.digester.Rule;
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.rcfaces.core.internal.Constants;
29  import org.rcfaces.core.internal.RcfacesContext;
30  import org.rcfaces.core.internal.contentAccessor.BasicContentAccessor;
31  import org.rcfaces.core.internal.contentAccessor.IContentAccessor;
32  import org.rcfaces.core.internal.contentAccessor.IContentPath;
33  import org.rcfaces.core.internal.contentAccessor.IContentProxyHandler;
34  import org.rcfaces.core.internal.contentAccessor.IGeneratedResourceInformation;
35  import org.rcfaces.core.internal.lang.StringAppender;
36  import org.rcfaces.core.internal.util.PathTypeTools;
37  import org.rcfaces.core.provider.AbstractProvider;
38  
39  /**
40   * 
41   * @author Olivier Oeuillot (latest modification by $Author: oeuillot $)
42   * @version $Revision: 1.2 $ $Date: 2010/03/19 14:53:48 $
43   */
44  public class ResourceProxyHandlerImpl extends AbstractProvider implements
45          IContentProxyHandler, IResourceProxyHandler {
46  
47      private static final String REVISION = "$Revision: 1.2 $";
48  
49      private static final Log LOG = LogFactory
50              .getLog(ResourceProxyHandlerImpl.class);
51  
52      private static final String RESOURCES_DEFAULT_PROXY_URL_PARAMETER = Constants
53              .getPackagePrefix()
54              + ".RESOURCE_PROXY_DEFAULT_URL";
55  
56      private static final String RESOURCES_PROXY_RULES_PATHS_PARAMETER = Constants
57              .getPackagePrefix()
58              + ".RESOURCE_PROXY_RULES_PATHS";
59  
60      private static final String ENABLE_FILTRED_RESOURCES_PROXY_PARAMETER = Constants
61              .getPackagePrefix()
62              + ".ENABLE_FILTRED_RESOURCES_PROXY";
63  
64      private static final String ENABLE_FRAMEWORK_RESOURCES_PROXY_PARAMETER = Constants
65              .getPackagePrefix()
66              + ".ENABLE_FRAMEWORK_RESOURCES_PROXY";
67  
68      protected static final String PROTOCOL_KEYWORD = "protocol";
69  
70      protected static final String LOCAL_NAME_KEYWORD = "host";
71  
72      protected static final String LOCAL_ADDR_KEYWORD = "addr";
73  
74      protected static final String LOCAL_PORT_KEYWORD = "port";
75  
76      protected static final String OPTIONAL_LOCAL_PORT_KEYWORD = "optional-port";
77  
78      protected static final String CONTEXT_PATH_KEYWORD = "context";
79  
80      protected static final int DEFAULT_HTTP_PORT = 80;
81  
82      protected static final int DEFAULT_HTTPS_PORT = 443;
83  
84      private static final String CACHED_URL_BASE_PROPERTY = "org.rcfaces.core.CACHED_URL_BASE";
85  
86      private static final String NO_BASE_URL_STRING = CACHED_URL_BASE_PROPERTY;
87  
88      private static final String DISABLED_URL = "disabled";
89  
90      private IPatternRule defaultRule;
91  
92      private IPatternRule rules[];
93  
94      private boolean enabled;
95  
96      private final Map keywordValueMap = new HashMap(16);
97  
98      private boolean filtredResourcesEnabled;
99  
100     private boolean frameworkResourceEnabled;
101 
102     public String getId() {
103         return ID;
104     }
105 
106     public void startup(FacesContext facesContext) {
107 
108         ExternalContext externalContext = facesContext.getExternalContext();
109 
110         final String defaultURL = externalContext
111                 .getInitParameter(RESOURCES_DEFAULT_PROXY_URL_PARAMETER);
112 
113         String rulesPaths = externalContext
114                 .getInitParameter(RESOURCES_PROXY_RULES_PATHS_PARAMETER);
115 
116         if ((defaultURL == null || "none".equalsIgnoreCase(defaultURL))
117                 && (rulesPaths == null || rulesPaths.trim().length() == 0)) {
118             LOG
119                     .info("Disable application proxy rewriting engine. (context parameter '"
120                             + RESOURCES_DEFAULT_PROXY_URL_PARAMETER
121                             + "="
122                             + defaultURL + "')");
123             return;
124         }
125 
126         enabled = true;
127 
128         if (defaultURL != null) {
129             this.defaultRule = new DefaultPatternRule(defaultURL, null);
130         }
131 
132         if (rulesPaths != null && rulesPaths.length() > 0) {
133             loadRules(externalContext, rulesPaths);
134         }
135 
136         filtredResourcesEnabled = "true".equalsIgnoreCase(externalContext
137                 .getInitParameter(ENABLE_FILTRED_RESOURCES_PROXY_PARAMETER));
138 
139         frameworkResourceEnabled = ("false".equalsIgnoreCase(externalContext
140                 .getInitParameter(ENABLE_FRAMEWORK_RESOURCES_PROXY_PARAMETER)) == false);
141 
142         LOG.info("Set proxy pattern to '" + defaultURL
143                 + "', filtredResourcesEnabled=" + filtredResourcesEnabled
144                 + ", frameworkResourceEnabled=" + frameworkResourceEnabled
145                 + ".");
146 
147         RcfacesContext rcfacesContext = RcfacesContext
148                 .getInstance(facesContext);
149 
150         if (rcfacesContext.getResourceProxyHandler() == null) {
151             rcfacesContext.setResourceProxyHandler(this);
152 
153             if (rcfacesContext.getDefaultContentProxyHandler() == null) {
154                 rcfacesContext.setDefaultContentProxyHandler(this);
155             }
156         }
157 
158         fillKeywordValues(rcfacesContext, keywordValueMap);
159 
160     }
161 
162     public boolean isEnabled() {
163         return enabled;
164     }
165 
166     public boolean isFiltredResourcesEnabled() {
167         return filtredResourcesEnabled;
168     }
169 
170     public boolean isFrameworkResourcesEnabled() {
171         return frameworkResourceEnabled;
172     }
173 
174     public IContentAccessor getProxyedContentAccessor(
175             RcfacesContext rcfacesContext, FacesContext facesContext,
176             IContentAccessor contentAccessor,
177             IGeneratedResourceInformation[] contentInformationRef) {
178 
179         int pathType = contentAccessor.getPathType();
180         if (pathType != IContentPath.RELATIVE_PATH_TYPE
181                 && pathType != IContentPath.ABSOLUTE_PATH_TYPE
182                 && pathType != IContentPath.CONTEXT_PATH_TYPE) {
183 
184             return contentAccessor;
185         }
186 
187         if (facesContext == null) {
188             facesContext = FacesContext.getCurrentInstance();
189         }
190 
191         String url = (String) contentAccessor.getContentRef();
192 
193         if (pathType == IContentPath.RELATIVE_PATH_TYPE) {
194             // A convertir en CONTEXT
195 
196             url = PathTypeTools.convertRelativePathToContextPath(facesContext,
197                     url, null);
198 
199         } else if (pathType == IContentPath.ABSOLUTE_PATH_TYPE) {
200             // A convertir en CONTEXT
201 
202             String converted = PathTypeTools.convertAbsolutePathToContextType(
203                     facesContext, url);
204 
205             if (converted == null) {
206                 throw new FacesException("Can not convert '" + url
207                         + "' to context path type.");
208             }
209 
210             url = converted;
211         }
212 
213         String converted = computeProxyedURL(facesContext, contentAccessor,
214                 contentInformationRef, url);
215 
216         if (LOG.isDebugEnabled()) {
217             LOG.debug("computeNewURL returns '" + converted + "'.");
218         }
219 
220         if (converted == null) {
221             return contentAccessor;
222         }
223 
224         return new BasicContentAccessor(facesContext, converted,
225                 contentAccessor, IContentPath.EXTERNAL_PATH_TYPE);
226     }
227 
228     public String computeProxyedURL(FacesContext facesContext,
229             IContentAccessor contentAccessor,
230             IGeneratedResourceInformation[] contentInformationRef, String url) {
231 
232         if (rules != null) {
233             for (int i = 0; i < rules.length; i++) {
234                 IPatternRule rule = rules[i];
235 
236                 if (rule.acceptURL(url) == false) {
237                     continue;
238                 }
239 
240                 String ret = computeProxyedURL(facesContext, contentAccessor,
241                         contentInformationRef, rule, url);
242                 if (ret != null) {
243                     if (ret == DISABLED_URL) {
244                         return null;
245                     }
246                     return ret;
247                 }
248             }
249         }
250 
251         if (defaultRule != null) {
252             String ret = computeProxyedURL(facesContext, contentAccessor,
253                     contentInformationRef, defaultRule, url);
254             if (ret != null) {
255                 if (ret == DISABLED_URL) {
256                     return null;
257                 }
258                 return ret;
259             }
260         }
261 
262         return null;
263     }
264 
265     protected String computeProxyedURL(FacesContext facesContext,
266             IContentAccessor contentAccessor,
267             IGeneratedResourceInformation[] contentInformationRef,
268             IPatternRule rule, String url) {
269 
270         Map requestMap = facesContext.getExternalContext().getRequestMap();
271 
272         String baseURL = (String) requestMap.get(rule);
273 
274         if (baseURL == NO_BASE_URL_STRING) {
275             return null;
276         }
277         if (baseURL == DISABLED_URL) {
278             return DISABLED_URL;
279         }
280 
281         if (baseURL == null) {
282             baseURL = computeRequestURLBase(facesContext, contentAccessor,
283                     contentInformationRef, rule);
284             if (baseURL == null) {
285                 requestMap.put(rule, NO_BASE_URL_STRING);
286 
287                 return null;
288             }
289             if (baseURL == DISABLED_URL) {
290                 requestMap.put(rule, DISABLED_URL);
291 
292                 return baseURL;
293             }
294             if (baseURL.endsWith("/")) {
295                 baseURL = baseURL.substring(0, baseURL.length() - 1);
296             }
297 
298             requestMap.put(rule, baseURL);
299         }
300 
301         StringAppender sa = new StringAppender(baseURL, url.length() + 2);
302 
303         if (url.startsWith("/") == false) {
304             sa.append('/');
305         }
306 
307         sa.append(url);
308 
309         String converted = sa.toString();
310 
311         return converted;
312     }
313 
314     protected String computeRequestURLBase(FacesContext facesContext,
315             IContentAccessor contentAccessor,
316             IGeneratedResourceInformation[] contentInformationRef,
317             IPatternRule rule) {
318 
319         String url = rule.getBaseURI();
320 
321         if (DISABLED_URL.equals(url)) {
322             return DISABLED_URL;
323         }
324 
325         if (url.indexOf('[') < 0) {
326             if (LOG.isDebugEnabled()) {
327                 LOG.debug("Set URL base to pattern '" + url
328                         + "'. (no replacement)");
329             }
330 
331             return url;
332         }
333 
334         char chs[] = url.toCharArray();
335 
336         StringAppender sa = new StringAppender(url.length() * 2);
337         int first = 0;
338 
339         for (int i = 0; i < chs.length; i++) {
340             char c = chs[i];
341 
342             if (c != '[') {
343                 continue;
344             }
345 
346             if (first < i) {
347                 sa.append(chs, first, i - first);
348 
349                 first = i;
350             }
351 
352             int j = i + 1;
353             for (i = j; i < chs.length; i++) {
354                 c = chs[i];
355                 if (c == ']') {
356                     break;
357                 }
358             }
359 
360             if (i == chs.length) {
361                 // PROBLEME !!!!
362 
363                 throw new FacesException("Invalid pattern '" + url + "'.");
364             }
365 
366             String keyword = url.substring(j, i);
367 
368             IKeywordValue keywordValue = (IKeywordValue) keywordValueMap
369                     .get(keyword);
370             if (keywordValue != null) {
371                 String ret = keywordValue.getValue(facesContext, keyword);
372                 if (ret != null) {
373                     sa.append(ret);
374                 }
375             }
376 
377             first = i + 1;
378         }
379 
380         if (first == 0) {
381             if (LOG.isDebugEnabled()) {
382                 LOG.debug("Set URL base to pattern '" + url + "'.");
383             }
384 
385         } else if (first < chs.length) {
386             sa.append(chs, first, chs.length - first);
387         }
388 
389         String prefix = sa.toString();
390 
391         if (LOG.isDebugEnabled()) {
392             LOG.debug("Set URL base to '" + prefix + "'.");
393         }
394 
395         return prefix;
396     }
397 
398     protected void fillKeywordValues(RcfacesContext rcfacesContext,
399             Map replaceMap) {
400 
401         replaceMap.put(PROTOCOL_KEYWORD, new IKeywordValue() {
402             private static final String REVISION = "$Revision: 1.2 $";
403 
404             public String getValue(FacesContext facesContext, String keyword) {
405                 Object request = facesContext.getExternalContext().getRequest();
406                 if ((request instanceof ServletRequest) == false) {
407                     return null;
408                 }
409 
410                 ServletRequest servletRequest = (ServletRequest) request;
411 
412                 String protocol = servletRequest.getScheme();
413                 if (protocol != null && protocol.length() > 0) {
414                     return protocol;
415                 }
416 
417                 return null;
418             }
419         });
420 
421         replaceMap.put(LOCAL_NAME_KEYWORD, new IKeywordValue() {
422             private static final String REVISION = "$Revision: 1.2 $";
423 
424             public String getValue(FacesContext facesContext, String keyword) {
425                 Object request = facesContext.getExternalContext().getRequest();
426                 if ((request instanceof ServletRequest) == false) {
427                     return null;
428                 }
429 
430                 ServletRequest servletRequest = (ServletRequest) request;
431 
432                 String localName = servletRequest.getServerName();
433                 if (localName != null && localName.length() > 0) {
434                     return localName;
435                 }
436 
437                 return null;
438             }
439         });
440 
441         replaceMap.put(LOCAL_ADDR_KEYWORD, new IKeywordValue() {
442             private static final String REVISION = "$Revision: 1.2 $";
443 
444             public String getValue(FacesContext facesContext, String keyword) {
445                 Object request = facesContext.getExternalContext().getRequest();
446                 if ((request instanceof ServletRequest) == false) {
447                     return null;
448                 }
449 
450                 ServletRequest servletRequest = (ServletRequest) request;
451 
452                 String localAddr = servletRequest.getServerName();
453                 if (localAddr != null && localAddr.length() > 0) {
454                     InetAddress inetAddress;
455                     try {
456                         inetAddress = InetAddress.getByName(localAddr);
457 
458                     } catch (UnknownHostException e) {
459                         LOG.error("Can not getByName '" + localAddr + "'.", e);
460                         inetAddress = null;
461                     }
462 
463                     if (inetAddress != null) {
464                         String address = inetAddress.getHostAddress();
465                         if (address != null) {
466                             return address;
467                         }
468                     }
469                 }
470 
471                 return null;
472             }
473         });
474 
475         replaceMap.put(LOCAL_PORT_KEYWORD, new IKeywordValue() {
476             private static final String REVISION = "$Revision: 1.2 $";
477 
478             public String getValue(FacesContext facesContext, String keyword) {
479                 Object request = facesContext.getExternalContext().getRequest();
480                 if ((request instanceof ServletRequest) == false) {
481                     return null;
482                 }
483 
484                 ServletRequest servletRequest = (ServletRequest) request;
485 
486                 int port = servletRequest.getServerPort();
487                 if (port > 0) {
488                     return String.valueOf(port);
489                 }
490 
491                 return null;
492             }
493         });
494 
495         replaceMap.put(OPTIONAL_LOCAL_PORT_KEYWORD, new IKeywordValue() {
496             private static final String REVISION = "$Revision: 1.2 $";
497 
498             public String getValue(FacesContext facesContext, String keyword) {
499                 Object request = facesContext.getExternalContext().getRequest();
500                 if ((request instanceof ServletRequest) == false) {
501                     return null;
502                 }
503 
504                 ServletRequest servletRequest = (ServletRequest) request;
505 
506                 String protocol = servletRequest.getScheme();
507                 int port = servletRequest.getServerPort();
508 
509                 if ("http".equalsIgnoreCase(protocol)
510                         && port == DEFAULT_HTTP_PORT) {
511 
512                     return null;
513 
514                 } else if ("https".equalsIgnoreCase(protocol)
515                         && port == DEFAULT_HTTPS_PORT) {
516                     return null;
517                 }
518 
519                 if (port > 0) {
520                     return ":" + port;
521                 }
522 
523                 return null;
524             }
525         });
526 
527         replaceMap.put(CONTEXT_PATH_KEYWORD, new IKeywordValue() {
528             private static final String REVISION = "$Revision: 1.2 $";
529 
530             public String getValue(FacesContext facesContext, String keyword) {
531                 String requestContextPath = facesContext.getExternalContext()
532                         .getRequestContextPath();
533                 if (requestContextPath != null) {
534                     if (requestContextPath.length() > 0
535                             && requestContextPath.charAt(0) == '/') {
536                         return requestContextPath.substring(1);
537                     }
538                     return requestContextPath;
539                 }
540 
541                 return null;
542             }
543         });
544     }
545 
546     private void loadRules(ExternalContext externalContext, String rulesPath) {
547         StringTokenizer st = new StringTokenizer(rulesPath, ",");
548 
549         List rules = new ArrayList(32);
550 
551         Digester digester = new Digester();
552         fillDigesterRules(digester, rules);
553 
554         for (; st.hasMoreTokens();) {
555             String tok = st.nextToken().trim();
556 
557             InputStream ins = externalContext.getResourceAsStream(tok);
558             if (ins == null) {
559                 LOG.error("Can not open rules resource '" + tok + "'.");
560                 continue;
561             }
562 
563             try {
564                 LOG.info("Open rules resource '" + tok + "'.");
565 
566                 digester.parse(ins);
567 
568             } catch (Exception ex) {
569                 LOG.error("Can not parse rules from '" + tok + "'.", ex);
570 
571             } finally {
572                 try {
573                     ins.close();
574                 } catch (IOException e) {
575                     LOG.error(e);
576                 }
577             }
578         }
579 
580         if (rules.isEmpty() == false) {
581             this.rules = (IPatternRule[]) rules.toArray(new IPatternRule[rules
582                     .size()]);
583         }
584     }
585 
586     protected void fillDigesterRules(Digester digester, final List rules) {
587 
588         final Map infos = new HashMap();
589 
590         digester.addRule("rules/rule", new Rule() {
591 
592             public void end(String namespace, String name) throws Exception {
593 
594                 String url = (String) infos.get("url");
595                 Map attributes = null;
596                 String pattern = (String) infos.get("pattern");
597                 String regexp = (String) infos.get("regexp");
598                 infos.clear();
599 
600                 if (url == null) {
601                     LOG.error("No URL defined for rule pattern='" + pattern
602                             + "' or regexp='" + regexp + "'.");
603                     return;
604                 }
605                 url = url.trim();
606 
607                 if (DISABLED_URL.equalsIgnoreCase(url)) {
608                     url = DISABLED_URL;
609                 }
610 
611                 if (pattern != null) {
612                     pattern = pattern.trim();
613 
614                     if (pattern.indexOf('*') >= 0) {
615                         if (pattern.equals("*")) {
616                             rules.add(new DefaultPatternRule(url, attributes));
617                             return;
618                         }
619 
620                         if (pattern.indexOf('*') == pattern.length() - 1) {
621                             rules.add(new StartsWithRule(url, attributes,
622                                     pattern));
623                             return;
624                         }
625 
626                         if (pattern.lastIndexOf('*') == 0) {
627                             rules
628                                     .add(new EndsWithRule(url, attributes,
629                                             pattern));
630                             return;
631                         }
632 
633                         throw new FacesException(
634                                 "Invalid expression ! (Use regexp tag to declare more complex pattern) '" + pattern
635                                         + "'.");
636                     }
637 
638                     rules.add(new BasicPatternRule(url, attributes, pattern));
639                     return;
640                 }
641 
642                 if (regexp != null) {
643                     regexp = regexp.trim();
644 
645                     rules.add(new RegExpPatternRule(url, attributes, regexp));
646                     return;
647                 }
648 
649             }
650 
651         });
652         digester.addRule("rules/rule/pattern", new Rule() {
653 
654             public void body(String namespace, String name, String text)
655                     throws Exception {
656                 infos.put("pattern", text);
657             }
658         });
659         digester.addRule("rules/rule/regexp", new Rule() {
660 
661             public void body(String namespace, String name, String text)
662                     throws Exception {
663                 infos.put("regexp", text);
664             }
665         });
666         digester.addRule("rules/rule/url", new Rule() {
667 
668             public void body(String namespace, String name, String text)
669                     throws Exception {
670                 infos.put("url", text);
671             }
672         });
673     }
674 
675     /**
676      * 
677      * @author Olivier Oeuillot (latest modification by $Author: oeuillot $)
678      * @version $Revision: 1.2 $ $Date: 2010/03/19 14:53:48 $
679      */
680     protected interface IKeywordValue {
681         String getValue(FacesContext facesContext, String keyword);
682     }
683 
684     /**
685      * 
686      * @author Olivier Oeuillot (latest modification by $Author: oeuillot $)
687      * @version $Revision: 1.2 $ $Date: 2010/03/19 14:53:48 $
688      */
689     protected static interface IPatternRule {
690         String getPattern();
691 
692         String getBaseURI();
693 
694         Map listAttributes();
695 
696         boolean acceptURL(String url);
697     }
698 
699     /**
700      * 
701      * @author Olivier Oeuillot (latest modification by $Author: oeuillot $)
702      * @version $Revision: 1.2 $ $Date: 2010/03/19 14:53:48 $
703      */
704     protected static abstract class AbstractPatternRule implements IPatternRule {
705         protected final String baseURI;
706 
707         protected final Map attributes;
708 
709         public AbstractPatternRule(String baseURI, Map attributes) {
710             this.baseURI = baseURI;
711 
712             if (attributes == null) {
713                 attributes = Collections.EMPTY_MAP;
714             }
715             this.attributes = attributes;
716         }
717 
718         public String getBaseURI() {
719             return baseURI;
720         }
721 
722         public Map listAttributes() {
723             return attributes;
724         }
725 
726         public String toString() {
727             return "[Rule baseURI='" + baseURI + "' attributes='" + attributes
728                     + "']";
729         }
730     }
731 
732     /**
733      * 
734      * @author Olivier Oeuillot (latest modification by $Author: oeuillot $)
735      * @version $Revision: 1.2 $ $Date: 2010/03/19 14:53:48 $
736      */
737     protected static class BasicPatternRule extends AbstractPatternRule {
738         protected final String pattern;
739 
740         public BasicPatternRule(String baseURI, Map attributes, String pattern) {
741             super(baseURI, attributes);
742 
743             this.pattern = pattern;
744         }
745 
746         public String getPattern() {
747             return pattern;
748         }
749 
750         public int hashCode() {
751             return pattern.hashCode();
752         }
753 
754         public boolean acceptURL(String url) {
755             return pattern.equals(url);
756         }
757 
758         public boolean equals(Object obj) {
759             if (this == obj)
760                 return true;
761             if (obj == null)
762                 return false;
763             if (getClass() != obj.getClass())
764                 return false;
765             BasicPatternRule other = (BasicPatternRule) obj;
766             if (pattern == null) {
767                 if (other.pattern != null)
768                     return false;
769             } else if (!pattern.equals(other.pattern))
770                 return false;
771             return true;
772         }
773 
774         public String toString() {
775             return "[BasicRule pattern='" + pattern + "' baseURI='" + baseURI
776                     + "' attributes='" + attributes + "']";
777         }
778     }
779 
780     /**
781      * 
782      * @author Olivier Oeuillot (latest modification by $Author: oeuillot $)
783      * @version $Revision: 1.2 $ $Date: 2010/03/19 14:53:48 $
784      */
785     protected static class StartsWithRule extends BasicPatternRule {
786 
787         private final String localPattern;
788 
789         public StartsWithRule(String baseURI, Map attributes, String pattern) {
790             super(baseURI, attributes, pattern);
791 
792             localPattern = pattern.substring(0, pattern.length() - 1);
793         }
794 
795         public boolean acceptURL(String url) {
796             return url.startsWith(localPattern);
797         }
798     }
799 
800     /**
801      * 
802      * @author Olivier Oeuillot (latest modification by $Author: oeuillot $)
803      * @version $Revision: 1.2 $ $Date: 2010/03/19 14:53:48 $
804      */
805     protected static class EndsWithRule extends BasicPatternRule {
806 
807         private final String localPattern;
808 
809         public EndsWithRule(String baseURI, Map attributes, String pattern) {
810             super(baseURI, attributes, pattern);
811 
812             localPattern = pattern.substring(1);
813         }
814 
815         public boolean acceptURL(String url) {
816             return url.endsWith(localPattern);
817         }
818     }
819 
820     /**
821      * 
822      * @author Olivier Oeuillot (latest modification by $Author: oeuillot $)
823      * @version $Revision: 1.2 $ $Date: 2010/03/19 14:53:48 $
824      */
825     protected static class RegExpPatternRule extends BasicPatternRule {
826 
827         private final Pattern localPattern;
828 
829         public RegExpPatternRule(String baseURI, Map attributes, String regex) {
830             super(baseURI, attributes, regex);
831 
832             localPattern = Pattern.compile(regex);
833         }
834 
835         public boolean acceptURL(String url) {
836             Matcher m = localPattern.matcher(url);
837 
838             return m.matches();
839         }
840     }
841 
842     /**
843      * 
844      * @author Olivier Oeuillot (latest modification by $Author: oeuillot $)
845      * @version $Revision: 1.2 $ $Date: 2010/03/19 14:53:48 $
846      */
847     protected static class DefaultPatternRule extends BasicPatternRule {
848 
849         public DefaultPatternRule(String baseURI, Map attributes) {
850             super(baseURI, attributes, "*");
851         }
852 
853         public boolean acceptURL(String url) {
854             return true;
855         }
856     }
857 }