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