2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

View Javadoc

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  /*
19   * $Id: ConfigDefinitionsWatchdogFilter.java 464373 2006-10-16 04:21:54Z rahul $
20   */
21  package org.apache.shale.clay.config.beans;
22  
23  import java.io.IOException;
24  import java.io.StreamTokenizer;
25  import java.io.StringReader;
26  import java.util.ArrayList;
27  import java.util.List;
28  import java.util.regex.Pattern;
29  
30  import javax.servlet.http.HttpServletRequest;
31  
32  import org.apache.commons.chain.Command;
33  import org.apache.commons.chain.Context;
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  
37  
38  /***
39   * <p>This is the timing mechanism for looking for modified
40   * Clay templates and configuration files.  This is a preprocess
41   * filter chains command that should only be used in the
42   * development environment.</p>
43   */
44  public class ConfigDefinitionsWatchdogFilter implements Command {
45  
46      /***
47       * <p>Comma-delimited regular expression patterns to include remote host
48       * names that match.</p>
49       */
50      private String includes = null;
51  
52      /***
53       * <p>Array of regular expression patterns for the includes list.</p>
54       */
55      private Pattern[] includesPatterns = new Pattern[0];
56  
57      /***
58       * @return an array of regular expression patterns for the includes list.
59       */
60      private Pattern[] getIncludesPatterns() { return includesPatterns; }
61  
62      /***
63       * @return Return the comma-delimited regular expresson patterns to include
64       * remote host names that match, if any; otherwise, return
65       * <code>null</code>.
66       */
67      public String getIncludes() { return this.includes; }
68  
69  
70      /***
71       * <p>Set the comma-delimited regular expression patterns to include
72       * remote host names that match, if any; or <code>null</code> for no
73       * restrictions.</p>
74       *
75       * @param includes New include pattern(s)
76       */
77      public void setIncludes(String includes) {
78          this.includes = includes;
79          this.includesPatterns = precompile(includes);
80      }
81  
82      /***
83       * <p>Log instance for this class.</p>
84       */
85      private static Log log = LogFactory.getLog(ConfigDefinitionsWatchdogFilter.class);
86  
87  
88      /***
89       * <p>Return the servlet path (if any) concatenated with the path info
90       * (if any) for this request.</p>
91       *
92       * @param context <code>Context</code> for the current request
93       * @return servletPath and pathInfo
94       */
95      protected String value(Context context) {
96  
97          HttpServletRequest request = (HttpServletRequest) context.get("request");
98          String servletPath = request.getServletPath();
99          if (servletPath == null) {
100             servletPath = "";
101         }
102         String pathInfo = request.getPathInfo();
103         if (pathInfo == null) {
104             pathInfo = "";
105         }
106         return servletPath + pathInfo;
107 
108     }
109 
110 
111     /***
112      * <p>Perform the matching algorithm against the value
113      * returned by the <code>value()</code> method.  If the
114      * value <code>matches()</code> the <code>includes</code>
115      * pattern list, the {@link org.apache.shale.clay.component.Clay}
116      * configuration files are checked for changes and reloaded.</p>
117      *
118      * @param context <code>ShaleWebContext</code> for this request
119      * @return <code>true</code> if the chain is done
120      * @exception Exception thrown back to the calling command
121      */
122     public boolean execute(Context context) throws Exception {
123 
124         // Acquire the value to be tested
125         String value = value(context);
126         if (log.isDebugEnabled()) {
127             log.debug("execute(" + value + ")");
128         }
129 
130         // Check for a match on the included list
131         if (value != null && matches(value, getIncludesPatterns(), true)) {
132             if (log.isTraceEnabled()) {
133                 log.trace("  accept(include)");
134             }
135             accept(context);
136         }
137 
138         return false;
139 
140     }
141 
142 
143     /***
144      * <p>Trigger reloading of the {@link org.apache.shale.clay.component.Clay}'s
145      * xml configuration files if the
146      * <code>org.apache.shale.clay.AUTO_RELOAD_CONFIG_FILES</code> init
147      * parameter is set to <code>true</code> in the web.xml.  The HTML templates
148      * are re-cashed on-demand due to their atomicity.  The XML configuration
149      * files are shared by all {@link org.apache.shale.clay.component.Clay}
150      * view composition mechanisms so all files must be reloaded if a change
151      * is made.</p>
152      *
153      * @param context <code>Context</code> for the current request
154      * @exception Exception thrown back to the caller
155      */
156     protected void accept(Context context) throws Exception {
157         ConfigBeanFactory.refresh();
158     }
159 
160     /***
161      * <p>Parse the specified string of comma-delimited (and optionally quoted,
162      * if an embedded comma is required) regular expressions into an array
163      * of precompiled <code>Pattern</code> instances that represent these
164      * expressons.</p>
165      *
166      * @param expr Comma-delimited regular expressions
167      * @return Recognized regular expressions
168      */
169      private Pattern[] precompile(String expr) {
170 
171         if (expr == null) {
172             return new Pattern[0];
173         }
174 
175         // Set up to parse the specified expression
176         StreamTokenizer st =
177           new StreamTokenizer(new StringReader(expr));
178         st.eolIsSignificant(false);
179         st.lowerCaseMode(false);
180         st.slashSlashComments(false);
181         st.slashStarComments(false);
182         st.wordChars(0x00, 0xff);
183         st.quoteChar('\'');
184         st.quoteChar('"');
185         st.whitespaceChars(0, ' ');
186         st.whitespaceChars(',', ',');
187         List list = new ArrayList();
188         int type = 0;
189 
190         // Parse each included expression
191         while (true) {
192             try {
193                 type = st.nextToken();
194             } catch (IOException e) {
195                 ; // Can not happen
196             }
197             if (type == StreamTokenizer.TT_EOF) {
198                 break;
199             } else if (type == StreamTokenizer.TT_NUMBER) {
200                 list.add(Pattern.compile("" + st.nval));
201             } else if (type == StreamTokenizer.TT_WORD) {
202                 list.add(Pattern.compile(st.sval.trim()));
203             } else {
204                 throw new IllegalArgumentException(expr);
205             }
206         }
207 
208         // Return the precompiled patterns as an array
209         return (Pattern[]) list.toArray(new Pattern[list.size()]);
210 
211     }
212 
213      /***
214       * <p>Match the specified expression against the specified precompiled
215       * patterns.  If there are no patterns, return the specified unrestricted
216       * return value; otherwise, return <code>true</code> if the expression
217       * matches one of the patterns, or <code>false</code> otherwise.</p>
218       *
219       * @param expr Expression to be tested
220       * @param patterns Array of <code>Pattern</code> to be tested against
221       * @param unrestricted Result to be returned if there are no matches
222       * @return <code>true</code> if a match is found
223       */
224      protected boolean matches(String expr, Pattern[] patterns,
225                              boolean unrestricted) {
226 
227          // Check for the unrestricted case
228          if ((patterns == null) || (patterns.length == 0)) {
229              return unrestricted;
230          }
231 
232          // Compare each pattern in turn for a match
233          for (int i = 0; i < patterns.length; i++) {
234              if (patterns[i].matcher(expr).matches()) {
235                  return true;
236              }
237          }
238 
239          // No match found, so return false
240          return false;
241 
242      }
243 
244 }