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  package org.apache.shale.validator.faces;
19  
20  import java.io.IOException;
21  import java.net.MalformedURLException;
22  import java.net.URL;
23  import java.util.ArrayList;
24  import java.util.HashMap;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Map;
28  import javax.faces.FacesException;
29  import javax.servlet.ServletContext;
30  import javax.servlet.ServletContextEvent;
31  import javax.servlet.ServletContextListener;
32  import org.apache.commons.beanutils.PropertyUtils;
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  import org.apache.commons.validator.ValidatorAction;
36  import org.apache.commons.validator.ValidatorResources;
37  import org.apache.shale.validator.Globals;
38  import org.apache.shale.validator.util.ShaleValidatorAction;
39  import org.xml.sax.SAXException;
40  
41  /***
42   * <p>ServletContextListener that loads validator configuration resources
43   * at application startup, and cleans up the libraries we depend on at
44   * application shutdown.</p>
45   */
46  public class ValidatorLifecycleListener implements ServletContextListener {
47      
48  
49      // -------------------------------------------------------- Static Variables
50  
51  
52      // ------------------------------------------------------ Instance Variables
53  
54  
55      /***
56       * <p>The <code>Log</code> instance we will use for this listener.</p>
57       */
58      private Log log = LogFactory.getLog(ValidatorLifecycleListener.class);
59  
60  
61      // ------------------------------------------ ServletContextListener Methods
62  
63  
64      /***
65       * <p>Process an application shutdown event.</p>
66       *
67       * @param event Shutdown event to be processed
68       */
69      public void contextDestroyed(ServletContextEvent event) {
70  
71          if (log.isInfoEnabled()) {
72              log.info("Finalizing Validator Integration");
73          }
74  
75          // Clean up our cached configuration information
76          event.getServletContext().removeAttribute(Globals.VALIDATOR_ACTIONS);
77          event.getServletContext().removeAttribute(Globals.VALIDATOR_RESOURCES);
78  
79          // Clean up dependency libraries we have used
80          PropertyUtils.clearDescriptors(); // Used by Commons Validator via Digester
81          LogFactory.release(Thread.currentThread().getContextClassLoader());
82          log = null;
83  
84      }
85  
86  
87      /***
88       * <p>Process an application startup event.</p>
89       *
90       * @param event Startup event to be processed
91       */
92      public void contextInitialized(ServletContextEvent event) {
93  
94          if (log.isInfoEnabled()) {
95              log.info("Initializing Validator Integration");
96          }
97  
98          // Configure and cache the validator resources for this application
99          ServletContext context = event.getServletContext();
100         ValidatorResources resources = null;
101         try {
102             resources = validatorResources(context);
103         } catch (IllegalArgumentException e) {
104             throw e;
105         } catch (IOException e) {
106             throw new FacesException(e);
107         } catch (SAXException e) {
108             throw new FacesException(e);
109         }
110         context.setAttribute(Globals.VALIDATOR_RESOURCES, resources);
111 
112         // Configure and cache precalculated arrays of validator actions
113         // to be performed at runtime
114         Map actions = validatorActions(resources);
115         context.setAttribute(Globals.VALIDATOR_ACTIONS, actions);
116 
117     }
118 
119 
120     // --------------------------------------------------------- Private Methods
121 
122 
123     /***
124      * <p>Configure precalcualted lists of validator actions that will be
125      * used to perform server side validation processing at runtime.</p>
126      *
127      * @param resources <code>ValidatorResources</code> for this application
128      *
129      * @exception IllegalArgumentException if the configuration resources
130      *  specify invalid validator types, or classes or methods that
131      *  cannot be loaded
132      */
133     private Map validatorActions(ValidatorResources resources) {
134 
135         // Use the validator resources to precalculate a map of
136         // ShaleValidatorAction wrappers for the Commons Validator
137         // ValidatorAction configuration information
138         Map map = new HashMap();
139         Iterator entries = resources.getValidatorActions().entrySet().iterator();
140         while (entries.hasNext()) {
141             Map.Entry entry = (Map.Entry) entries.next();
142             if ("includeJavaScriptUtilities".equals(entry.getKey())) {
143                 continue;
144             }
145             map.put((String) entry.getKey(),
146                     new ShaleValidatorAction(resources,
147                                              (ValidatorAction) entry.getValue()));
148         }
149 
150         // Next, create arrays of the ShaleValidatorAction instances to be
151         // processed for each validator type, taking into account the
152         // configured dependencies that must also be tested
153         ShaleValidatorAction[] result = null;
154         Map results = new HashMap();
155         List list = null;
156         Iterator actions = map.entrySet().iterator();
157         while (actions.hasNext()) {
158             Map.Entry action = (Map.Entry) actions.next();
159             list =
160               ((ShaleValidatorAction) action.getValue()).getAction().getDependencyList();
161             if (list == null) {
162                 list = new ArrayList(0);
163             }
164             result = new ShaleValidatorAction[list.size() + 1];
165             for (int i = 0; i < list.size(); i++) {
166                 result[i] = (ShaleValidatorAction) map.get((String) list.get(i));
167                 if (result[i] == null) {
168                     throw new IllegalArgumentException((String) action.getKey());
169                 }
170             }
171             result[result.length - 1] = (ShaleValidatorAction) action.getValue();
172             results.put((String) action.getKey(), result);
173         }
174 
175         // Return the map of created arrays
176         return results;
177 
178     }
179 
180 
181     /***
182      * <p>Configure the validator resources to be used by this application,
183      * by reading the list of resources configured on the context init
184      * parameter named by <code>Globals.VALIDATOR_RULES</code> (if any),
185      * followed by reading the default resource named by
186      * <code>Globals.DEFAULT_VALIDATOR_RULES</code> (if it has not already
187      * been processed).</p>
188      *
189      * @param context <code>ServletContext</code> for this application
190      *
191      * @exception IllegalArgumentException if a specified resource cannot
192      *  be located, or if a malformed URL is constructed from the
193      *  specified resource name
194      * @exception IOException if an input/output error occurs while
195      *  processing the specified configuration resources
196      * @exception SAXException if an XML parsing error occurs while
197      *  processing the specified configuration resources
198      */
199     private ValidatorResources validatorResources(ServletContext context)
200       throws IOException, SAXException {
201 
202         // Process the explicitly configured resources (if any)
203         List urls = new ArrayList();
204         URL url = null;
205         boolean didDefault = false;
206         String pathnames = context.getInitParameter(Globals.VALIDATOR_RULES);
207         if (pathnames != null) {
208             pathnames = pathnames.trim();
209             while (pathnames.length() > 0) {
210 
211                 // Identify the next resource pathname to be processed
212                 int comma = pathnames.indexOf(',');
213                 String pathname = null;
214                 if (comma >= 0) {
215                     pathname = pathnames.substring(0, comma).trim();
216                     pathnames = pathnames.substring(comma + 1);
217                 } else {
218                     pathname = pathnames.trim();
219                     pathnames = "";
220                 }
221                 if (pathname.length() < 1) {
222                     break;
223                 }
224 
225                 // Add the corresponding URL to our list
226                 try {
227                     url = context.getResource(pathname);
228                 } catch (MalformedURLException e) {
229                     throw new IllegalArgumentException("MalformedURLException:"
230                         + " The URL '" + pathname
231                         + "' specified as a validator rules resource is malformed.");
232                 }
233                 if (url == null) {
234                     url = ValidatorLifecycleListener.class.getResource(pathname);
235                 }
236                 if (url == null) {
237                     throw new IllegalArgumentException(pathname);
238                 }
239                 urls.add(url);
240                 if (Globals.DEFAULT_VALIDATOR_RULES.equals(pathname)) {
241                     didDefault = true;
242                 }
243 
244             }
245         }
246 
247         // Process the default configuration resources (if not already loaded)
248         if (!didDefault) {
249             try {
250                 url = context.getResource(Globals.DEFAULT_VALIDATOR_RULES);
251             } catch (MalformedURLException e) {
252                 throw new IllegalArgumentException("MalformedURLException:"
253                         + " The URL '" + Globals.DEFAULT_VALIDATOR_RULES
254                         + "' specified as a validator rules resource is malformed.");
255             }
256             if (url == null) {
257                 url = ValidatorLifecycleListener.class.getResource(Globals.DEFAULT_VALIDATOR_RULES);
258             }
259             if (url == null) {
260                 throw new IllegalArgumentException(Globals.DEFAULT_VALIDATOR_RULES);
261             }
262             urls.add(url);
263         }
264 
265         // Until <http://issues.apache.org/jira/browse/VALIDATOR-209>
266         // is addressed, we must convert the URLs we have gathered back into
267         // Strings and hope no information is lost in the process
268         String[] array = new String[urls.size()];
269         for (int i = 0; i < array.length; i++) {
270             array[i] = ((URL) urls.get(i)).toExternalForm();
271         }
272         
273         // Construct and return a new ValidatorResources instance
274         return new ValidatorResources(array);
275 
276     }
277 
278 
279 }