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.chain.commands;
22
23 import org.apache.commons.chain.Catalog;
24 import org.apache.commons.chain.CatalogFactory;
25 import org.apache.commons.chain.Command;
26 import org.apache.commons.chain.Filter;
27 import org.apache.struts.chain.contexts.ActionContext;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 /**
32 * Intercept any exception thrown by a subsequent {@code Command} in this
33 * processing chain, and fire the configured exception handler chain after
34 * storing the exception that has occurred into the {@code Context}.
35 */
36 public class ExceptionCatcher extends ActionCommandBase implements Filter<ActionContext> {
37
38 /**
39 * The {@code Log} instance for this class.
40 */
41 private final Logger log =
42 LoggerFactory.getLogger(ExceptionCatcher.class);
43
44 // ------------------------------------------------------ Instance Variables
45
46 /**
47 * Field for CatalogName property.
48 */
49 private String catalogName = null;
50
51 /**
52 * Field for ExceptionCommand property.
53 */
54 private String exceptionCommand = null;
55
56 // -------------------------------------------------------------- Properties
57
58 /**
59 * Return the name of the {@code Catalog} in which to perform lookups, or
60 * {@code null} for the default {@code Catalog}.
61 *
62 * @return Name of catalog to use, or null
63 */
64 public String getCatalogName() {
65 return (this.catalogName);
66 }
67
68 /**
69 * Set the name of the {@code Catalog} in which to perform lookups, or
70 * {@code null} for the default {@code Catalog}.
71 *
72 * @param catalogName The new catalog name or {@code null}
73 */
74 public void setCatalogName(String catalogName) {
75 this.catalogName = catalogName;
76 }
77
78 /**
79 * Return the name of the command to be executed if an exception occurs.
80 *
81 * @return The name of the command to be executed on an exception
82 */
83 public String getExceptionCommand() {
84 return (this.exceptionCommand);
85 }
86
87 /**
88 * Set the name of the command to be executed if an exception occurs.
89 *
90 * @param exceptionCommand The name of the chain to be executed
91 */
92 public void setExceptionCommand(String exceptionCommand) {
93 this.exceptionCommand = exceptionCommand;
94 }
95
96 // ---------------------------------------------------------- Public Methods
97
98 /**
99 * Clear any existing stored exception and pass the {@code context} on to
100 * the remainder of the current chain.
101 *
102 * @param actionCtx The {@code Context} for the current request
103 *
104 * @return {@code false} so that processing continues
105 *
106 * @throws Exception On any error
107 */
108 @Override
109 protected boolean execute_(ActionContext actionCtx)
110 throws Exception {
111 actionCtx.setException(null);
112
113 return CONTINUE_PROCESSING;
114 }
115
116 /**
117 * If an exception was thrown by a subsequent {@code Command}, pass it on
118 * to the specified exception handling chain. Otherwise, do nothing.
119 *
120 * @param actionCtx The {@link ActionContext} to be processed by this
121 * {@link Filter}
122 * @param exception The {@code Exception} (if any) that was thrown by the
123 * last {@link Command} that was executed; otherwise
124 * {@code null}
125 *
126 * @return TRUE if post processing an exception occurred and the exception
127 * processing chain invoked
128 *
129 * @throws IllegalStateException If exception throws exception
130 */
131 public boolean postprocess(ActionContext actionCtx, Exception exception) {
132 // Do nothing if there was no exception thrown
133 if (exception == null) {
134 return (false);
135 }
136
137 // Stash the exception in the specified context attribute
138 log.debug("Attempting to handle a thrown exception");
139
140 actionCtx.setException(exception);
141
142 // Execute the specified command
143 try {
144 Command<ActionContext> command = lookupExceptionCommand();
145
146 if (command == null) {
147 log.error("Cannot find exceptionCommand '{}'",
148 exceptionCommand);
149 throw new IllegalStateException(
150 "Cannot find exceptionCommand '" + exceptionCommand + "'");
151 }
152
153 log.trace("Calling exceptionCommand '{}'", exceptionCommand);
154
155 command.execute(actionCtx);
156 } catch (Exception e) {
157 log.warn("Exception from exceptionCommand '{}'",
158 exceptionCommand, e);
159 IllegalStateException e2 = new IllegalStateException("Exception chain threw exception");
160 e2.initCause(e);
161 throw e2;
162 }
163
164 return true;
165 }
166
167 /**
168 * Return the command to be executed if an exception occurs.
169 *
170 * @return The command to be executed if an exception occurs
171 *
172 * @throws IllegalArgumentException If catalog cannot be found
173 * @throws IllegalStateException If command property is not specified
174 */
175 protected Command<ActionContext> lookupExceptionCommand() {
176 final String catalogName = getCatalogName();
177
178 final CatalogFactory<ActionContext> catalogFactory =
179 CatalogFactory.getInstance();
180
181 final Catalog<ActionContext> catalog;
182
183 if (catalogName == null) {
184 catalog = catalogFactory.getCatalog();
185
186 if (catalog == null) {
187 log.error("Cannot find default catalog");
188 throw new IllegalArgumentException(
189 "Cannot find default catalog");
190 }
191 } else {
192 catalog = catalogFactory.getCatalog(catalogName);
193
194 if (catalog == null) {
195 log.error("Cannot find catalog '{}'", catalogName);
196 throw new IllegalArgumentException("Cannot find catalog '"
197 + catalogName + "'");
198 }
199 }
200
201 String exceptionCommand = getExceptionCommand();
202
203 if (exceptionCommand == null) {
204 log.error("No exceptionCommand property specified");
205 throw new IllegalStateException(
206 "No exceptionCommand property specfied");
207 }
208
209 return catalog.getCommand(exceptionCommand);
210 }
211 }