View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.trinidad.resource;
20  
21  import java.io.IOException;
22  import java.net.URL;
23  
24  import java.util.ArrayList;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.regex.Matcher;
28  import java.util.regex.Pattern;
29  import org.apache.myfaces.trinidad.logging.TrinidadLogger;
30  
31  /**
32   * A resource loader implementation which loads resources
33   * by pattern matching the requested resource path to a
34   * registered resource loader.
35   * 
36   * Change history
37   * 2006-08-01: -= Simon Lessard =-
38   *             Changed to use a list of entry rather than a dual typed
39   *             one to add more type safety with minimal memory overhaul
40   *             and get a really small performance gain. 
41   *
42   */
43  public class RegexResourceLoader extends ResourceLoader
44  {
45    /**
46     * Creates a new RegexResourceLoader.
47     */
48    public RegexResourceLoader()
49    {
50      _loaders = new ArrayList<RegexResourceNode>();
51    }
52    
53    @Override
54    protected URL findResource(
55      String path) throws IOException
56    {
57  
58      // a RegexResourceNode contains a ResourceLoader 
59      // (e.g., a CoreClassLoaderResourceLoader) and a Pattern.
60      // loop through all the RegExResourceNodes that have been registered
61      // with the RegexResourceLoader's register(regex, loader) method, 
62      // and find the node where the path fits the node's pattern.
63      // Once the node is found, return the resource with the given name
64      for(RegexResourceNode node : _loaders)
65      {
66        Matcher matcher = node.getPattern().matcher(path);
67        if (matcher.matches())
68        {
69          return node.getResourceLoader().getResource(matcher.group(1));
70        }
71      }
72      
73      return null;
74    }
75    
76    /**
77     * Registers a resource loader by regular expression.
78     * 
79     * @param regex  the regular expression to match
80     * @param loader  the resource loader to use for matching paths
81     */
82    protected void register(
83      String         regex,
84      ResourceLoader loader)
85    {
86      Pattern pattern = Pattern.compile(regex);
87      _checkPathRegex(regex);
88      _loaders.add(new RegexResourceNode(pattern,loader));
89    }
90    
91    /**
92     * Deregisters a resource loader by regular expression.
93     * 
94     * @param regex  the regular expression to remove
95     */
96    protected void deregister(
97      String regex)
98    {
99      // -= Simon Lessard =- 
100     // Regex compilation can be expensive and the variable 
101     // is only used for equals purpose, so use the other way 
102     // around instead, that is get the expression out of the 
103     // compiled patterns through Pattern.pattern().
104     // Pattern pattern = Pattern.compile(regex);
105 
106     Iterator<RegexResourceNode> nodeIterator = _loaders.iterator();
107     while(nodeIterator.hasNext())
108     {
109       if(regex.equals(nodeIterator.next().getPattern().pattern()))
110       {
111         nodeIterator.remove();
112         return;
113       }
114     }
115   }
116 
117   /**
118    * Verify that the regular expression will match only paths with a 
119    * leading slash.
120    * 
121    * @param regex  the regular expression to verify
122    */
123   private void _checkPathRegex(
124     String regex)
125   {
126     if (!regex.startsWith("/")  &&
127         !regex.startsWith("(/"))
128     {
129       throw new IllegalArgumentException(_LOG.getMessage(
130         "RESOURCE_PATH_REGULAR_EXPRESSION_HAS_NO_LEADING_SLASH", regex));
131     }
132   }
133   
134   private static class RegexResourceNode
135   {
136     public RegexResourceNode(Pattern pattern, ResourceLoader loader)
137     {
138       _pattern = pattern;
139       _loader  = loader;
140     }
141     
142     public Pattern getPattern()
143     {
144       return _pattern;
145     }
146     
147     public ResourceLoader getResourceLoader()
148     {
149       return _loader;
150     }
151 
152     private ResourceLoader _loader;
153     private Pattern _pattern;
154   }
155 
156   private final List<RegexResourceNode> _loaders;
157   private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
158     RegexResourceLoader.class);
159 }