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.extras.plugins;
22
23 import jakarta.servlet.ServletException;
24
25 import org.apache.struts.action.ActionServlet;
26 import org.apache.struts.action.PlugIn;
27 import org.apache.struts.config.ForwardConfig;
28 import org.apache.struts.config.MessageResourcesConfig;
29 import org.apache.struts.config.ModuleConfig;
30 import org.apache.struts.config.PlugInConfig;
31 import org.apache.struts.util.RequestUtils;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36 * <p>Convenient implementation of {@link PlugIn} that performs as many
37 * verification tests on the information stored in the {@link ModuleConfig}
38 * for this module as is practical. Based on the setting of the
39 * <code>fatal</code> property (which defaults to <code>true</code>), the
40 * detection of any such errors will cause a <code>ServletException</code> to
41 * be thrown from the <code>init</code> method, which will ultimately cause
42 * the initialization of your Struts controller servlet to fail.</p>
43 *
44 * @version $Rev$ $Date$
45 * @since Struts 1.1
46 */
47 public class ModuleConfigVerifier implements PlugIn {
48
49 /**
50 * The {@code Log} instance for this class.
51 */
52 private final Logger log =
53 LoggerFactory.getLogger(ModuleConfigVerifier.class);
54
55 // ----------------------------------------------------- Instance Variables
56
57 /**
58 * <p>The {@link ModuleConfig} instance for our module.</p>
59 */
60 protected ModuleConfig config = null;
61
62 /**
63 * <p>The {@link ActionServlet} instance we are associated with.</p>
64 */
65 protected ActionServlet servlet = null;
66
67 // ------------------------------------------------------------- Properties
68
69 /**
70 * <p>Should the existence of configuration errors be fatal.</p>
71 */
72 private boolean fatal = true;
73
74 /**
75 * <p>Return the "configuation errors are fatal" flag.</p>
76 */
77 public boolean isFatal() {
78 return (this.fatal);
79 }
80
81 /**
82 * <p>Set the "configuration errors are fatal" flag.</p>
83 *
84 * @param fatal The new flag value
85 */
86 public void setFatal(boolean fatal) {
87 this.fatal = fatal;
88 }
89
90 // --------------------------------------------------------- Public Methods
91
92 /**
93 * <p>Receive notification that our owning module is being shut down.</p>
94 */
95 public void destroy() {
96 ; // No action required
97 }
98
99 // See interface for Javadoc.
100 public void init(ActionServlet servlet, ModuleConfig config)
101 throws ServletException {
102 this.servlet = servlet;
103 this.config = config;
104
105 boolean ok = true;
106
107 log.atInfo().log(() -> servlet.getInternal().getMessage("configVerifying"));
108
109 // Perform detailed validations of each portion of ModuleConfig
110 // :TODO: Complete methods to verify Action, Controller, et al, configurations.
111
112 /*
113 if (!verifyActionConfigs()) {
114 ok = false;
115 }
116 */
117 if (!verifyActionMappingClass()) {
118 ok = false;
119 }
120
121 /*
122 if (!verifyControllerConfig()) {
123 ok = false;
124 }
125 if (!verifyExceptionConfigs()) {
126 ok = false;
127 }
128 if (!verifyFormBeanConfigs()) {
129 ok = false;
130 }
131 */
132 if (!verifyForwardConfigs()) {
133 ok = false;
134 }
135
136 if (!verifyMessageResourcesConfigs()) {
137 ok = false;
138 }
139
140 if (!verifyPlugInConfigs()) {
141 ok = false;
142 }
143
144 // Throw an exception on a fatal error
145 log.atInfo().log(() -> servlet.getInternal().getMessage("configCompleted"));
146
147 if (!ok && isFatal()) {
148 throw new ServletException(servlet.getInternal().getMessage("configFatal"));
149 }
150 }
151
152 // ------------------------------------------------------ Protected Methods
153
154 /**
155 * <p>Return <code>true</code> if information returned by
156 * <code>config.getActionMappingClass</code> is all valid; otherwise, log
157 * error messages and return <code>false</code>.</p>
158 */
159 protected boolean verifyActionMappingClass() {
160 String amcName = config.getActionMappingClass();
161
162 if (amcName == null) {
163 log.atError().log(() -> servlet.getInternal().getMessage("verifyActionMappingClass.missing"));
164
165 return (false);
166 }
167
168 try {
169 RequestUtils.applicationClass(amcName);
170 } catch (ClassNotFoundException e) {
171 log.atError().log(() -> servlet.getInternal().getMessage("verifyActionMappingClass.invalid",
172 amcName));
173
174 return (false);
175 }
176
177 return (true);
178 }
179
180 /**
181 * <p>Return <code>true</code> if information returned by
182 * <code>config.findForwardConfigs</code> is all valid; otherwise, log
183 * error messages and return <code>false</code>.</p>
184 */
185 protected boolean verifyForwardConfigs() {
186 boolean ok = true;
187 ForwardConfig[] fcs = config.findForwardConfigs();
188
189 for (ForwardConfig fc : fcs) {
190 String path = fc.getPath();
191
192 if (path == null) {
193 log.atError().log(() -> servlet.getInternal().getMessage("verifyForwardConfigs.missing",
194 fc.getName()));
195 ok = false;
196 } else if (!path.startsWith("/")) {
197 log.atError().log(() -> servlet.getInternal().getMessage("verifyForwardConfigs.invalid",
198 path, fc.getName()));
199 }
200 }
201
202 return (ok);
203 }
204
205 /**
206 * <p>Return <code>true</code> if information returned by
207 * <code>config.findMessageResourcesConfigs</code> is all valid;
208 * otherwise, log error messages and return <code>false</code>.</p>
209 */
210 protected boolean verifyMessageResourcesConfigs() {
211 boolean ok = true;
212 MessageResourcesConfig[] mrcs = config.findMessageResourcesConfigs();
213
214 for (int i = 0; i < mrcs.length; i++) {
215 String factory = mrcs[i].getFactory();
216
217 if (factory == null) {
218 log.atError().log(() -> servlet.getInternal().getMessage("verifyMessageResourcesConfigs.missing"));
219 ok = false;
220 } else {
221 try {
222 RequestUtils.applicationClass(factory);
223 } catch (ClassNotFoundException e) {
224 log.atError().log(() -> servlet.getInternal().getMessage("verifyMessageResourcesConfigs.invalid",
225 factory));
226 ok = false;
227 }
228 }
229
230 String key = mrcs[i].getKey();
231
232 if (key == null) {
233 log.atError().log(() -> servlet.getInternal().getMessage("verifyMessageResourcesConfigs.key"));
234 }
235 }
236
237 return (ok);
238 }
239
240 /**
241 * <p>Return <code>true</code> if information returned by
242 * <code>config.findPluginConfigs</code> is all valid; otherwise, log
243 * error messages and return <code>false</code>.</p>
244 */
245 protected boolean verifyPlugInConfigs() {
246 boolean ok = true;
247 PlugInConfig[] pics = config.findPlugInConfigs();
248
249 for (int i = 0; i < pics.length; i++) {
250 String className = pics[i].getClassName();
251
252 if (className == null) {
253 log.atError().log(() -> servlet.getInternal().getMessage("verifyPlugInConfigs.missing"));
254 ok = false;
255 } else {
256 try {
257 RequestUtils.applicationClass(className);
258 } catch (ClassNotFoundException e) {
259 log.atError().log(() -> servlet.getInternal().getMessage("verifyPlugInConfigs.invalid",
260 className));
261 ok = false;
262 }
263 }
264 }
265
266 return (ok);
267 }
268 }