Added features:
[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: zapata $
74  * @version $Id: Mir.java,v 1.49.2.9 2003/12/21 13:32:02 zapata 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           usersModule.recordLogin(user);
173           aRequest.getSession().setAttribute("sessiontracker", new SessionTracker(username, user.getId()));
174         }
175       }
176
177       return user;
178     }
179     catch (Throwable t) {
180       t.printStackTrace();
181
182       throw new ServletException(t.toString());
183     }
184   }
185
186   public void process(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletException, IOException, UnavailableException {
187     try {
188       long startTime = System.currentTimeMillis();
189       long sessionConnectTime = 0;
190
191       HttpSession session = aRequest.getSession(true);
192       setNoCaching(aResponse);
193       Locale locale = new Locale(getDefaultLanguage(aRequest), "");
194       aResponse.setContentType("text/html; charset=" +
195                                configuration.
196                                getString("Mir.DefaultHTMLCharset", "UTF-8"));
197
198       EntityUsers userEntity = checkCredentials(aRequest);
199
200       if (userEntity == null) {
201         String queryString = aRequest.getQueryString();
202
203         if ( (queryString != null) && (queryString.length() != 0) && session.getAttribute("login.target") == null &&
204              (aRequest.getParameter("module")==null ||
205               (!aRequest.getParameter("module").equals("login") && !aRequest.getParameter("module").equals("logout")))) {
206           session.setAttribute("login.target", queryString);
207         }
208
209         _sendLoginPage(aResponse, aRequest);
210       }
211       else {
212         String moduleName = aRequest.getParameter("module");
213         checkLanguage(session, aRequest);
214
215         if ( ( (moduleName == null) || moduleName.equals(""))) {
216           moduleName="Admin";
217         }
218
219
220         if (moduleName.equals("login")) {
221           String target = (String) session.getAttribute("login.target");
222
223           if (target != null) {
224             ServletHelper.redirect(aResponse, target);
225           }
226           else {
227             ServletHelper.redirect(aResponse, "");
228           }
229         }
230         else if (moduleName.equals("logout")) {
231           logger.info(userEntity.getValue("login") + " has logged out");
232           session.invalidate();
233           _sendLoginPage(aResponse, aRequest);
234           return;
235         }
236         else {
237           try {
238             ServletModule servletModule = getServletModuleForName(moduleName);
239             ServletModuleDispatch.dispatch(servletModule, aRequest, aResponse);
240
241             sessionConnectTime = System.currentTimeMillis() - startTime;
242             logger.info("EXECTIME (" + moduleName + "): " + sessionConnectTime + " ms");
243           }
244           catch (Throwable e) {
245             Throwable cause = ExceptionFunctions.traceCauseException(e);
246
247             if (cause instanceof ServletModuleUserExc)
248               handleUserError(aRequest, aResponse, (ServletModuleUserExc) cause);
249             else
250               handleError(aRequest, aResponse, cause);
251           }
252
253           if (aRequest.getParameter("killsession")!=null)
254             aRequest.getSession().invalidate();
255         }
256       }
257     }
258     catch (Throwable t) {
259       t.printStackTrace();
260
261       throw new ServletException(t.toString());
262     }
263   }
264
265   /**
266    * caching routine to get a module for a module name
267    *
268    * @param moduleName the module name
269    * @return the requested module
270    * @throws ServletModuleExc
271    */
272
273   private static ServletModule getServletModuleForName(String moduleName) throws ServletModuleExc {
274     // Instance in Map ?
275     if (!servletModuleInstanceHash.containsKey(moduleName)) {
276       // was not found in hash...
277       try {
278         Class theServletModuleClass = null;
279
280         try {
281           // first we try to get ServletModule from stern.che3.servlet
282           theServletModuleClass =
283             Class.forName("mircoders.servlet.ServletModule" + moduleName);
284         }
285         catch (ClassNotFoundException e) {
286           // on failure, we try to get it from lib-layer
287           theServletModuleClass =
288             Class.forName("mir.servlet.ServletModule" + moduleName);
289         }
290
291         Method m = theServletModuleClass.getMethod("getInstance", null);
292         ServletModule smod = (ServletModule) m.invoke(null, null);
293
294         // we put it into map for further reference
295         servletModuleInstanceHash.put(moduleName, smod);
296
297         return smod;
298       }
299       catch (Exception e) {
300         throw new ServletModuleExc("*** error resolving classname for " + moduleName + " -- " + e.getMessage());
301       }
302     }
303     else {
304       return (ServletModule) servletModuleInstanceHash.get(moduleName);
305     }
306   }
307
308   private void handleUserError(HttpServletRequest aRequest, HttpServletResponse aResponse, ServletModuleUserExc anException) {
309     try {
310       logger.info("user error: " + anException.getMessage());
311
312       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] {getLocale(aRequest), getFallbackLocale()});
313
314       MessageResources messages = MessageResources.getMessageResources("bundles.admin");
315       responseData.put("errorstring", messages.getMessage(getLocale(aRequest), anException.getMessage(), anException.getParameters()));
316       responseData.put("date", new GregorianCalendar().getTime());
317
318       ServletHelper.generateResponse(aResponse.getWriter(), responseData, MirPropertiesConfiguration.instance().getString("Mir.UserErrorTemplate"));
319     }
320     catch (Throwable e) {
321       logger.error("Error handling user error" + e.toString());
322     }
323   }
324
325   private void handleError(HttpServletRequest aRequest, HttpServletResponse aResponse, Throwable anException) {
326     try {
327       logger.error("error: " + anException);
328
329       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] {getLocale(aRequest), getFallbackLocale()});
330
331       responseData.put("errorstring", anException.toString());
332       responseData.put("date", new GregorianCalendar().getTime());
333
334       ServletHelper.generateResponse(aResponse.getWriter(), responseData, MirPropertiesConfiguration.instance().getString("Mir.ErrorTemplate"));
335     }
336     catch (Throwable e) {
337       logger.error("Error handling error: " + e.toString());
338     }
339   }
340
341   // Redirect-methods
342   private void _sendLoginPage(HttpServletResponse aResponse, HttpServletRequest aRequest) {
343     String loginTemplate = configuration.getString("Mir.LoginTemplate");
344
345     try {
346       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] {getLocale(aRequest), getFallbackLocale()});
347
348       responseData.put("defaultlanguage", getDefaultLanguage(aRequest));
349       responseData.put("languages", getLoginLanguages());
350
351       ServletHelper.generateResponse(aResponse.getWriter(), responseData, loginTemplate);
352     }
353     catch (Throwable e) {
354       handleError(aRequest, aResponse, e);
355     }
356   }
357
358   public String getServletInfo() {
359     return "Mir " + configuration.getString("Mir.Version");
360   }
361
362   private class SessionTracker implements HttpSessionBindingListener {
363     private String name;
364     private String id;
365
366     public SessionTracker(String aUserName, String anId) {
367       name = aUserName;
368       id = anId;
369     }
370
371     public void valueBound(HttpSessionBindingEvent anEvent) {
372       MirGlobal.registerLogin(name, id);
373     }
374
375     public void valueUnbound(HttpSessionBindingEvent anEvent) {
376       MirGlobal.registerLogout(name, id);
377     }
378   }
379 }