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