View Javadoc
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 }