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.BufferedReader;
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.FileNotFoundException;
26 import java.io.FileReader;
27 import java.io.IOException;
28 import java.io.Reader;
29 import java.io.UnsupportedEncodingException;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.Map;
33 import java.util.Properties;
34
35 import javax.servlet.ServletConfig;
36 import javax.servlet.ServletContext;
37 import javax.servlet.ServletException;
38 import javax.servlet.http.HttpServlet;
39 import javax.servlet.http.HttpServletRequest;
40 import javax.servlet.http.HttpServletResponse;
41 import javax.xml.parsers.FactoryConfigurationError;
42
43 import org.apache.commons.configuration.Configuration;
44 import org.apache.commons.configuration.DefaultConfigurationBuilder;
45 import org.apache.commons.configuration.PropertiesConfiguration;
46 import org.apache.commons.lang.StringUtils;
47 import org.apache.commons.lang.exception.ExceptionUtils;
48 import org.apache.commons.logging.Log;
49 import org.apache.commons.logging.LogFactory;
50 import org.apache.log4j.PropertyConfigurator;
51 import org.apache.log4j.xml.DOMConfigurator;
52 import org.apache.turbine.modules.PageLoader;
53 import org.apache.turbine.pipeline.Pipeline;
54 import org.apache.turbine.pipeline.PipelineData;
55 import org.apache.turbine.pipeline.TurbinePipeline;
56 import org.apache.turbine.services.Initable;
57 import org.apache.turbine.services.InitializationException;
58 import org.apache.turbine.services.ServiceManager;
59 import org.apache.turbine.services.TurbineServices;
60 import org.apache.turbine.services.rundata.RunDataService;
61 import org.apache.turbine.services.template.TemplateService;
62 import org.apache.turbine.services.template.TurbineTemplate;
63 import org.apache.turbine.util.RunData;
64 import org.apache.turbine.util.ServerData;
65 import org.apache.turbine.util.TurbineConfig;
66 import org.apache.turbine.util.TurbineException;
67 import org.apache.turbine.util.uri.URIConstants;
68
69 import com.thoughtworks.xstream.XStream;
70 import com.thoughtworks.xstream.io.xml.StaxDriver;
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 public class Turbine
110 extends HttpServlet
111 {
112
113 private static final long serialVersionUID = -6317118078613623990L;
114
115
116
117
118
119 public static final String REDIRECTED_PATHINFO_NAME = "redirected";
120
121
122 public static final String BASEDIR_KEY = "basedir";
123
124
125
126
127
128
129 private static boolean firstInit = true;
130
131
132
133
134 private static Pipeline pipeline = null;
135
136
137 private static Throwable initFailure = null;
138
139
140
141
142 private static boolean firstDoGet = true;
143
144
145
146
147
148 private static ServerData serverData = null;
149
150
151 private static String applicationRoot;
152
153
154 private static ServletConfig servletConfig;
155
156
157 private static ServletContext servletContext;
158
159
160
161
162
163
164 private static String webappRoot;
165
166
167 private static Configuration configuration = null;
168
169
170 private String inputEncoding = null;
171
172
173 private static Log log = LogFactory.getLog(Turbine.class);
174
175
176
177
178
179
180
181
182
183 @Override
184 public void init() throws ServletException
185 {
186 synchronized (Turbine.class)
187 {
188 super.init();
189 ServletConfig config = getServletConfig();
190
191 if (!firstInit)
192 {
193 log.info("Double initialization of Turbine was attempted!");
194 return;
195 }
196
197
198 firstInit = false;
199
200 try
201 {
202 ServletContext context = config.getServletContext();
203
204 configure(config, context);
205
206 TemplateService templateService = TurbineTemplate.getService();
207 if (templateService == null)
208 {
209 throw new TurbineException(
210 "No Template Service configured!");
211 }
212
213 if (getRunDataService() == null)
214 {
215 throw new TurbineException(
216 "No RunData Service configured!");
217 }
218
219 }
220 catch (Exception e)
221 {
222
223 initFailure = e;
224 log.fatal("Turbine: init() failed: ", e);
225 throw new ServletException("Turbine: init() failed", e);
226 }
227
228 log.info("Turbine: init() Ready to Rumble!");
229 }
230 }
231
232
233
234
235
236
237
238
239
240
241
242 protected void configure(ServletConfig config, ServletContext context)
243 throws Exception
244 {
245
246
247
248
249
250 applicationRoot = findInitParameter(context, config,
251 TurbineConstants.APPLICATION_ROOT_KEY,
252 TurbineConstants.APPLICATION_ROOT_DEFAULT);
253
254 webappRoot = config.getServletContext().getRealPath("/");
255
256
257
258 if (applicationRoot == null || applicationRoot.equals(TurbineConstants.WEB_CONTEXT))
259 {
260 applicationRoot = webappRoot;
261
262 }
263
264
265 setApplicationRoot(applicationRoot);
266
267
268
269 createRuntimeDirectories(context, config);
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299 String confStyle = "unset";
300 String confPath= null;
301
302 String confFile= findInitParameter(context, config,
303 TurbineConfig.CONFIGURATION_PATH_KEY,
304 null);
305 if (StringUtils.isNotEmpty(confFile))
306 {
307 confStyle = "XML";
308 } else
309 {
310 confFile = findInitParameter(context, config,
311 TurbineConfig.PROPERTIES_PATH_KEY,
312 null);
313 if (StringUtils.isNotEmpty((confFile)) )
314 {
315 confStyle = "Properties";
316 }
317 }
318
319
320 if (confStyle.equals( "unset" ))
321 {
322 confFile = findInitParameter(context, config,
323 TurbineConfig.PROPERTIES_PATH_KEY,
324 TurbineConfig.PROPERTIES_PATH_DEFAULT);
325 confStyle = "Properties";
326 }
327
328 if (!confStyle.equals( "unset" ))
329 {
330 if (confStyle.equals( "XML" )) {
331 if (confFile.startsWith( "/" ))
332 {
333 confFile = confFile.substring( 1 );
334 }
335 DefaultConfigurationBuilder configurationBuilder = new DefaultConfigurationBuilder(confFile);
336 confPath = new File(applicationRoot).toURI().toString();
337 configurationBuilder.setBasePath(confPath);
338 configuration = configurationBuilder.getConfiguration();
339 } else {
340 confPath = getRealPath(confFile);
341
342 configuration = new PropertiesConfiguration(confPath);
343 }
344 }
345
346
347
348 configureLogging();
349
350
351 log.info("Loaded configuration (" + confStyle + ") from " + confFile + " (" + confPath + ") style: "+ configuration.toString());
352
353 setTurbineServletConfig(config);
354 setTurbineServletContext(context);
355
356 getServiceManager().setApplicationRoot(applicationRoot);
357
358
359
360
361
362
363 configuration.setProperty(TurbineConstants.APPLICATION_ROOT_KEY, applicationRoot);
364 configuration.setProperty(TurbineConstants.WEBAPP_ROOT_KEY, webappRoot);
365
366
367 inputEncoding = configuration.getString(
368 TurbineConstants.PARAMETER_ENCODING_KEY,
369 TurbineConstants.PARAMETER_ENCODING_DEFAULT);
370
371 if (log.isDebugEnabled())
372 {
373 log.debug("Input Encoding has been set to " + inputEncoding);
374 }
375
376 getServiceManager().setConfiguration(configuration);
377
378
379
380
381
382 getServiceManager().init();
383
384
385
386
387 String descriptorPath =
388 configuration.getString(
389 "pipeline.default.descriptor",
390 TurbinePipeline.CLASSIC_PIPELINE);
391
392 descriptorPath = getRealPath(descriptorPath);
393
394 log.debug("Using descriptor path: " + descriptorPath);
395 Reader reader = new BufferedReader(new FileReader(descriptorPath));
396 XStream pipelineMapper = new XStream(new StaxDriver());
397 pipeline = (Pipeline) pipelineMapper.fromXML(reader);
398
399 log.debug("Initializing pipeline");
400
401 pipeline.initialize();
402 }
403
404
405
406
407
408
409 protected void configureLogging() throws IOException
410 {
411 String log4jFile = configuration.getString(TurbineConstants.LOG4J_CONFIG_FILE,
412 TurbineConstants.LOG4J_CONFIG_FILE_DEFAULT);
413
414 if (StringUtils.isNotEmpty(log4jFile) &&
415 !log4jFile.equalsIgnoreCase("none"))
416 {
417 log4jFile = getRealPath(log4jFile);
418 boolean success = false;
419
420 if (log4jFile.endsWith(".xml"))
421 {
422
423
424 try
425 {
426 DOMConfigurator.configure(log4jFile);
427 success = true;
428 }
429 catch (FactoryConfigurationError e)
430 {
431 System.err.println("Could not configure Log4J from configuration file "
432 + log4jFile + ": ");
433 e.printStackTrace();
434 }
435 }
436 else
437 {
438
439
440
441
442 Properties p = new Properties();
443 FileInputStream fis = null;
444
445 try
446 {
447 fis = new FileInputStream(log4jFile);
448 p.load(fis);
449 p.setProperty(TurbineConstants.APPLICATION_ROOT_KEY, getApplicationRoot());
450 PropertyConfigurator.configure(p);
451 success = true;
452 }
453 catch (FileNotFoundException fnf)
454 {
455 System.err.println("Could not open Log4J configuration file "
456 + log4jFile + ": ");
457 fnf.printStackTrace();
458 }
459 finally
460 {
461 if (fis != null)
462 {
463 fis.close();
464 }
465 }
466 }
467
468 if (success)
469 {
470
471 log = LogFactory.getLog(this.getClass());
472 log.info("Configured log4j from " + log4jFile);
473 }
474 }
475 }
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493 protected void createRuntimeDirectories(ServletContext context,
494 ServletConfig config)
495 {
496 String path = findInitParameter(context, config,
497 TurbineConstants.LOGGING_ROOT_KEY,
498 TurbineConstants.LOGGING_ROOT_DEFAULT);
499
500 File logDir = new File(getRealPath(path));
501 if (!logDir.exists())
502 {
503
504 if (!logDir.mkdirs())
505 {
506 System.err.println("Cannot create directory for logs!");
507 }
508 }
509 }
510
511
512
513
514
515
516
517 protected String findInitParameter(ServletContext context,
518 ServletConfig config, String name, String defaultValue)
519 {
520 String path = null;
521
522
523 boolean usingNamespace = name.startsWith(TurbineConstants.CONFIG_NAMESPACE);
524 while (true)
525 {
526 path = config.getInitParameter(name);
527 if (StringUtils.isEmpty(path))
528 {
529 path = context.getInitParameter(name);
530 if (StringUtils.isEmpty(path))
531 {
532
533 if (usingNamespace)
534 {
535 path = defaultValue;
536 }
537 else
538 {
539
540 name = TurbineConstants.CONFIG_NAMESPACE + '.' + name;
541 usingNamespace = true;
542 continue;
543 }
544 }
545 }
546 break;
547 }
548
549 return path;
550 }
551
552
553
554
555
556
557
558 public void init(PipelineData data)
559 {
560 synchronized (Turbine.class)
561 {
562 if (firstDoGet)
563 {
564
565
566
567
568
569 saveServletInfo(data);
570
571
572 TurbineServices services = (TurbineServices)TurbineServices.getInstance();
573
574 for (Iterator<String> i = services.getServiceNames(); i.hasNext();)
575 {
576 String serviceName = i.next();
577 Object service = services.getService(serviceName);
578
579 if (service instanceof Initable)
580 {
581 try
582 {
583 ((Initable)service).init(data);
584 }
585 catch (InitializationException e)
586 {
587 log.warn("Could not initialize Initable " + serviceName + " with PipelineData", e);
588 }
589 }
590 }
591
592
593 firstDoGet = false;
594 log.info("Turbine: first Request successful");
595 }
596 }
597 }
598
599
600
601
602
603
604 public static Configuration getConfiguration()
605 {
606 return configuration;
607 }
608
609
610
611
612
613
614 public static String getServerName()
615 {
616 return getDefaultServerData().getServerName();
617 }
618
619
620
621
622
623
624 public static String getServerScheme()
625 {
626 return getDefaultServerData().getServerScheme();
627 }
628
629
630
631
632
633
634 public static String getServerPort()
635 {
636 return Integer.toString(getDefaultServerData().getServerPort());
637 }
638
639
640
641
642
643
644
645
646 public static String getScriptName()
647 {
648 return getDefaultServerData().getScriptName();
649 }
650
651
652
653
654
655
656 public static String getContextPath()
657 {
658 return getDefaultServerData().getContextPath();
659 }
660
661
662
663
664
665
666
667
668
669
670
671
672 public static ServerData getDefaultServerData()
673 {
674 if (serverData == null)
675 {
676 String serverName
677 = configuration.getString(TurbineConstants.DEFAULT_SERVER_NAME_KEY);
678 if (serverName == null)
679 {
680 log.error("ServerData Information requested from Turbine before first request!");
681 }
682 else
683 {
684 log.info("ServerData Information retrieved from configuration.");
685 }
686
687 serverData = new ServerData(serverName,
688 configuration.getInt(TurbineConstants.DEFAULT_SERVER_PORT_KEY,
689 URIConstants.HTTP_PORT),
690 configuration.getString(TurbineConstants.DEFAULT_SERVER_SCHEME_KEY,
691 URIConstants.HTTP),
692 configuration.getString(TurbineConstants.DEFAULT_SCRIPT_NAME_KEY),
693 configuration.getString(TurbineConstants.DEFAULT_CONTEXT_PATH_KEY));
694 }
695 return serverData;
696 }
697
698
699
700
701
702
703 public static void setTurbineServletConfig(ServletConfig config)
704 {
705 servletConfig = config;
706 }
707
708
709
710
711
712
713 public static ServletConfig getTurbineServletConfig()
714 {
715 return servletConfig;
716 }
717
718
719
720
721
722
723 public static void setTurbineServletContext(ServletContext context)
724 {
725 servletContext = context;
726 }
727
728
729
730
731
732
733 public static ServletContext getTurbineServletContext()
734 {
735 return servletContext;
736 }
737
738
739
740
741
742 @Override
743 public void destroy()
744 {
745
746 getServiceManager().shutdownServices();
747
748 firstInit = true;
749 firstDoGet = true;
750 log.info("Turbine: Done shutting down!");
751 }
752
753
754
755
756
757
758
759
760
761 @Override
762 public void doGet(HttpServletRequest req, HttpServletResponse res)
763 throws IOException, ServletException
764 {
765 PipelineData pipelineData = null;
766
767 try
768 {
769
770 if (initFailure != null)
771 {
772 throw initFailure;
773 }
774
775
776
777
778 if (req.getCharacterEncoding() == null)
779 {
780 if (log.isDebugEnabled())
781 {
782 log.debug("Changing Input Encoding to " + inputEncoding);
783 }
784
785 try
786 {
787 req.setCharacterEncoding(inputEncoding);
788 }
789 catch (UnsupportedEncodingException uee)
790 {
791 log.warn("Could not change request encoding to " + inputEncoding, uee);
792 }
793 }
794
795
796
797 pipelineData = getRunDataService().getRunData(req, res, getServletConfig());
798 Map<Class<?>, Object> runDataMap = new HashMap<Class<?>, Object>();
799 runDataMap.put(RunData.class, pipelineData);
800
801 pipelineData.put(RunData.class, runDataMap);
802
803
804
805
806 if (firstDoGet)
807 {
808 init(pipelineData);
809 }
810
811
812
813
814 pipeline.invoke(pipelineData);
815
816 }
817 catch (Exception e)
818 {
819 handleException(pipelineData, res, e);
820 }
821 catch (Throwable t)
822 {
823 handleException(pipelineData, res, t);
824 }
825 finally
826 {
827
828 getRunDataService().putRunData((RunData)pipelineData);
829 }
830 }
831
832
833
834
835
836
837
838
839
840 @Override
841 public void doPost(HttpServletRequest req, HttpServletResponse res)
842 throws IOException, ServletException
843 {
844 doGet(req, res);
845 }
846
847
848
849
850
851
852 @Override
853 public String getServletInfo()
854 {
855 return "Turbine Servlet";
856 }
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871 protected void handleException(PipelineData pipelineData, HttpServletResponse res,
872 Throwable t)
873 {
874 RunData data = getRunData(pipelineData);
875
876 log.error("Turbine.handleException: ", t);
877
878 String mimeType = "text/plain";
879 try
880 {
881
882
883 data.setStackTrace(ExceptionUtils.getStackTrace(t), t);
884
885
886 data.setScreen(configuration.getString(
887 TurbineConstants.SCREEN_ERROR_KEY,
888 TurbineConstants.SCREEN_ERROR_DEFAULT));
889
890
891 if (data.getTemplateInfo() != null)
892 {
893 data.getTemplateInfo()
894 .setScreenTemplate(configuration.getString(
895 TurbineConstants.TEMPLATE_ERROR_KEY,
896 TurbineConstants.TEMPLATE_ERROR_VM));
897 }
898
899
900 data.setAction("");
901
902 PageLoader.getInstance().exec(pipelineData,
903 configuration.getString(TurbineConstants.PAGE_DEFAULT_KEY,
904 TurbineConstants.PAGE_DEFAULT_DEFAULT));
905
906 data.getResponse().setContentType(data.getContentType());
907 data.getResponse().setStatus(data.getStatusCode());
908 }
909
910
911 catch (java.lang.NoSuchFieldError e)
912 {
913 try
914 {
915 data.getResponse().setContentType(mimeType);
916 data.getResponse().setStatus(200);
917 }
918 catch (Exception ignored)
919 {
920
921 }
922
923 try
924 {
925 data.getResponse().getWriter().print("java.lang.NoSuchFieldError: "
926 + "Please recompile all of your source code.");
927 }
928 catch (IOException ignored)
929 {
930
931 }
932
933 log.error(data.getStackTrace(), e);
934 }
935
936 catch (Throwable reallyScrewedNow)
937 {
938 StringBuilder msg = new StringBuilder();
939 msg.append("Horrible Exception: ");
940 if (data != null)
941 {
942 msg.append(data.getStackTrace());
943 }
944 else
945 {
946 msg.append(t);
947 }
948 try
949 {
950 res.setContentType(mimeType);
951 res.setStatus(200);
952 res.getWriter().print(msg.toString());
953 }
954 catch (Exception ignored)
955 {
956
957 }
958
959 log.error(reallyScrewedNow.getMessage(), reallyScrewedNow);
960 }
961 }
962
963
964
965
966
967
968
969
970 public static synchronized void saveServletInfo(PipelineData data)
971 {
972
973
974
975
976
977
978
979 ServerData requestServerData = data.get(Turbine.class, ServerData.class);
980 serverData = (ServerData) requestServerData.clone();
981 }
982
983
984
985
986
987
988 public static void setApplicationRoot(String val)
989 {
990 applicationRoot = val;
991 }
992
993
994
995
996
997
998
999
1000
1001
1002 public static String getApplicationRoot()
1003 {
1004 return applicationRoot;
1005 }
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015 public static String getRealPath(String path)
1016 {
1017 if (path.startsWith("/"))
1018 {
1019 return new File(getApplicationRoot(), path.substring(1)).getAbsolutePath();
1020 }
1021
1022 return new File(getApplicationRoot(), path).getAbsolutePath();
1023 }
1024
1025
1026
1027
1028
1029
1030 private ServiceManager getServiceManager()
1031 {
1032 return TurbineServices.getInstance();
1033 }
1034
1035
1036
1037
1038
1039
1040
1041 private RunData getRunData(PipelineData pipelineData)
1042 {
1043 RunData data = null;
1044 data = (RunData)pipelineData;
1045 return data;
1046 }
1047
1048
1049
1050
1051
1052
1053
1054 public String getDefaultInputEncoding()
1055 {
1056 return inputEncoding;
1057 }
1058
1059
1060
1061
1062
1063 private RunDataService getRunDataService()
1064 {
1065 return (RunDataService) TurbineServices
1066 .getInstance().getService(RunDataService.SERVICE_NAME);
1067 }
1068 }