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