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