70430462b3c2008f18c708c1c3bb23f77d73ccac
[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 java.io.IOException;
32 import java.lang.reflect.Method;
33 import java.util.GregorianCalendar;
34 import java.util.HashMap;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Locale;
38 import java.util.Map;
39 import java.util.Vector;
40
41 import javax.servlet.ServletConfig;
42 import javax.servlet.ServletException;
43 import javax.servlet.UnavailableException;
44 import javax.servlet.http.HttpServletRequest;
45 import javax.servlet.http.HttpServletResponse;
46 import javax.servlet.http.HttpSession;
47 import javax.servlet.http.HttpSessionBindingEvent;
48 import javax.servlet.http.HttpSessionBindingListener;
49
50 import mir.config.MirPropertiesConfiguration;
51 import mir.servlet.AbstractServlet;
52 import mir.servlet.ServletModule;
53 import mir.servlet.ServletModuleDispatch;
54 import mir.servlet.ServletModuleExc;
55 import mir.servlet.ServletModuleUserExc;
56 import mir.util.ExceptionFunctions;
57 import mir.util.StringRoutines;
58 import mircoders.entity.EntityUsers;
59 import mircoders.global.MirGlobal;
60 import mircoders.module.ModuleMessage;
61 import mircoders.module.ModuleUsers;
62 import mircoders.servlet.ServletHelper;
63 import mircoders.storage.DatabaseUsers;
64
65 import org.apache.struts.util.MessageResources;
66
67
68
69
70 /**
71  * Mir.java - main servlet, that dispatches to servletmodules
72  *
73  * @author $Author: rk $
74  * @version $Id: Mir.java,v 1.49.2.8 2003/10/23 14:55:26 rk Exp $
75  *
76  */
77 public class Mir extends AbstractServlet {
78   private static ModuleUsers usersModule = null;
79   private static ModuleMessage messageModule = null;
80   private final static Map servletModuleInstanceHash = new HashMap();
81   private static Locale fallbackLocale = null;
82
83   private static List loginLanguages = null;
84
85   protected List getLoginLanguages() throws ServletException {
86     synchronized (Mir.class) {
87       try {
88         if (loginLanguages == null) {
89           MessageResources messageResources =
90             MessageResources.getMessageResources("bundles.adminlocal");
91           MessageResources messageResources2 =
92             MessageResources.getMessageResources("bundles.admin");
93
94           List languages =
95             StringRoutines.splitString(MirGlobal.config().getString("Mir.Login.Languages", "en"), ";");
96
97           loginLanguages = new Vector();
98
99           Iterator i = languages.iterator();
100
101           while (i.hasNext()) {
102             String code = (String) i.next();
103             Locale locale = new Locale(code, "");
104             String name = messageResources.getMessage(locale, "languagename");
105
106             if (name == null) {
107               name = messageResources2.getMessage(locale, "languagename");
108             }
109
110             if (name == null) {
111               name = code;
112             }
113
114             Map record = new HashMap();
115             record.put("name", name);
116             record.put("code", code);
117             loginLanguages.add(record);
118           }
119         }
120
121         return loginLanguages;
122       }
123       catch (Throwable t) {
124         throw new ServletException(t.getMessage());
125       }
126     }
127   }
128
129   public void init(ServletConfig config) throws ServletException {
130     super.init(config);
131
132     usersModule = new ModuleUsers(DatabaseUsers.getInstance());
133   }
134
135   protected String getDefaultLanguage(HttpServletRequest aRequest) {
136     String defaultlanguage =
137       MirGlobal.config().getString("Mir.Login.DefaultLanguage", "");
138
139     if (defaultlanguage.length() == 0) {
140       Locale locale = aRequest.getLocale();
141       defaultlanguage = locale.getLanguage();
142     }
143
144     return defaultlanguage;
145   }
146
147   protected synchronized Locale getFallbackLocale() throws ServletException {
148     try {
149       if (fallbackLocale == null) {
150         fallbackLocale = new Locale(MirPropertiesConfiguration.instance().getString("Mir.Admin.FallbackLanguage", "en"), "");
151       }
152     }
153     catch (Throwable t) {
154       throw new ServletException(t.getMessage());
155     }
156
157     return fallbackLocale;
158   }
159
160   public EntityUsers checkCredentials(HttpServletRequest aRequest) throws ServletException {
161     try {
162       EntityUsers user = ServletHelper.getUser(aRequest);
163
164       String username = aRequest.getParameter("login");
165       String password = aRequest.getParameter("password");
166
167       if (username != null && password != null) {
168         user = usersModule.getUserForLogin(username, password);
169
170         if (user!=null) {
171           ServletHelper.setUser(aRequest, user);
172           aRequest.getSession().setAttribute("sessiontracker", new SessionTracker(username));
173         }
174       }
175
176       return user;
177     }
178     catch (Throwable t) {
179       t.printStackTrace();
180
181       throw new ServletException(t.toString());
182     }
183   }
184
185   public void process(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletException, IOException, UnavailableException {
186     try {
187       long startTime = System.currentTimeMillis();
188       long sessionConnectTime = 0;
189
190       HttpSession session = aRequest.getSession(true);
191       setNoCaching(aResponse);
192       Locale locale = new Locale(getDefaultLanguage(aRequest), "");
193       aResponse.setContentType("text/html; charset=" +
194                                configuration.
195                                getString("Mir.DefaultHTMLCharset", "UTF-8"));
196
197       EntityUsers userEntity = checkCredentials(aRequest);
198
199       if (userEntity == null) {
200         String queryString = aRequest.getQueryString();
201
202         if ( (queryString != null) && (queryString.length() != 0) && session.getAttribute("login.target") == null &&
203              (aRequest.getParameter("module")==null ||
204               (!aRequest.getParameter("module").equals("login") && !aRequest.getParameter("module").equals("logout")))) {
205           session.setAttribute("login.target", queryString);
206         }
207
208         _sendLoginPage(aResponse, aRequest);
209       }
210       else {
211         String moduleName = aRequest.getParameter("module");
212         checkLanguage(session, aRequest);
213
214         if ( ( (moduleName == null) || moduleName.equals(""))) {
215           moduleName="Admin";
216         }
217
218
219         if (moduleName.equals("login")) {
220           String target = (String) session.getAttribute("login.target");
221
222           if (target != null) {
223             ServletHelper.redirect(aResponse, target);
224           }
225           else {
226             ServletHelper.redirect(aResponse, "");
227           }
228         }
229         else if (moduleName.equals("logout")) {
230           logger.info(userEntity.getValue("login") + " has logged out");
231           session.invalidate();
232           _sendLoginPage(aResponse, aRequest);
233           return;
234         }
235         else {
236           try {
237             ServletModule servletModule = getServletModuleForName(moduleName);
238             ServletModuleDispatch.dispatch(servletModule, aRequest, aResponse);
239
240             sessionConnectTime = System.currentTimeMillis() - startTime;
241             logger.info("EXECTIME (" + moduleName + "): " + sessionConnectTime + " ms");
242           }
243           catch (Throwable e) {
244             Throwable cause = ExceptionFunctions.traceCauseException(e);
245
246             if (cause instanceof ServletModuleUserExc)
247               handleUserError(aRequest, aResponse, (ServletModuleUserExc) cause);
248             else
249               handleError(aRequest, aResponse, cause);
250           }
251
252           if (aRequest.getParameter("killsession")!=null)
253             aRequest.getSession().invalidate();
254         }
255       }
256     }
257     catch (Throwable t) {
258       t.printStackTrace();
259
260       throw new ServletException(t.toString());
261     }
262   }
263
264   /**
265    * caching routine to get a module for a module name
266    *
267    * @param moduleName the module name
268    * @return the requested module
269    * @throws ServletModuleExc
270    */
271
272   private static ServletModule getServletModuleForName(String moduleName) throws ServletModuleExc {
273     // Instance in Map ?
274     if (!servletModuleInstanceHash.containsKey(moduleName)) {
275       // was not found in hash...
276       try {
277         Class theServletModuleClass = null;
278
279         try {
280           // first we try to get ServletModule from stern.che3.servlet
281           theServletModuleClass =
282             Class.forName("mircoders.servlet.ServletModule" + moduleName);
283         }
284         catch (ClassNotFoundException e) {
285           // on failure, we try to get it from lib-layer
286           theServletModuleClass =
287             Class.forName("mir.servlet.ServletModule" + moduleName);
288         }
289
290         Method m = theServletModuleClass.getMethod("getInstance", null);
291         ServletModule smod = (ServletModule) m.invoke(null, null);
292
293         // we put it into map for further reference
294         servletModuleInstanceHash.put(moduleName, smod);
295
296         return smod;
297       }
298       catch (Exception e) {
299         throw new ServletModuleExc("*** error resolving classname for " + moduleName + " -- " + e.getMessage());
300       }
301     }
302     else {
303       return (ServletModule) servletModuleInstanceHash.get(moduleName);
304     }
305   }
306
307   private void handleUserError(HttpServletRequest aRequest, HttpServletResponse aResponse, ServletModuleUserExc anException) {
308     try {
309       logger.info("user error: " + anException.getMessage());
310
311       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] {getLocale(aRequest), getFallbackLocale()});
312
313       MessageResources messages = MessageResources.getMessageResources("bundles.admin");
314       responseData.put("errorstring", messages.getMessage(getLocale(aRequest), anException.getMessage(), anException.getParameters()));
315       responseData.put("date", new GregorianCalendar().getTime());
316
317       ServletHelper.generateResponse(aResponse.getWriter(), responseData, MirPropertiesConfiguration.instance().getString("Mir.UserErrorTemplate"));
318     }
319     catch (Throwable e) {
320       logger.error("Error handling user error" + e.toString());
321     }
322   }
323
324   private void handleError(HttpServletRequest aRequest, HttpServletResponse aResponse, Throwable anException) {
325     try {
326       logger.error("error: " + anException);
327
328       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] {getLocale(aRequest), getFallbackLocale()});
329
330       responseData.put("errorstring", anException.toString());
331       responseData.put("date", new GregorianCalendar().getTime());
332
333       ServletHelper.generateResponse(aResponse.getWriter(), responseData, MirPropertiesConfiguration.instance().getString("Mir.ErrorTemplate"));
334     }
335     catch (Throwable e) {
336       logger.error("Error handling error: " + e.toString());
337     }
338   }
339
340   // Redirect-methods
341   private void _sendLoginPage(HttpServletResponse aResponse, HttpServletRequest aRequest) {
342     String loginTemplate = configuration.getString("Mir.LoginTemplate");
343
344     try {
345       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] {getLocale(aRequest), getFallbackLocale()});
346
347       responseData.put("defaultlanguage", getDefaultLanguage(aRequest));
348       responseData.put("languages", getLoginLanguages());
349
350       ServletHelper.generateResponse(aResponse.getWriter(), responseData, loginTemplate);
351     }
352     catch (Throwable e) {
353       handleError(aRequest, aResponse, e);
354     }
355   }
356
357   public String getServletInfo() {
358     return "Mir " + configuration.getString("Mir.Version");
359   }
360
361   private class SessionTracker implements HttpSessionBindingListener {
362     private String name;
363
364     public SessionTracker(String aUserName) {
365       name = aUserName;
366     }
367
368     public void valueBound(HttpSessionBindingEvent anEvent) {
369       MirGlobal.registerLogin(name);
370     }
371
372     public void valueUnbound(HttpSessionBindingEvent anEvent) {
373       MirGlobal.registerLogout(name);
374     }
375   }
376 }