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