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