1 /*
2 * $Id$
3 *
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21 package org.apache.struts.validator;
22
23 import java.io.IOException;
24 import java.net.URL;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.StringTokenizer;
28
29 import jakarta.servlet.ServletContext;
30 import jakarta.servlet.ServletException;
31 import jakarta.servlet.UnavailableException;
32
33 import org.apache.commons.validator.ValidatorResources;
34 import org.apache.struts.action.ActionServlet;
35 import org.apache.struts.action.PlugIn;
36 import org.apache.struts.config.ModuleConfig;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39 import org.xml.sax.SAXException;
40
41 /**
42 * Loads <code>ValidatorResources</code> based on configuration in the
43 * struts-config.xml file.
44 *
45 * @version $Rev$ $Date: 2005-08-30 00:22:27 -0400 (Tue, 30 Aug 2005)
46 * $
47 * @since Struts 1.1
48 */
49 public class ValidatorPlugIn implements PlugIn {
50
51 /**
52 * The {@code Log} instance for this class.
53 */
54 private final Logger log =
55 LoggerFactory.getLogger(ValidatorPlugIn.class);
56
57 /**
58 * Delimitter for Validator resources.
59 */
60 private final static String RESOURCE_DELIM = ",";
61
62 /**
63 * Application scope key that <code>ValidatorResources</code> is stored
64 * under.
65 */
66 public final static String VALIDATOR_KEY =
67 "org.apache.commons.validator.VALIDATOR_RESOURCES";
68
69 /**
70 * Application scope key that <code>StopOnError</code> is stored under.
71 *
72 * @since Struts 1.2
73 */
74 public final static String STOP_ON_ERROR_KEY =
75 "org.apache.struts.validator.STOP_ON_ERROR";
76
77 /*
78 * The module configuration for our owning module.
79 */
80 // private ModuleConfig config = null;
81
82 /**
83 * The {@link ActionServlet} owning this application.
84 */
85 private ActionServlet servlet = null;
86
87 /**
88 * The set of Form instances that have been created and initialized, keyed
89 * by the struts form name.
90 */
91 protected ValidatorResources resources = null;
92
93 // ------------------------------------------------------------- Properties
94
95 /**
96 * A comma delimitted list of Validator resource.
97 */
98 private String pathnames = null;
99
100 /**
101 * Informs the Validators if it has to stop validation when finding the
102 * first error or if it should continue. Default to <code>true</code> to
103 * keep Struts 1.1 backwards compatibility.
104 */
105 private boolean stopOnFirstError = true;
106
107 /**
108 * Gets a comma delimitted list of Validator resources.
109 *
110 * @return comma delimited list of Validator resource path names
111 */
112 public String getPathnames() {
113 return pathnames;
114 }
115
116 /**
117 * Sets a comma delimitted list of Validator resources.
118 *
119 * @param pathnames delimited list of Validator resource path names
120 */
121 public void setPathnames(String pathnames) {
122 this.pathnames = pathnames;
123 }
124
125 /**
126 * Gets the value for stopOnFirstError.
127 *
128 * @return A boolean indicating whether JavaScript validation should stop
129 * when it finds the first error (Struts 1.1 behaviour) or
130 * continue validation.
131 * @since Struts 1.2
132 */
133 public boolean isStopOnFirstError() {
134 return this.stopOnFirstError;
135 }
136
137 /**
138 * Sets the value for stopOnFirstError.
139 *
140 * @param stopOnFirstError A boolean indicating whether JavaScript
141 * validation should stop when it finds the first
142 * error (Struts 1.1 behaviour) or continue
143 * validation.
144 * @since Struts 1.2
145 */
146 public void setStopOnFirstError(boolean stopOnFirstError) {
147 this.stopOnFirstError = stopOnFirstError;
148 }
149
150 /**
151 * Initialize and load our resources.
152 *
153 * @param servlet The ActionServlet for our application
154 * @param config The ModuleConfig for our owning module
155 * @throws ServletException if we cannot configure ourselves correctly
156 */
157 public void init(ActionServlet servlet, ModuleConfig config)
158 throws ServletException {
159
160 // Remember our associated configuration and servlet
161 // this.config = config;
162 this.servlet = servlet;
163
164 // Verify only one instance of the plugin is loaded per module
165 String validatorModuleKey = VALIDATOR_KEY + config.getPrefix();
166 ServletContext servletContext = servlet.getServletContext();
167 if (servletContext.getAttribute(validatorModuleKey) != null) {
168 throw new UnavailableException("ValidatorPlugIn cannot be " +
169 "redefined for module '" + config.getPrefix() + "'");
170 }
171
172 // Load our database from persistent storage
173 try {
174 this.initResources();
175 servletContext.setAttribute(validatorModuleKey, resources);
176 servletContext.setAttribute(STOP_ON_ERROR_KEY + '.'
177 + config.getPrefix(),
178 (this.stopOnFirstError ? Boolean.TRUE : Boolean.FALSE));
179 } catch (Exception e) {
180 log.error(e.getMessage(), e);
181 throw new UnavailableException(
182 "Cannot load a validator resource from '" + pathnames + "'");
183 }
184 }
185
186 /**
187 * Gracefully shut down, releasing any resources that were allocated at
188 * initialization.
189 */
190 public void destroy() {
191 log.debug("Destroying ValidatorPlugin");
192
193 servlet = null;
194 // config = null;
195
196 destroyResources();
197 }
198
199 /**
200 * Initialize the validator resources for this module.
201 *
202 * @throws IOException if an input/output error is encountered
203 * @throws ServletException if we cannot initialize these resources
204 */
205 protected void initResources()
206 throws IOException, ServletException {
207 if ((pathnames == null) || (pathnames.length() <= 0)) {
208 return;
209 }
210
211 StringTokenizer st = new StringTokenizer(pathnames, RESOURCE_DELIM);
212
213 List<URL> urlList = new ArrayList<>();
214
215 try {
216 while (st.hasMoreTokens()) {
217 String validatorRules = st.nextToken().trim();
218
219 log.info("Loading validation rules file from '{}'",
220 validatorRules);
221
222 URL input =
223 servlet.getServletContext().getResource(validatorRules);
224
225 // If the config isn't in the servlet context, try the class
226 // loader which allows the config files to be stored in a jar
227 if (input == null) {
228 input = getClass().getResource(validatorRules);
229 }
230
231 if (input != null) {
232 urlList.add(input);
233 } else {
234 throw new ServletException(
235 "Skipping validation rules file from '"
236 + validatorRules + "'. No url could be located.");
237 }
238 }
239
240 URL[] urlArray = urlList.toArray(new URL[0]);
241
242 this.resources = new ValidatorResources(urlArray);
243 } catch (SAXException sex) {
244 log.error("Skipping all validation", sex);
245 throw new ServletException(sex);
246 }
247 }
248
249 /**
250 * Destroy <code>ValidatorResources</code>.
251 */
252 protected void destroyResources() {
253 resources = null;
254 }
255 }