1.1 restoration
[mir.git] / source / Mir.java
1 /*
2  * Copyright (C) 2001, 2002 The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
6  * Mir is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Mir is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Mir; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with  any library licensed under the Apache Software License,
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23  * (or with modified versions of the above that use the same license as the above),
24  * and distribute linked combinations including the two.  You must obey the
25  * GNU General Public License in all respects for all of the code used other than
26  * the above mentioned libraries.  If you modify this file, you may extend this
27  * exception to your version of the file, but you are not obligated to do so.
28  * If you do not wish to do so, delete this exception statement from your version.
29  */
30
31 import mir.bundle.Bundle;
32 import mir.config.MirPropertiesConfiguration;
33 import mir.servlet.*;
34 import mir.util.ExceptionFunctions;
35 import mir.util.StringRoutines;
36 import mir.log.LoggerWrapper;
37 import mircoders.entity.EntityUsers;
38 import mircoders.global.MirGlobal;
39 import mircoders.module.ModuleUsers;
40 import mircoders.servlet.ServletHelper;
41
42 import javax.servlet.ServletConfig;
43 import javax.servlet.ServletException;
44 import javax.servlet.UnavailableException;
45 import javax.servlet.http.*;
46 import java.io.IOException;
47 import java.io.PrintWriter;
48 import java.lang.reflect.Method;
49 import java.util.*;
50
51 import multex.Failure;
52
53 /**
54  * Mir.java - main servlet, that dispatches to servletmodules
55  */
56 public class Mir extends AbstractServlet {
57   private static ModuleUsers usersModule = null;
58   private final static Map servletModuleInstanceHash = new HashMap();
59   private static Locale fallbackLocale = null;
60
61   private static List loginLanguages = null;
62
63   private List getLoginLanguages() throws Failure {
64     synchronized (Mir.class) {
65       try {
66         if (loginLanguages == null) {
67           List languages =
68             StringRoutines.splitString(MirGlobal.config().getString("Mir.Login.Languages", "en"), ";");
69
70           loginLanguages = new ArrayList();
71
72           Iterator i = languages.iterator();
73
74           while (i.hasNext()) {
75             String code = (String) i.next();
76
77             Bundle bundle =
78                 MirGlobal.getBundleFactory().getBundle("etc/bundles/adminlocal", new String[] { code });
79             Bundle defaultBundle =
80                 MirGlobal.getBundleFactory().getBundle("bundles/admin", new String[] { code });
81
82             String name = bundle.getValue("languagename", Collections.EMPTY_LIST);
83
84             if (name == null) {
85               name = defaultBundle.getValue("languagename", Collections.EMPTY_LIST);
86             }
87
88             if (name == null) {
89               name = code;
90             }
91
92             Map record = new HashMap();
93             record.put("name", name);
94             record.put("code", code);
95             loginLanguages.add(record);
96           }
97         }
98
99         return loginLanguages;
100       }
101       catch (Throwable t) {
102         throw new Failure("Error while retrieving the available login languages", t);
103       }
104     }
105   }
106
107   public void init(ServletConfig config) throws ServletException {
108     super.init(config);
109
110     usersModule = new ModuleUsers();
111   }
112
113   protected String getDefaultLanguage(HttpServletRequest aRequest) {
114     String defaultlanguage =
115       MirGlobal.config().getString("Mir.Login.DefaultLanguage", "");
116
117     if (defaultlanguage.length() == 0) {
118       Locale locale = aRequest.getLocale();
119       defaultlanguage = locale.getLanguage();
120     }
121
122     return defaultlanguage;
123   }
124
125   protected synchronized Locale getFallbackLocale() throws ServletException {
126     try {
127       if (fallbackLocale == null) {
128         fallbackLocale = new Locale(MirPropertiesConfiguration.instance().getString("Mir.Admin.FallbackLanguage", "en"), "");
129       }
130     }
131     catch (Throwable t) {
132       throw new ServletException(t.getMessage());
133     }
134
135     return fallbackLocale;
136   }
137
138   public EntityUsers checkCredentials(HttpServletRequest aRequest) throws ServletException {
139     try {
140       EntityUsers user = ServletHelper.getUser(aRequest);
141
142       String username = aRequest.getParameter("login");
143       String password = aRequest.getParameter("password");
144
145       if (username != null && password != null) {
146         user = usersModule.getUserForLogin(username, password);
147
148         if (user!=null) {
149           ServletHelper.setUser(aRequest, user);
150           usersModule.recordLogin(user);
151           aRequest.getSession().setAttribute("sessiontracker", new SessionTracker(username, user.getId()));
152         }
153       }
154
155       return user;
156     }
157     catch (Throwable t) {
158       t.printStackTrace();
159
160       throw new ServletException(t.toString());
161     }
162   }
163
164   public void process(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletException, IOException, UnavailableException {
165     try {
166       long startTime = System.currentTimeMillis();
167       long sessionConnectTime = 0;
168
169       HttpSession session = aRequest.getSession(true);
170       setNoCaching(aResponse);
171       aResponse.setContentType("text/html; charset=" +
172                                configuration.
173                                getString("Mir.DefaultHTMLCharset", "UTF-8"));
174
175       EntityUsers userEntity = checkCredentials(aRequest);
176
177       if (userEntity == null) {
178         String queryString = aRequest.getQueryString();
179
180         if ( (queryString != null) && (queryString.length() != 0) && session.getAttribute("login.target") == null &&
181              (aRequest.getParameter("module")==null ||
182               (!aRequest.getParameter("module").equals("login") && !aRequest.getParameter("module").equals("logout")))) {
183           session.setAttribute("login.target", queryString);
184         }
185
186         _sendLoginPage(aResponse, aRequest);
187       }
188       else {
189         String moduleName = aRequest.getParameter("module");
190         checkLanguage(session, aRequest);
191
192         if ( ( (moduleName == null) || moduleName.equals(""))) {
193           moduleName="Admin";
194         }
195
196
197         if (moduleName.equals("login")) {
198           String target = (String) session.getAttribute("login.target");
199
200           if (target != null) {
201             ServletHelper.redirect(aResponse, target);
202           }
203           else {
204             ServletHelper.redirect(aResponse, "");
205           }
206         }
207         else if (moduleName.equals("logout")) {
208           logger.info(userEntity.getFieldValue("login") + " has logged out");
209           session.invalidate();
210           _sendLoginPage(aResponse, aRequest);
211           return;
212         }
213         else {
214           try {
215             ServletModule servletModule = getServletModuleForName(moduleName);
216             ServletModuleDispatch.dispatch(servletModule, aRequest, aResponse);
217
218             sessionConnectTime = System.currentTimeMillis() - startTime;
219             logger.info("EXECTIME (" + moduleName + "): " + sessionConnectTime + " ms");
220           }
221           catch (Throwable e) {
222             Throwable cause = ExceptionFunctions.traceCauseException(e);
223
224             if (cause instanceof ServletModuleUserExc)
225               handleUserError(aRequest, aResponse, (ServletModuleUserExc) cause);
226             else
227               handleError(aRequest, aResponse, cause);
228           }
229
230           if (aRequest.getParameter("killsession")!=null)
231             aRequest.getSession().invalidate();
232         }
233       }
234     }
235     catch (Throwable t) {
236       t.printStackTrace(logger.asPrintWriter(LoggerWrapper.DEBUG_MESSAGE));
237
238       throw new ServletException(t.toString());
239     }
240   }
241
242   /**
243    * caching routine to get a module for a module name
244    *
245    * @param moduleName the module name
246    * @return the requested module
247    * @throws ServletModuleExc
248    */
249
250   private static ServletModule getServletModuleForName(String moduleName) throws ServletModuleExc {
251     // Instance in Map ?
252     if (!servletModuleInstanceHash.containsKey(moduleName)) {
253       // was not found in hash...
254       try {
255         Class theServletModuleClass = null;
256
257         try {
258           // first we try to get ServletModule from stern.che3.servlet
259           theServletModuleClass =
260             Class.forName("mircoders.servlet.ServletModule" + moduleName);
261         }
262         catch (ClassNotFoundException e) {
263           // on failure, we try to get it from lib-layer
264           theServletModuleClass =
265             Class.forName("mir.servlet.ServletModule" + moduleName);
266         }
267
268         Method m = theServletModuleClass.getMethod("getInstance", null);
269         ServletModule smod = (ServletModule) m.invoke(null, null);
270
271         // we put it into map for further reference
272         servletModuleInstanceHash.put(moduleName, smod);
273
274         return smod;
275       }
276       catch (Exception e) {
277         throw new ServletModuleExc("*** error resolving classname for " + moduleName + " -- " + e.getMessage());
278       }
279     }
280     else {
281       return (ServletModule) servletModuleInstanceHash.get(moduleName);
282     }
283   }
284
285   private void handleUserError(HttpServletRequest aRequest, HttpServletResponse aResponse, ServletModuleUserExc anException) {
286     try {
287       logger.info("user error: " + anException.getMessage());
288
289       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] {getLocale(aRequest), getFallbackLocale()});
290
291       Bundle bundle =
292           MirGlobal.getBundleFactory().getBundle("etc/bundles/adminlocal", new
293               String[] { getLocale(aRequest).getLanguage() });
294       Bundle defaultBundle =
295           MirGlobal.getBundleFactory().getBundle("bundles/admin", new
296               String[] { getLocale(aRequest).getLanguage() });
297       String message =
298         bundle.getValue(anException.getMessage(), Arrays.asList(anException.getParameters()));
299
300       if (message==null) {
301         message =
302           defaultBundle.getValue(anException.getMessage(), Arrays.asList(anException.getParameters()));
303       }
304
305       responseData.put("errorstring", message);
306       responseData.put("date", new GregorianCalendar().getTime());
307
308       ServletHelper.generateResponse(aResponse.getWriter(), responseData, MirPropertiesConfiguration.instance().getString("Mir.UserErrorTemplate"));
309     }
310     catch (Throwable e) {
311       logger.error("Error handling user error" + e.toString());
312     }
313   }
314
315   private void handleError(HttpServletRequest aRequest, HttpServletResponse aResponse, Throwable anException) {
316     try {
317       logger.error("error: " + anException);
318
319       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] {getLocale(aRequest), getFallbackLocale()});
320
321       responseData.put("errorstring", anException.toString());
322       responseData.put("date", new GregorianCalendar().getTime());
323
324       ServletHelper.generateResponse(aResponse.getWriter(), responseData, MirPropertiesConfiguration.instance().getString("Mir.ErrorTemplate"));
325     }
326     catch (Throwable e) {
327       logger.error("Error handling error: " + e.toString());
328
329       try {
330         Throwable rootException = ExceptionFunctions.traceCauseException(anException);
331
332         PrintWriter writer = aResponse.getWriter();
333         writer.println("<html><head><title>FATAL Error</title><body>");
334         writer.println("<h1>" + rootException.toString()+"</h1>");
335         writer.println("<code>");
336         rootException.printStackTrace(writer);
337         writer.println("</code>");
338         writer.println("</body></html>");
339         writer.close();
340       }
341       catch (Throwable t) {
342
343       }
344     }
345   }
346
347   // Redirect-methods
348   private void _sendLoginPage(HttpServletResponse aResponse, HttpServletRequest aRequest) {
349     String loginTemplate = configuration.getString("Mir.LoginTemplate");
350
351     try {
352       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] {getLocale(aRequest), getFallbackLocale()});
353
354       responseData.put("defaultlanguage", getDefaultLanguage(aRequest));
355       responseData.put("languages", getLoginLanguages());
356
357       ServletHelper.generateResponse(aResponse.getWriter(), responseData, loginTemplate);
358     }
359     catch (Throwable e) {
360       handleError(aRequest, aResponse, e);
361     }
362   }
363
364   public String getServletInfo() {
365     return "Mir " + configuration.getString("Mir.Version");
366   }
367
368   private class SessionTracker implements HttpSessionBindingListener {
369     private String name;
370     private String id;
371
372     public SessionTracker(String aUserName, String anId) {
373       name = aUserName;
374       id = anId;
375     }
376
377     public void valueBound(HttpSessionBindingEvent anEvent) {
378       MirGlobal.registerLogin(name, id);
379     }
380
381     public void valueUnbound(HttpSessionBindingEvent anEvent) {
382       MirGlobal.registerLogout(name, id);
383     }
384   }
385 }