1 package org.apache.turbine;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileNotFoundException;
25 import java.io.IOException;
26 import java.io.UnsupportedEncodingException;
27 import java.util.Properties;
28
29 import javax.servlet.ServletConfig;
30 import javax.servlet.ServletContext;
31 import javax.servlet.ServletException;
32 import javax.servlet.http.HttpServlet;
33 import javax.servlet.http.HttpServletRequest;
34 import javax.servlet.http.HttpServletResponse;
35
36 import org.apache.commons.configuration.Configuration;
37 import org.apache.commons.configuration.ConfigurationFactory;
38 import org.apache.commons.configuration.PropertiesConfiguration;
39 import org.apache.commons.lang.StringUtils;
40 import org.apache.commons.lang.exception.ExceptionUtils;
41 import org.apache.commons.logging.Log;
42 import org.apache.commons.logging.LogFactory;
43 import org.apache.log4j.PropertyConfigurator;
44 import org.apache.turbine.modules.ActionLoader;
45 import org.apache.turbine.modules.PageLoader;
46 import org.apache.turbine.services.ServiceManager;
47 import org.apache.turbine.services.TurbineServices;
48 import org.apache.turbine.services.avaloncomponent.AvalonComponentService;
49 import org.apache.turbine.services.rundata.RunDataService;
50 import org.apache.turbine.services.rundata.TurbineRunDataFacade;
51 import org.apache.turbine.services.template.TemplateService;
52 import org.apache.turbine.services.template.TurbineTemplate;
53 import org.apache.turbine.services.velocity.VelocityService;
54 import org.apache.turbine.util.RunData;
55 import org.apache.turbine.util.ServerData;
56 import org.apache.turbine.util.TurbineConfig;
57 import org.apache.turbine.util.TurbineException;
58 import org.apache.turbine.util.security.AccessControlList;
59 import org.apache.turbine.util.template.TemplateInfo;
60 import org.apache.turbine.util.uri.URIConstants;
61
62 /***
63 * Turbine is the main servlet for the entire system. It is <code>final</code>
64 * because you should <i>not</i> ever need to subclass this servlet. If you
65 * need to perform initialization of a service, then you should implement the
66 * Services API and let your code be initialized by it.
67 * If you need to override something in the <code>doGet()</code> or
68 * <code>doPost()</code> methods, edit the TurbineResources.properties file and
69 * specify your own classes there.
70 * <p>
71 * Turbine servlet recognizes the following initialization parameters.
72 * <ul>
73 * <li><code>properties</code> the path to TurbineResources.properties file
74 * used by the default implementation of <code>ResourceService</code>, relative
75 * to the application root.</li>
76 * <li><code>basedir</code> this parameter is used <strong>only</strong> if your
77 * application server does not support web applications, or the or does not
78 * support <code>ServletContext.getRealPath(String)</code> method correctly.
79 * You can use this parameter to specify the directory within the server's
80 * filesystem, that is the base of your web application.</li>
81 * </ul>
82 *
83 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
84 * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
85 * @author <a href="mailto:greg@shwoop.com">Greg Ritter</a>
86 * @author <a href="mailto:john.mcnally@clearink.com">John D. McNally</a>
87 * @author <a href="mailto:frank.kim@clearink.com">Frank Y. Kim</a>
88 * @author <a href="mailto:krzewski@e-point.pl">Rafal Krzewski</a>
89 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
90 * @author <a href="mailto:sean@informage.net">Sean Legassick</a>
91 * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
92 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
93 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
94 * @author <a href="mailto:epugh@upstate.com">Eric Pugh</a>
95 * @author <a href="mailto:seade@backstagetech.com.au">Scott Eade</a>
96 * @version $Id: Turbine.java 543399 2007-06-01 06:15:17Z seade $
97 */
98 public class Turbine
99 extends HttpServlet
100 implements TurbineConstants
101 {
102 /*** SerialVersionUID for serialization */
103 private static final long serialVersionUID = -6895381097045304308L;
104
105 /***
106 * Name of path info parameter used to indicate the redirected stage of
107 * a given user's initial Turbine request
108 */
109 public static final String REDIRECTED_PATHINFO_NAME = "redirected";
110
111 /*** The base directory key */
112 public static final String BASEDIR_KEY = "basedir";
113
114 /***
115 * In certain situations the init() method is called more than once,
116 * somtimes even concurrently. This causes bad things to happen,
117 * so we use this flag to prevent it.
118 */
119 private static boolean firstInit = true;
120
121 /*** Whether init succeeded or not. */
122 private static Throwable initFailure = null;
123
124 /***
125 * Should initialization activities be performed during doGet() execution?
126 */
127 private static boolean firstDoGet = true;
128
129 /***
130 * Keep all the properties of the web server in a convenient data
131 * structure
132 */
133 private static ServerData serverData = null;
134
135 /*** The base from which the Turbine application will operate. */
136 private static String applicationRoot;
137
138 /*** Servlet config for this Turbine webapp. */
139 private static ServletConfig servletConfig;
140
141 /*** Servlet context for this Turbine webapp. */
142 private static ServletContext servletContext;
143
144 /***
145 * The webapp root where the Turbine application
146 * is running in the servlet container.
147 * This might differ from the application root.
148 */
149 private static String webappRoot;
150
151 /*** Our internal configuration object */
152 private static Configuration configuration = null;
153
154 /*** A reference to the Template Service */
155 private TemplateService templateService = null;
156
157 /*** A reference to the RunData Service */
158 private RunDataService rundataService = null;
159
160 /*** Default Input encoding if the servlet container does not report an encoding */
161 private String inputEncoding = null;
162
163 /*** Logging class from commons.logging */
164 private static Log log = LogFactory.getLog(Turbine.class);
165
166 /***
167 * This init method will load the default resources from a
168 * properties file.
169 *
170 * This method is called by init(ServletConfig config)
171 *
172 * @exception ServletException a servlet exception.
173 */
174 public final void init() throws ServletException
175 {
176 synchronized (this.getClass())
177 {
178 super.init();
179 ServletConfig config = getServletConfig();
180
181 if (!firstInit)
182 {
183 log.info("Double initialization of Turbine was attempted!");
184 return;
185 }
186
187
188 firstInit = false;
189
190 try
191 {
192 ServletContext context = config.getServletContext();
193
194 configure(config, context);
195
196 templateService = TurbineTemplate.getService();
197 rundataService = TurbineRunDataFacade.getService();
198
199 if (rundataService == null)
200 {
201 throw new TurbineException(
202 "No RunData Service configured!");
203 }
204
205 }
206 catch (Exception e)
207 {
208
209 initFailure = e;
210 log.fatal("Turbine: init() failed: ", e);
211 throw new ServletException("Turbine: init() failed", e);
212 }
213 log.info("Turbine: init() Ready to Rumble!");
214 }
215 }
216
217 /***
218 * Read the master configuration file in, configure logging
219 * and start up any early services.
220 *
221 * @param config The Servlet Configuration supplied by the container
222 * @param context The Servlet Context supplied by the container
223 *
224 * @throws Exception A problem occured while reading the configuration or performing early startup
225 */
226
227 private void configure(ServletConfig config, ServletContext context)
228 throws Exception
229 {
230
231
232
233
234 applicationRoot = findInitParameter(context, config,
235 APPLICATION_ROOT_KEY,
236 APPLICATION_ROOT_DEFAULT);
237
238 webappRoot = config.getServletContext().getRealPath("/");
239
240
241
242 if (applicationRoot == null || applicationRoot.equals(WEB_CONTEXT))
243 {
244 applicationRoot = webappRoot;
245
246 }
247
248
249 setApplicationRoot(applicationRoot);
250
251
252
253 createRuntimeDirectories(context, config);
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283 String confFile= findInitParameter(context, config,
284 TurbineConfig.CONFIGURATION_PATH_KEY,
285 null);
286
287 String confPath;
288 String confStyle = "unset";
289
290 if (StringUtils.isNotEmpty(confFile))
291 {
292 confPath = getRealPath(confFile);
293 ConfigurationFactory configurationFactory = new ConfigurationFactory(confPath);
294 configurationFactory.setBasePath(getApplicationRoot());
295 configuration = configurationFactory.getConfiguration();
296 confStyle = "XML";
297 }
298 else
299 {
300 confFile = findInitParameter(context, config,
301 TurbineConfig.PROPERTIES_PATH_KEY,
302 TurbineConfig.PROPERTIES_PATH_DEFAULT);
303
304 confPath = getRealPath(confFile);
305
306
307
308
309 configuration = (Configuration) new PropertiesConfiguration(confPath);
310 confStyle = "Properties";
311 }
312
313
314
315
316
317 String log4jFile = configuration.getString(LOG4J_CONFIG_FILE,
318 LOG4J_CONFIG_FILE_DEFAULT);
319
320 if (StringUtils.isNotEmpty(log4jFile) &&
321 !log4jFile.equalsIgnoreCase("none"))
322 {
323 log4jFile = getRealPath(log4jFile);
324
325
326
327
328
329 Properties p = new Properties();
330 try
331 {
332 p.load(new FileInputStream(log4jFile));
333 p.setProperty(APPLICATION_ROOT_KEY, getApplicationRoot());
334 PropertyConfigurator.configure(p);
335
336 log.info("Configured log4j from " + log4jFile);
337 }
338 catch (FileNotFoundException fnf)
339 {
340 System.err.println("Could not open Log4J configuration file "
341 + log4jFile + ": ");
342 fnf.printStackTrace();
343 }
344 }
345
346
347 log.info("Loaded configuration (" + confStyle + ") from " + confFile + " (" + confPath + ")");
348
349
350 setTurbineServletConfig(config);
351 setTurbineServletContext(context);
352
353 getServiceManager().setApplicationRoot(applicationRoot);
354
355
356
357
358
359
360 configuration.setProperty(APPLICATION_ROOT_KEY, applicationRoot);
361 configuration.setProperty(WEBAPP_ROOT_KEY, webappRoot);
362
363
364
365
366
367 configuration.setProperty(TurbineServices.SERVICE_PREFIX +
368 AvalonComponentService.SERVICE_NAME + ".earlyInit",
369 Boolean.TRUE);
370
371 getServiceManager().setConfiguration(configuration);
372
373
374
375
376
377 getServiceManager().init();
378
379
380 inputEncoding = configuration.getString(
381 TurbineConstants.PARAMETER_ENCODING_KEY,
382 TurbineConstants.PARAMETER_ENCODING_DEFAULT);
383
384 if (log.isDebugEnabled())
385 {
386 log.debug("Input Encoding has been set to " + inputEncoding);
387 }
388 }
389
390 /***
391 * Create any directories that might be needed during
392 * runtime. Right now this includes:
393 *
394 * <ul>
395 *
396 * <li>The directory to write the log files to (relative to the
397 * web application root), or <code>null</code> for the default of
398 * <code>/logs</code>. The directory is specified via the {@link
399 * TurbineConstants#LOGGING_ROOT} parameter.</li>
400 *
401 * </ul>
402 *
403 * @param context Global initialization parameters.
404 * @param config Initialization parameters specific to the Turbine
405 * servlet.
406 */
407 private static void createRuntimeDirectories(ServletContext context,
408 ServletConfig config)
409 {
410 String path = findInitParameter(context, config,
411 LOGGING_ROOT_KEY,
412 LOGGING_ROOT_DEFAULT);
413
414 File logDir = new File(getRealPath(path));
415 if (!logDir.exists())
416 {
417
418 if (!logDir.mkdirs())
419 {
420 System.err.println("Cannot create directory for logs!");
421 }
422 }
423 }
424
425 /***
426 * Finds the specified servlet configuration/initialization
427 * parameter, looking first for a servlet-specific parameter, then
428 * for a global parameter, and using the provided default if not
429 * found.
430 */
431 protected static final String findInitParameter(ServletContext context,
432 ServletConfig config, String name, String defaultValue)
433 {
434 String path = null;
435
436
437 boolean usingNamespace = name.startsWith(CONFIG_NAMESPACE);
438 while (true)
439 {
440 path = config.getInitParameter(name);
441 if (StringUtils.isEmpty(path))
442 {
443 path = context.getInitParameter(name);
444 if (StringUtils.isEmpty(path))
445 {
446
447 if (usingNamespace)
448 {
449 path = defaultValue;
450 }
451 else
452 {
453
454 name = CONFIG_NAMESPACE + '.' + name;
455 usingNamespace = true;
456 continue;
457 }
458 }
459 }
460 break;
461 }
462
463 return path;
464 }
465
466 /***
467 * Initializes the services which need <code>RunData</code> to
468 * initialize themselves (post startup).
469 *
470 * @param data The first <code>GET</code> request.
471 */
472 public final void init(RunData data)
473 {
474 synchronized (Turbine.class)
475 {
476 if (firstDoGet)
477 {
478
479
480
481
482
483 saveServletInfo(data);
484
485
486 firstDoGet = false;
487 log.info("Turbine: first Request successful");
488 }
489 }
490 }
491
492 /***
493 * Return the current configuration with all keys included
494 *
495 * @return a Configuration Object
496 */
497 public static Configuration getConfiguration()
498 {
499 return configuration;
500 }
501
502 /***
503 * Return the server name.
504 *
505 * @return String server name
506 */
507 public static String getServerName()
508 {
509 return getDefaultServerData().getServerName();
510 }
511
512 /***
513 * Return the server scheme.
514 *
515 * @return String server scheme
516 */
517 public static String getServerScheme()
518 {
519 return getDefaultServerData().getServerScheme();
520 }
521
522 /***
523 * Return the server port.
524 *
525 * @return String server port
526 */
527 public static String getServerPort()
528 {
529 return Integer.toString(getDefaultServerData().getServerPort());
530 }
531
532 /***
533 * Get the script name. This is the initial script name.
534 * Actually this is probably not needed any more. I'll
535 * check. jvz.
536 *
537 * @return String initial script name.
538 */
539 public static String getScriptName()
540 {
541 return getDefaultServerData().getScriptName();
542 }
543
544 /***
545 * Return the context path.
546 *
547 * @return String context path
548 */
549 public static String getContextPath()
550 {
551 return getDefaultServerData().getContextPath();
552 }
553
554 /***
555 * Return all the Turbine Servlet information (Server Name, Port,
556 * Scheme in a ServerData structure. This is generated from the
557 * values set when initializing the Turbine and may not be correct
558 * if you're running in a clustered structure. You can provide default
559 * values in your configuration for cases where access is requied before
560 * your application is first accessed by a user. This might be used
561 * if you need a DataURI and have no RunData object handy.
562 *
563 * @return An initialized ServerData object
564 */
565 public static ServerData getDefaultServerData()
566 {
567 if (serverData == null)
568 {
569 String serverName
570 = configuration.getString(DEFAULT_SERVER_NAME_KEY);
571 if (serverName == null)
572 {
573 log.error("ServerData Information requested from Turbine before first request!");
574 }
575 else
576 {
577 log.info("ServerData Information retrieved from configuration.");
578 }
579
580 serverData = new ServerData(serverName,
581 configuration.getInt(DEFAULT_SERVER_PORT_KEY,
582 URIConstants.HTTP_PORT),
583 configuration.getString(DEFAULT_SERVER_SCHEME_KEY,
584 URIConstants.HTTP),
585 configuration.getString(DEFAULT_SCRIPT_NAME_KEY),
586 configuration.getString(DEFAULT_CONTEXT_PATH_KEY));
587 }
588 return serverData;
589 }
590
591 /***
592 * Set the servlet config for this turbine webapp.
593 *
594 * @param config New servlet config
595 */
596 public static void setTurbineServletConfig(ServletConfig config)
597 {
598 servletConfig = config;
599 }
600
601 /***
602 * Get the servlet config for this turbine webapp.
603 *
604 * @return ServletConfig
605 */
606 public static ServletConfig getTurbineServletConfig()
607 {
608 return servletConfig;
609 }
610
611 /***
612 * Set the servlet context for this turbine webapp.
613 *
614 * @param context New servlet context.
615 */
616 public static void setTurbineServletContext(ServletContext context)
617 {
618 servletContext = context;
619 }
620
621 /***
622 * Get the servlet context for this turbine webapp.
623 *
624 * @return ServletContext
625 */
626 public static ServletContext getTurbineServletContext()
627 {
628 return servletContext;
629 }
630
631 /***
632 * The <code>Servlet</code> destroy method. Invokes
633 * <code>ServiceBroker</code> tear down method.
634 */
635 public final void destroy()
636 {
637
638 getServiceManager().shutdownServices();
639 System.gc();
640
641 firstInit = true;
642 firstDoGet = true;
643 log.info("Turbine: Done shutting down!");
644 }
645
646 /***
647 * The primary method invoked when the Turbine servlet is executed.
648 *
649 * @param req Servlet request.
650 * @param res Servlet response.
651 * @exception IOException a servlet exception.
652 * @exception ServletException a servlet exception.
653 */
654 public final void doGet(HttpServletRequest req, HttpServletResponse res)
655 throws IOException, ServletException
656 {
657
658 boolean requestRedirected = false;
659
660
661 RunData data = null;
662 try
663 {
664
665 if (initFailure != null)
666 {
667 throw initFailure;
668 }
669
670
671
672
673 if (req.getCharacterEncoding() == null)
674 {
675 if (log.isDebugEnabled())
676 {
677 log.debug("Changing Input Encoding to " + inputEncoding);
678 }
679
680 try
681 {
682 req.setCharacterEncoding(inputEncoding);
683 }
684 catch (UnsupportedEncodingException uee)
685 {
686 log.warn("Could not change request encoding to " + inputEncoding, uee);
687 }
688 }
689
690
691
692 data = rundataService.getRunData(req, res, getServletConfig());
693
694
695
696
697 if (firstDoGet)
698 {
699 init(data);
700 }
701
702
703
704 if (data.getSession().isNew())
705 {
706 int timeout = configuration.getInt(SESSION_TIMEOUT_KEY,
707 SESSION_TIMEOUT_DEFAULT);
708
709 if (timeout != SESSION_TIMEOUT_DEFAULT)
710 {
711 data.getSession().setMaxInactiveInterval(timeout);
712 }
713 }
714
715
716 data.setScreen(data.getParameters().getString(URIConstants.CGI_SCREEN_PARAM));
717 data.setAction(data.getParameters().getString(URIConstants.CGI_ACTION_PARAM));
718
719
720
721
722
723
724 if (data.hasAction())
725 {
726 String action = data.getAction();
727 log.debug("action = " + action);
728
729 if (action.equalsIgnoreCase(
730 configuration.getString(ACTION_LOGIN_KEY,
731 ACTION_LOGIN_DEFAULT)))
732 {
733 loginAction(data);
734 }
735 else if (action.equalsIgnoreCase(
736 configuration.getString(ACTION_LOGOUT_KEY,
737 ACTION_LOGOUT_DEFAULT)))
738 {
739 logoutAction(data);
740 }
741 }
742
743
744
745
746
747
748
749
750
751 ActionLoader.getInstance().exec(
752 data, configuration.getString(ACTION_SESSION_VALIDATOR_KEY,
753 ACTION_SESSION_VALIDATOR_DEFAULT));
754
755
756
757
758
759
760 ActionLoader.getInstance().exec(
761 data, configuration.getString(ACTION_ACCESS_CONTROLLER_KEY,
762 ACTION_ACCESS_CONTROLLER_DEFAULT));
763
764
765
766
767
768
769
770
771
772
773
774
775
776 String defaultPage = (templateService == null)
777 ? null :templateService.getDefaultPageName(data);
778
779 if (defaultPage == null)
780 {
781
782
783
784
785
786
787
788
789
790
791
792 defaultPage = configuration.getString(PAGE_DEFAULT_KEY,
793 PAGE_DEFAULT_DEFAULT);
794 }
795
796 PageLoader.getInstance().exec(data, defaultPage);
797
798
799
800 if (data.getACL() == null)
801 {
802 try
803 {
804 data.getSession().removeAttribute(
805 AccessControlList.SESSION_KEY);
806 }
807 catch (IllegalStateException ignored)
808 {
809 }
810 }
811
812
813 requestRedirected = ((data.getRedirectURI() != null)
814 && (data.getRedirectURI().length() > 0));
815 if (requestRedirected)
816 {
817 if (data.getResponse().isCommitted())
818 {
819 requestRedirected = false;
820 log.warn("redirect requested, response already committed: " +
821 data.getRedirectURI());
822 }
823 else
824 {
825 data.getResponse().sendRedirect(data.getRedirectURI());
826 }
827 }
828
829 if (!requestRedirected)
830 {
831 try
832 {
833 if (data.isPageSet() == false && data.isOutSet() == false)
834 {
835 throw new Exception("Nothing to output");
836 }
837
838
839
840
841
842 if (data.isPageSet() && data.isOutSet() == false)
843 {
844
845 data.getResponse().setLocale(data.getLocale());
846 data.getResponse().setContentType(
847 data.getContentType());
848
849
850 data.getResponse().setStatus(data.getStatusCode());
851
852 data.getPage().output(data.getOut());
853 }
854 }
855 catch (Exception e)
856 {
857
858
859
860
861 log.debug("Output stream closed? ", e);
862 }
863 }
864 }
865 catch (Exception e)
866 {
867 handleException(data, res, e);
868 }
869 catch (Throwable t)
870 {
871 handleException(data, res, t);
872 }
873 finally
874 {
875
876 rundataService.putRunData(data);
877 }
878 }
879
880 /***
881 * In this application doGet and doPost are the same thing.
882 *
883 * @param req Servlet request.
884 * @param res Servlet response.
885 * @exception IOException a servlet exception.
886 * @exception ServletException a servlet exception.
887 */
888 public final void doPost(HttpServletRequest req, HttpServletResponse res)
889 throws IOException, ServletException
890 {
891 doGet(req, res);
892 }
893
894 /***
895 * This method is executed if the configured Login action should be
896 * executed by Turbine.
897 * <p>
898 * This Action must be performed before the Session validation or we
899 * get sent in an endless loop back to the Login screen before
900 * the action can be performed
901 *
902 * @param data a RunData object
903 *
904 * @throws Exception A problem while logging in occured.
905 */
906 private void loginAction(RunData data)
907 throws Exception
908 {
909 ActionLoader.getInstance().exec(data, data.getAction());
910 cleanupTemplateContext(data);
911 data.setAction(null);
912 }
913
914 /***
915 * This method is executed if the configured Logout action should be
916 * executed by Turbine.
917 * <p>
918 * This Action must be performed before the Session validation for the
919 * session validator to send us back to the Login screen.
920 * <p>
921 * The existing session is invalidated before the logout action is
922 * executed.
923 *
924 * @param data a RunData object
925 *
926 * @throws Exception A problem while logging out occured.
927 */
928 private void logoutAction(RunData data)
929 throws Exception
930 {
931 ActionLoader.getInstance().exec(data, data.getAction());
932 cleanupTemplateContext(data);
933 data.setAction(null);
934 data.getSession().invalidate();
935 }
936
937 /***
938 * cleans the Velocity Context if available.
939 *
940 * @param data A RunData Object
941 *
942 * @throws Exception A problem while cleaning out the Template Context occured.
943 */
944 private void cleanupTemplateContext(RunData data)
945 throws Exception
946 {
947
948
949
950 TemplateInfo ti = data.getTemplateInfo();
951 if (ti != null)
952 {
953 ti.removeTemp(VelocityService.CONTEXT);
954 }
955 }
956
957 /***
958 * Return the servlet info.
959 *
960 * @return a string with the servlet information.
961 */
962 public final String getServletInfo()
963 {
964 return "Turbine Servlet";
965 }
966
967 /***
968 * This method is about making sure that we catch and display
969 * errors to the screen in one fashion or another. What happens is
970 * that it will attempt to show the error using your user defined
971 * Error Screen. If that fails, then it will resort to just
972 * displaying the error and logging it all over the place
973 * including the servlet engine log file, the Turbine log file and
974 * on the screen.
975 *
976 * @param data A Turbine RunData object.
977 * @param res Servlet response.
978 * @param t The exception to report.
979 */
980 private void handleException(RunData data, HttpServletResponse res,
981 Throwable t)
982 {
983
984 log.error("Turbine.handleException: ", t);
985
986 String mimeType = "text/plain";
987 try
988 {
989
990
991 data.setStackTrace(ExceptionUtils.getStackTrace(t), t);
992
993
994 data.setScreen(configuration.getString(SCREEN_ERROR_KEY,
995 SCREEN_ERROR_DEFAULT));
996
997
998 if (data.getTemplateInfo() != null)
999 {
1000 data.getTemplateInfo()
1001 .setScreenTemplate(configuration.getString(
1002 TEMPLATE_ERROR_KEY, TEMPLATE_ERROR_VM));
1003 }
1004
1005
1006 data.setAction("");
1007
1008 PageLoader.getInstance().exec(data,
1009 configuration.getString(PAGE_DEFAULT_KEY,
1010 PAGE_DEFAULT_DEFAULT));
1011
1012 data.getResponse().setContentType(data.getContentType());
1013 data.getResponse().setStatus(data.getStatusCode());
1014 if (data.isPageSet())
1015 {
1016 data.getOut().print(data.getPage().toString());
1017 }
1018 }
1019
1020
1021 catch (java.lang.NoSuchFieldError e)
1022 {
1023 try
1024 {
1025 data.getResponse().setContentType(mimeType);
1026 data.getResponse().setStatus(200);
1027 }
1028 catch (Exception ignored)
1029 {
1030
1031 }
1032
1033 try
1034 {
1035 data.getOut().print("java.lang.NoSuchFieldError: "
1036 + "Please recompile all of your source code.");
1037 }
1038 catch (IOException ignored)
1039 {
1040 }
1041
1042 log.error(data.getStackTrace(), e);
1043 }
1044
1045 catch (Throwable reallyScrewedNow)
1046 {
1047 StringBuffer msg = new StringBuffer();
1048 msg.append("Horrible Exception: ");
1049 if (data != null)
1050 {
1051 msg.append(data.getStackTrace());
1052 }
1053 else
1054 {
1055 msg.append(t);
1056 }
1057 try
1058 {
1059 res.setContentType(mimeType);
1060 res.setStatus(200);
1061 res.getWriter().print(msg.toString());
1062 }
1063 catch (Exception ignored)
1064 {
1065 }
1066
1067 log.error(reallyScrewedNow.getMessage(), reallyScrewedNow);
1068 }
1069 }
1070
1071 /***
1072 * Save some information about this servlet so that
1073 * it can be utilized by object instances that do not
1074 * have direct access to RunData.
1075 *
1076 * @param data
1077 */
1078 public static synchronized void saveServletInfo(RunData data)
1079 {
1080
1081
1082
1083
1084
1085
1086
1087 serverData = (ServerData) data.getServerData().clone();
1088 }
1089
1090 /***
1091 * Set the application root for the webapp.
1092 *
1093 * @param val New app root.
1094 */
1095 public static void setApplicationRoot(String val)
1096 {
1097 applicationRoot = val;
1098 }
1099
1100 /***
1101 * Get the application root for this Turbine webapp. This
1102 * concept was started in 3.0 and will allow an app to be
1103 * developed from a standard CVS layout. With a simple
1104 * switch the app will work fully within the servlet
1105 * container for deployment.
1106 *
1107 * @return String applicationRoot
1108 */
1109 public static String getApplicationRoot()
1110 {
1111 return applicationRoot;
1112 }
1113
1114 /***
1115 * Used to get the real path of configuration and resource
1116 * information. This can be used by an app being
1117 * developed in a standard CVS layout.
1118 *
1119 * @param path path translated to the application root
1120 * @return the real path
1121 */
1122 public static String getRealPath(String path)
1123 {
1124 if (path.startsWith("/"))
1125 {
1126 path = path.substring(1);
1127 }
1128
1129 return new File(getApplicationRoot(), path).getAbsolutePath();
1130 }
1131
1132 /***
1133 * Return an instance of the currently configured Service Manager
1134 *
1135 * @return A service Manager instance
1136 */
1137 private ServiceManager getServiceManager()
1138 {
1139 return TurbineServices.getInstance();
1140 }
1141 }