2009/05/20 - Apache Shale has been retired.
For more information, please explore the Attic.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
125 String value = value(context);
126 if (log.isDebugEnabled()) {
127 log.debug("execute(" + value + ")");
128 }
129
130
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
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
191 while (true) {
192 try {
193 type = st.nextToken();
194 } catch (IOException e) {
195 ;
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
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
228 if ((patterns == null) || (patterns.length == 0)) {
229 return unrestricted;
230 }
231
232
233 for (int i = 0; i < patterns.length; i++) {
234 if (patterns[i].matcher(expr).matches()) {
235 return true;
236 }
237 }
238
239
240 return false;
241
242 }
243
244 }