1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.struts2.dispatcher;
22
23 import java.io.File;
24 import java.io.IOException;
25 import java.net.MalformedURLException;
26 import java.net.URL;
27 import java.util.ArrayList;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Locale;
31 import java.util.Map;
32
33 import javax.servlet.ServletContext;
34 import javax.servlet.ServletException;
35 import javax.servlet.http.HttpServletRequest;
36 import javax.servlet.http.HttpServletResponse;
37
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import org.apache.struts2.ServletActionContext;
41 import org.apache.struts2.StrutsConstants;
42 import org.apache.struts2.StrutsStatics;
43 import org.apache.struts2.config.*;
44 import org.apache.struts2.config.ClasspathConfigurationProvider.ClasspathPageLocator;
45 import org.apache.struts2.config.ClasspathConfigurationProvider.PageLocator;
46 import org.apache.struts2.dispatcher.mapper.ActionMapping;
47 import org.apache.struts2.dispatcher.multipart.MultiPartRequest;
48 import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
49 import org.apache.struts2.util.AttributeMap;
50 import org.apache.struts2.util.ClassLoaderUtils;
51 import org.apache.struts2.util.ObjectFactoryDestroyable;
52 import org.apache.struts2.views.freemarker.FreemarkerManager;
53
54 import com.opensymphony.xwork2.util.FileManager;
55 import com.opensymphony.xwork2.ActionContext;
56 import com.opensymphony.xwork2.ActionProxy;
57 import com.opensymphony.xwork2.ActionProxyFactory;
58 import com.opensymphony.xwork2.ObjectFactory;
59 import com.opensymphony.xwork2.Result;
60 import com.opensymphony.xwork2.config.Configuration;
61 import com.opensymphony.xwork2.config.ConfigurationException;
62 import com.opensymphony.xwork2.config.ConfigurationManager;
63 import com.opensymphony.xwork2.config.ConfigurationProvider;
64 import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
65 import com.opensymphony.xwork2.inject.Container;
66 import com.opensymphony.xwork2.inject.ContainerBuilder;
67 import com.opensymphony.xwork2.inject.Inject;
68 import com.opensymphony.xwork2.util.LocalizedTextUtil;
69 import com.opensymphony.xwork2.util.ObjectTypeDeterminer;
70 import com.opensymphony.xwork2.util.ObjectTypeDeterminerFactory;
71 import com.opensymphony.xwork2.util.ValueStack;
72 import com.opensymphony.xwork2.util.ValueStackFactory;
73 import com.opensymphony.xwork2.util.location.Location;
74 import com.opensymphony.xwork2.util.location.LocationUtils;
75 import com.opensymphony.xwork2.util.location.LocatableProperties;
76 import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
77
78 import freemarker.template.Template;
79
80 /***
81 * A utility class the actual dispatcher delegates most of its tasks to. Each instance
82 * of the primary dispatcher holds an instance of this dispatcher to be shared for
83 * all requests.
84 *
85 * @see org.apache.struts2.dispatcher.FilterDispatcher
86 * @see org.apache.struts2.portlet.dispatcher.Jsr168Dispatcher
87 */
88 public class Dispatcher {
89
90 /***
91 * Provide a logging instance.
92 */
93 private static final Log LOG = LogFactory.getLog(Dispatcher.class);
94
95 /***
96 * Provide a thread local instance.
97 */
98 private static ThreadLocal<Dispatcher> instance = new ThreadLocal<Dispatcher>();
99
100 /***
101 * Store list of DispatcherListeners.
102 */
103 private static List<DispatcherListener> dispatcherListeners =
104 new ArrayList<DispatcherListener>();
105
106 /***
107 * Store ConfigurationManager instance, set on init.
108 */
109 private ConfigurationManager configurationManager;
110
111 /***
112 * Store whether portlet support is active
113 * (set to true by Jsr168Dispatcher).
114 */
115 private static boolean portletSupportActive;
116
117 /***
118 * Store state of StrutsConstants.STRUTS_DEVMODE setting.
119 */
120 private static boolean devMode;
121
122 /***
123 * Store state of StrutsConstants.STRUTS_I18N_ENCODING setting.
124 */
125 private static String defaultEncoding;
126
127 /***
128 * Store state of StrutsConstants.STRUTS_LOCALE setting.
129 */
130 private static String defaultLocale;
131
132 /***
133 * Store state of StrutsConstants.STRUTS_MULTIPART_SAVEDIR setting.
134 */
135 private static String multipartSaveDir;
136
137 /***
138 * Provide list of default configuration files.
139 */
140 private static final String DEFAULT_CONFIGURATION_PATHS = "struts-default.xml,struts-plugin.xml,struts.xml";
141
142 /***
143 * Store state of STRUTS_DISPATCHER_PARAMETERSWORKAROUND.
144 * <p/>
145 * The workaround is for WebLogic.
146 * We try to autodect WebLogic on Dispatcher init.
147 * The workaround can also be enabled manually.
148 */
149 private boolean paramsWorkaroundEnabled = false;
150
151 /***
152 * Provide the dispatcher instance for the current thread.
153 *
154 * @return The dispatcher instance
155 */
156 public static Dispatcher getInstance() {
157 return instance.get();
158 }
159
160 /***
161 * Store the dispatcher instance for this thread.
162 *
163 * @param instance The instance
164 */
165 public static void setInstance(Dispatcher instance) {
166 Dispatcher.instance.set(instance);
167
168
169 if (instance != null) {
170 Container cont = instance.getContainer();
171 if (cont != null) {
172 ObjectFactory.setObjectFactory(cont.getInstance(ObjectFactory.class));
173 } else {
174 LOG.warn("This dispatcher instance doesn't have a container, so the object factory won't be set.");
175 }
176 } else {
177 ObjectFactory.setObjectFactory(null);
178 }
179 }
180
181 /***
182 * Add a dispatcher lifecycle listener.
183 *
184 * @param listener The listener to add
185 */
186 public static synchronized void addDispatcherListener(DispatcherListener listener) {
187 dispatcherListeners.add(listener);
188 }
189
190 /***
191 * Remove a specific dispatcher lifecycle listener.
192 *
193 * @param listener The listener
194 */
195 public static synchronized void removeDispatcherListener(DispatcherListener listener) {
196 dispatcherListeners.remove(listener);
197 }
198
199 private ServletContext servletContext;
200 private Map<String, String> initParams;
201
202
203 /***
204 * Create the Dispatcher instance for a given ServletContext and set of initialization parameters.
205 *
206 * @param servletContext Our servlet context
207 * @param initParams The set of initialization parameters
208 */
209 public Dispatcher(ServletContext servletContext, Map<String, String> initParams) {
210 this.servletContext = servletContext;
211 this.initParams = initParams;
212 }
213
214 /***
215 * Modify state of StrutsConstants.STRUTS_DEVMODE setting.
216 * @param mode New setting
217 */
218 @Inject(StrutsConstants.STRUTS_DEVMODE)
219 public static void setDevMode(String mode) {
220 devMode = "true".equals(mode);
221 }
222
223 /***
224 * Modify state of StrutsConstants.STRUTS_LOCALE setting.
225 * @param val New setting
226 */
227 @Inject(value=StrutsConstants.STRUTS_LOCALE, required=false)
228 public static void setDefaultLocale(String val) {
229 defaultLocale = val;
230 }
231
232 /***
233 * Modify state of StrutsConstants.STRUTS_I18N_ENCODING setting.
234 * @param val New setting
235 */
236 @Inject(StrutsConstants.STRUTS_I18N_ENCODING)
237 public static void setDefaultEncoding(String val) {
238 defaultEncoding = val;
239 }
240
241 /***
242 * Modify state of StrutsConstants.STRUTS_MULTIPART_SAVEDIR setting.
243 * @param val New setting
244 */
245 @Inject(StrutsConstants.STRUTS_MULTIPART_SAVEDIR)
246 public static void setMultipartSaveDir(String val) {
247 multipartSaveDir = val;
248 }
249
250 /***
251 * Releases all instances bound to this dispatcher instance.
252 */
253 public void cleanup() {
254
255
256 ObjectFactory objectFactory = getContainer().getInstance(ObjectFactory.class);
257 if (objectFactory == null) {
258 LOG.warn("Object Factory is null, something is seriously wrong, no clean up will be performed");
259 }
260 if (objectFactory instanceof ObjectFactoryDestroyable) {
261 try {
262 ((ObjectFactoryDestroyable)objectFactory).destroy();
263 }
264 catch(Exception e) {
265
266 LOG.error("exception occurred while destroying ObjectFactory ["+objectFactory+"]", e);
267 }
268 }
269
270
271 instance.set(null);
272
273
274 synchronized(Dispatcher.class) {
275 if (dispatcherListeners.size() > 0) {
276 for (DispatcherListener l : dispatcherListeners) {
277 l.dispatcherDestroyed(this);
278 }
279 }
280 }
281
282
283 configurationManager.destroyConfiguration();
284 configurationManager = null;
285 }
286
287 private void init_DefaultProperties() {
288 configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());
289 }
290
291 private void init_LegacyStrutsProperties() {
292 configurationManager.addConfigurationProvider(new LegacyPropertiesConfigurationProvider());
293 }
294
295 private void init_TraditionalXmlConfigurations() {
296 String configPaths = initParams.get("config");
297 if (configPaths == null) {
298 configPaths = DEFAULT_CONFIGURATION_PATHS;
299 }
300 String[] files = configPaths.split("//s*[,]//s*");
301 for (String file : files) {
302 if (file.endsWith(".xml")) {
303 if ("xwork.xml".equals(file)) {
304 configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));
305 } else {
306 configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));
307 }
308 } else {
309 throw new IllegalArgumentException("Invalid configuration file name");
310 }
311 }
312 }
313
314 private void init_ZeroConfiguration() {
315 String packages = initParams.get("actionPackages");
316 if (packages != null) {
317 String[] names = packages.split("//s*[,]//s*");
318
319 if (names.length > 0) {
320 ClasspathConfigurationProvider provider = new ClasspathConfigurationProvider(names);
321 provider.setPageLocator(new ServletContextPageLocator(servletContext));
322 configurationManager.addConfigurationProvider(provider);
323 }
324 }
325 }
326
327 private void init_CustomConfigurationProviders() {
328 String configProvs = initParams.get("configProviders");
329 if (configProvs != null) {
330 String[] classes = configProvs.split("//s*[,]//s*");
331 for (String cname : classes) {
332 try {
333 Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());
334 ConfigurationProvider prov = (ConfigurationProvider)cls.newInstance();
335 configurationManager.addConfigurationProvider(prov);
336 } catch (InstantiationException e) {
337 throw new ConfigurationException("Unable to instantiate provider: "+cname, e);
338 } catch (IllegalAccessException e) {
339 throw new ConfigurationException("Unable to access provider: "+cname, e);
340 } catch (ClassNotFoundException e) {
341 throw new ConfigurationException("Unable to locate provider class: "+cname, e);
342 }
343 }
344 }
345 }
346
347 private void init_MethodConfigurationProvider() {
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378 }
379
380 private void init_FilterInitParameters() {
381 configurationManager.addConfigurationProvider(new ConfigurationProvider() {
382 public void destroy() {}
383 public void init(Configuration configuration) throws ConfigurationException {}
384 public void loadPackages() throws ConfigurationException {}
385 public boolean needsReload() { return false; }
386
387 public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
388 props.putAll(initParams);
389 }
390 });
391 }
392
393 private void init_AliasStandardObjects() {
394 configurationManager.addConfigurationProvider(new BeanSelectionProvider());
395 }
396
397 private Container init_PreloadConfiguration() {
398 Configuration config = configurationManager.getConfiguration();
399 Container container = config.getContainer();
400
401 boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));
402 LocalizedTextUtil.setReloadBundles(reloadi18n);
403
404 ObjectTypeDeterminer objectTypeDeterminer = container.getInstance(ObjectTypeDeterminer.class);
405 ObjectTypeDeterminerFactory.setInstance(objectTypeDeterminer);
406
407 return container;
408 }
409
410 private void init_CheckConfigurationReloading(Container container) {
411 FileManager.setReloadingConfigs("true".equals(container.getInstance(String.class,
412 StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD)));
413 }
414
415 private void init_CheckWebLogicWorkaround(Container container) {
416
417 if (servletContext != null && servletContext.getServerInfo() != null
418 && servletContext.getServerInfo().indexOf("WebLogic") >= 0) {
419 LOG.info("WebLogic server detected. Enabling Struts parameter access work-around.");
420 paramsWorkaroundEnabled = true;
421 } else {
422 paramsWorkaroundEnabled = "true".equals(container.getInstance(String.class,
423 StrutsConstants.STRUTS_DISPATCHER_PARAMETERSWORKAROUND));
424 }
425
426 synchronized(Dispatcher.class) {
427 if (dispatcherListeners.size() > 0) {
428 for (DispatcherListener l : dispatcherListeners) {
429 l.dispatcherInitialized(this);
430 }
431 }
432 }
433
434 }
435
436 /***
437 * Load configurations, including both XML and zero-configuration strategies,
438 * and update optional settings, including whether to reload configurations and resource files.
439 */
440 public void init() {
441
442 if (configurationManager == null) {
443 configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
444 }
445
446 init_DefaultProperties();
447 init_TraditionalXmlConfigurations();
448 init_LegacyStrutsProperties();
449 init_ZeroConfiguration();
450 init_CustomConfigurationProviders();
451 init_MethodConfigurationProvider();
452 init_FilterInitParameters() ;
453 init_AliasStandardObjects() ;
454
455 Container container = init_PreloadConfiguration();
456 init_CheckConfigurationReloading(container);
457 init_CheckWebLogicWorkaround(container);
458
459 }
460
461 /***
462 * Load Action class for mapping and invoke the appropriate Action method, or go directly to the Result.
463 * <p/>
464 * This method first creates the action context from the given parameters,
465 * and then loads an <tt>ActionProxy</tt> from the given action name and namespace.
466 * After that, the Action method is executed and output channels through the response object.
467 * Actions not found are sent back to the user via the {@link Dispatcher#sendError} method,
468 * using the 404 return code.
469 * All other errors are reported by throwing a ServletException.
470 *
471 * @param request the HttpServletRequest object
472 * @param response the HttpServletResponse object
473 * @param mapping the action mapping object
474 * @throws ServletException when an unknown error occurs (not a 404, but typically something that
475 * would end up as a 5xx by the servlet container)
476 * @param context Our ServletContext object
477 */
478 public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,
479 ActionMapping mapping) throws ServletException {
480
481 Map<String, Object> extraContext = createContextMap(request, response, mapping, context);
482
483
484 ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
485 if (stack != null) {
486 extraContext.put(ActionContext.VALUE_STACK, ValueStackFactory.getFactory().createValueStack(stack));
487 }
488
489 String timerKey = "Handling request from Dispatcher";
490 try {
491 UtilTimerStack.push(timerKey);
492 String namespace = mapping.getNamespace();
493 String name = mapping.getName();
494 String method = mapping.getMethod();
495
496 Configuration config = configurationManager.getConfiguration();
497 ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
498 namespace, name, extraContext, true, false);
499 proxy.setMethod(method);
500 request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
501
502
503 if (mapping.getResult() != null) {
504 Result result = mapping.getResult();
505 result.execute(proxy.getInvocation());
506 } else {
507 proxy.execute();
508 }
509
510
511 if (stack != null) {
512 request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
513 }
514 } catch (ConfigurationException e) {
515 LOG.error("Could not find action or result", e);
516 sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);
517 } catch (Exception e) {
518 LOG.error("Could not execute action", e);
519 sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
520 } finally {
521 UtilTimerStack.pop(timerKey);
522 }
523 }
524
525 /***
526 * Create a context map containing all the wrapped request objects
527 *
528 * @param request The servlet request
529 * @param response The servlet response
530 * @param mapping The action mapping
531 * @param context The servlet context
532 * @return A map of context objects
533 */
534 public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,
535 ActionMapping mapping, ServletContext context) {
536
537
538 Map requestMap = new RequestMap(request);
539
540
541 Map params = null;
542 if (mapping != null) {
543 params = mapping.getParams();
544 }
545 Map requestParams = new HashMap(request.getParameterMap());
546 if (params != null) {
547 params.putAll(requestParams);
548 } else {
549 params = requestParams;
550 }
551
552
553 Map session = new SessionMap(request);
554
555
556 Map application = new ApplicationMap(context);
557
558 Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context);
559 extraContext.put(ServletActionContext.ACTION_MAPPING, mapping);
560 return extraContext;
561 }
562
563 /***
564 * Merge all application and servlet attributes into a single <tt>HashMap</tt> to represent the entire
565 * <tt>Action</tt> context.
566 *
567 * @param requestMap a Map of all request attributes.
568 * @param parameterMap a Map of all request parameters.
569 * @param sessionMap a Map of all session attributes.
570 * @param applicationMap a Map of all servlet context attributes.
571 * @param request the HttpServletRequest object.
572 * @param response the HttpServletResponse object.
573 * @param servletContext the ServletContextmapping object.
574 * @return a HashMap representing the <tt>Action</tt> context.
575 */
576 public HashMap<String,Object> createContextMap(Map requestMap,
577 Map parameterMap,
578 Map sessionMap,
579 Map applicationMap,
580 HttpServletRequest request,
581 HttpServletResponse response,
582 ServletContext servletContext) {
583 HashMap<String,Object> extraContext = new HashMap<String,Object>();
584 extraContext.put(ActionContext.PARAMETERS, new HashMap(parameterMap));
585 extraContext.put(ActionContext.SESSION, sessionMap);
586 extraContext.put(ActionContext.APPLICATION, applicationMap);
587
588 Locale locale;
589 if (defaultLocale != null) {
590 locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());
591 } else {
592 locale = request.getLocale();
593 }
594
595 extraContext.put(ActionContext.LOCALE, locale);
596
597
598 extraContext.put(StrutsStatics.HTTP_REQUEST, request);
599 extraContext.put(StrutsStatics.HTTP_RESPONSE, response);
600 extraContext.put(StrutsStatics.SERVLET_CONTEXT, servletContext);
601
602
603 extraContext.put("request", requestMap);
604 extraContext.put("session", sessionMap);
605 extraContext.put("application", applicationMap);
606 extraContext.put("parameters", parameterMap);
607
608 AttributeMap attrMap = new AttributeMap(extraContext);
609 extraContext.put("attr", attrMap);
610
611 return extraContext;
612 }
613
614 /***
615 * Return the path to save uploaded files to (this is configurable).
616 *
617 * @return the path to save uploaded files to
618 * @param servletContext Our ServletContext
619 */
620 private String getSaveDir(ServletContext servletContext) {
621 String saveDir = multipartSaveDir.trim();
622
623 if (saveDir.equals("")) {
624 File tempdir = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
625 LOG.info("Unable to find 'struts.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir");
626
627 if (tempdir != null) {
628 saveDir = tempdir.toString();
629 }
630 } else {
631 File multipartSaveDir = new File(saveDir);
632
633 if (!multipartSaveDir.exists()) {
634 multipartSaveDir.mkdir();
635 }
636 }
637
638 if (LOG.isDebugEnabled()) {
639 LOG.debug("saveDir=" + saveDir);
640 }
641
642 return saveDir;
643 }
644
645 /***
646 * Prepare a request, including setting the encoding and locale.
647 *
648 * @param request The request
649 * @param response The response
650 */
651 public void prepare(HttpServletRequest request, HttpServletResponse response) {
652 String encoding = null;
653 if (defaultEncoding != null) {
654 encoding = defaultEncoding;
655 }
656
657 Locale locale = null;
658 if (defaultLocale != null) {
659 locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());
660 }
661
662 if (encoding != null) {
663 try {
664 request.setCharacterEncoding(encoding);
665 } catch (Exception e) {
666 LOG.error("Error setting character encoding to '" + encoding + "' - ignoring.", e);
667 }
668 }
669
670 if (locale != null) {
671 response.setLocale(locale);
672 }
673
674 if (paramsWorkaroundEnabled) {
675 request.getParameter("foo");
676 }
677 }
678
679 /***
680 * Wrap and return the given request or return the original request object.
681 * </p>
682 * This method transparently handles multipart data as a wrapped class around the given request.
683 * Override this method to handle multipart requests in a special way or to handle other types of requests.
684 * Note, {@link org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper} is
685 * flexible - look first to that object before overriding this method to handle multipart data.
686 *
687 * @param request the HttpServletRequest object.
688 * @param servletContext Our ServletContext object
689 * @return a wrapped request or original request.
690 * @see org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper
691 * @throws java.io.IOException on any error.
692 */
693 public HttpServletRequest wrapRequest(HttpServletRequest request, ServletContext servletContext) throws IOException {
694
695 if (request instanceof StrutsRequestWrapper) {
696 return request;
697 }
698
699 String content_type = request.getContentType();
700 if (content_type != null && content_type.indexOf("multipart/form-data") != -1) {
701 MultiPartRequest multi = getContainer().getInstance(MultiPartRequest.class);
702 request = new MultiPartRequestWrapper(multi, request, getSaveDir(servletContext));
703 } else {
704 request = new StrutsRequestWrapper(request);
705 }
706
707 return request;
708 }
709
710 /***
711 * Send an HTTP error response code.
712 *
713 * @param request the HttpServletRequest object.
714 * @param response the HttpServletResponse object.
715 * @param code the HttpServletResponse error code (see {@link javax.servlet.http.HttpServletResponse} for possible error codes).
716 * @param e the Exception that is reported.
717 * @param ctx the ServletContext object.
718 */
719 public void sendError(HttpServletRequest request, HttpServletResponse response,
720 ServletContext ctx, int code, Exception e) {
721 if (devMode) {
722 response.setContentType("text/html");
723
724 try {
725 FreemarkerManager mgr = getContainer().getInstance(FreemarkerManager.class);
726
727 freemarker.template.Configuration config = mgr.getConfiguration(ctx);
728 Template template = config.getTemplate("/org/apache/struts2/dispatcher/error.ftl");
729
730 List<Throwable> chain = new ArrayList<Throwable>();
731 Throwable cur = e;
732 chain.add(cur);
733 while ((cur = cur.getCause()) != null) {
734 chain.add(cur);
735 }
736
737 HashMap<String,Object> data = new HashMap<String,Object>();
738 data.put("exception", e);
739 data.put("unknown", Location.UNKNOWN);
740 data.put("chain", chain);
741 data.put("locator", new Locator());
742 template.process(data, response.getWriter());
743 response.getWriter().close();
744 } catch (Exception exp) {
745 try {
746 response.sendError(code, "Unable to show problem report: " + exp);
747 } catch (IOException ex) {
748
749 }
750 }
751 } else {
752 try {
753
754
755 request.setAttribute("javax.servlet.error.exception", e);
756
757
758 request.setAttribute("javax.servlet.jsp.jspException", e);
759
760
761 response.sendError(code, e.getMessage());
762 } catch (IOException e1) {
763
764 }
765 }
766 }
767
768 /***
769 * Return <tt>true</tt>, if portlet support is active, <tt>false</tt> otherwise.
770 *
771 * @return <tt>true</tt>, if portlet support is active, <tt>false</tt> otherwise.
772 */
773 public boolean isPortletSupportActive() {
774 return portletSupportActive;
775 }
776
777 /***
778 * Modify the portlet support mode.
779 * @param portletSupportActive <tt>true</tt> or <tt>false</tt>
780 */
781 public static void setPortletSupportActive(boolean portletSupportActive) {
782 Dispatcher.portletSupportActive = portletSupportActive;
783 }
784
785 /***
786 * Search classpath for a page.
787 */
788 private final class ServletContextPageLocator implements PageLocator {
789 private final ServletContext context;
790 private ClasspathPageLocator classpathPageLocator = new ClasspathPageLocator();
791
792 private ServletContextPageLocator(ServletContext context) {
793 this.context = context;
794 }
795
796 public URL locate(String path) {
797 URL url = null;
798 try {
799 url = context.getResource(path);
800 if (url == null) {
801 url = classpathPageLocator.locate(path);
802 }
803 } catch (MalformedURLException e) {
804 if (LOG.isDebugEnabled()) {
805 LOG.debug("Unable to resolve path "+path+" against the servlet context");
806 }
807 }
808 return url;
809 }
810 }
811
812 /***
813 * Provide an accessor class for static XWork utility.
814 */
815 public class Locator {
816 public Location getLocation(Object obj) {
817 Location loc = LocationUtils.getLocation(obj);
818 if (loc == null) {
819 return Location.UNKNOWN;
820 }
821 return loc;
822 }
823 }
824
825 /***
826 * Expose the ConfigurationManager instance.
827 *
828 * @return The instance
829 */
830 public ConfigurationManager getConfigurationManager() {
831 return configurationManager;
832 }
833
834 /***
835 * Modify the ConfigurationManager instance
836 *
837 * @param mgr The configuration manager
838 */
839 public void setConfigurationManager(ConfigurationManager mgr) {
840 this.configurationManager = mgr;
841 }
842
843 /***
844 * Expose the dependency injection container.
845 * @return Our dependency injection container
846 */
847 public Container getContainer() {
848 ConfigurationManager mgr = getConfigurationManager();
849 if (mgr == null) {
850 throw new IllegalStateException("The configuration manager shouldn't be null");
851 } else {
852 Configuration config = mgr.getConfiguration();
853 if (config == null) {
854 throw new IllegalStateException("Unable to load configuration");
855 } else {
856 return config.getContainer();
857 }
858 }
859 }
860 }