f66b9a7d33f95691dc2c1c4450844575e30e26cd
[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 the com.oreilly.servlet library, any library
22  * licensed under the Apache Software License, The Sun (tm) Java Advanced
23  * Imaging library (JAI), The Sun JIMI library (or with modified versions of
24  * the above that use the same license as the above), and distribute linked
25  * combinations including the two.  You must obey the GNU General Public
26  * License in all respects for all of the code used other than the above
27  * mentioned libraries.  If you modify this file, you may extend this exception
28  * to your version of the file, but you are not obligated to do so.  If you do
29  * not wish to do so, delete this exception statement from your version.
30  */
31
32 import freemarker.template.SimpleHash;
33 import freemarker.template.SimpleScalar;
34 import mir.misc.HTMLParseException;
35 import mir.misc.HTMLTemplateProcessor;
36 import mir.misc.MirConfig;
37 import mir.misc.StringUtil;
38 import mir.servlet.*;
39 import mircoders.entity.EntityUsers;
40 import mircoders.module.ModuleMessage;
41 import mircoders.module.ModuleUsers;
42 import mircoders.storage.DatabaseMessages;
43 import mircoders.storage.DatabaseUsers;
44
45 import javax.servlet.ServletException;
46 import javax.servlet.UnavailableException;
47 import javax.servlet.http.HttpServletRequest;
48 import javax.servlet.http.HttpServletResponse;
49 import javax.servlet.http.HttpSession;
50 import java.io.IOException;
51 import java.io.PrintWriter;
52 import java.lang.reflect.Method;
53 import java.util.GregorianCalendar;
54 import java.util.HashMap;
55 import java.util.Locale;
56
57 /**
58  * Mir.java - main servlet, that dispatches to servletmodules
59  *
60  * @author $Author: mh $
61  * @version $Revision: 1.17.2.1 $ $Date: 2002/09/01 21:31:39 $
62  *
63  * $Log: Mir.java,v $
64  * Revision 1.17.2.1  2002/09/01 21:31:39  mh
65  * Mir goes GPL
66  *
67  * Revision 1.17  2002/07/21 22:27:39  mh
68  * make the user error msg look nicer
69  *
70  */
71
72
73 public class Mir extends AbstractServlet {
74
75     private static ModuleUsers usersModule = null;
76     private static ModuleMessage messageModule = null;
77     private final static HashMap servletModuleInstanceHash = new HashMap();
78
79     public HttpSession session;
80
81     public void doGet(HttpServletRequest req, HttpServletResponse res)
82             throws ServletException, IOException {
83         doPost(req, res);
84     }
85
86     public void doPost(HttpServletRequest req, HttpServletResponse res)
87             throws ServletException, IOException, UnavailableException {
88
89         long startTime = System.currentTimeMillis();
90         long sessionConnectTime = 0;
91         String http = "";
92
93         // get the configration - this could conflict if 2 mirs are in the
94         // VM maybe? to be checked. -mh
95         if (getServletContext().getAttribute("mir.confed") == null) {
96             getConfig(req);
97         }
98         MirConfig.setServletName(getServletName());
99
100         session = req.getSession(true);
101
102         if (req.getServerPort() == 443) http = "https"; else http = "http";
103         res.setContentType("text/html; charset="
104                             +MirConfig.getProp("Mir.DefaultEncoding"));
105         String moduleName = req.getParameter("module");
106
107         checkLanguage(session, req);
108
109         /** @todo for cleanup and readability this should be moved to
110          *  method loginIfNecessary() */
111
112         // Authentifizierung
113         if (moduleName != null && moduleName.equals("login")) {
114             String user = req.getParameter("login");
115             String passwd = req.getParameter("password");
116             theLog.printDebugInfo("--login: evaluating for user: " + user);
117             EntityUsers userEntity = allowedUser(user, passwd);
118             if (userEntity == null) {
119                 // login failed: redirecting to login
120                 theLog.printWarning("--login: failed!");
121                 _sendLoginPage(res, req, res.getWriter());
122                 return;
123             }
124             else {
125                 // login successful
126
127                 theLog.printInfo("--login: successful! setting uid: " + userEntity.getId());
128                 session.setAttribute("login.uid", userEntity);
129                 theLog.printDebugInfo("--login: trying to retrieve login.target");
130                 String target = (String) session.getAttribute("login.target");
131
132                 if (target != null) {
133                     theLog.printDebugInfo("Redirect: " + target);
134                     int serverPort = req.getServerPort();
135                     String redirect = "";
136                     String redirectString = "";
137
138
139                     if (serverPort == 80) {
140                         redirect = res.encodeURL(http + "://" + req.getServerName() + target);
141                         redirectString = "<html><head><meta http-equiv=refresh content=\"1;URL="
142                                 + redirect
143                                 + "\"></head><body>going <a href=\"" + redirect + "\">Mir</a></body></html>";
144                     }
145                     else {
146                         redirect = res.encodeURL(http + "://" + req.getServerName() + ":" + req.getServerPort() + target);
147                         redirectString = "<html><head><meta http-equiv=refresh content=\"1;URL="
148                                 + redirect
149                                 + "\"></head><body>going <a href=\"" + redirect + "\">Mir</a></body></html>";
150                     }
151                     res.getWriter().println(redirectString);
152
153
154                     //res.sendRedirect(redirect);
155
156                 }
157                 else {
158                     // redirecting to default target
159                     theLog.printDebugInfo("--login: no target - redirecting to default");
160                     _sendStartPage(res, req, res.getWriter(), userEntity);
161                 }
162                 return;
163             } // if login succesful
164         } // if login
165
166         if (moduleName != null && moduleName.equals("logout")) {
167             theLog.printDebugInfo("--logout");
168             session.invalidate();
169
170             //session = req.getSession(true);
171             //checkLanguage(session, req);
172             _sendLoginPage(res, req, res.getWriter());
173             return;
174         }
175
176         // Check if authed!
177         EntityUsers userEntity = (EntityUsers) session.getAttribute("login.uid");
178         if (userEntity == null) {
179             // redirect to loginpage
180             String redirectString = req.getRequestURI();
181             String queryString = req.getQueryString();
182             if (queryString != null && !queryString.equals("")) {
183                 redirectString += "?" + req.getQueryString();
184                 theLog.printDebugInfo("STORING: " + redirectString);
185                 session.setAttribute("login.target", redirectString);
186             }
187             _sendLoginPage(res, req, res.getWriter());
188             return;
189         }
190
191         // If no module is specified goto standard startpage
192         if (moduleName == null || moduleName.equals("")) {
193             theLog.printDebugInfo("no module: redirect to standardpage");
194             _sendStartPage(res, req, res.getWriter(), userEntity);
195             return;
196         }
197         // end of auth
198
199         // From now on regular dispatching...
200         try {
201             // get servletmodule by parameter and continue with dispacher
202             ServletModule smod = getServletModuleForName(moduleName);
203             ServletModuleDispatch.dispatch(smod, req, res);
204         }
205         catch (ServletModuleException e) {
206             handleError(req, res, res.getWriter(),
207                         "ServletException in Module " + moduleName + " -- " + e.toString());
208         }
209         catch (ServletModuleUserException e) {
210             handleUserError(req, res, res.getWriter(), e.getMsg());
211         }
212
213         // timing...
214         sessionConnectTime = System.currentTimeMillis() - startTime;
215         theLog.printInfo("EXECTIME (" + moduleName + "): " + sessionConnectTime + " ms");
216     }
217
218
219     /**
220      *  Private method getServletModuleForName returns ServletModule
221      *  from Cache
222      *
223      * @return ServletModule
224      *
225      */
226     private static ServletModule getServletModuleForName(String moduleName)
227             throws ServletModuleException {
228
229         // Instance in Map ?
230         if (!servletModuleInstanceHash.containsKey(moduleName)) {
231             // was not found in hash...
232             try {
233                 Class theServletModuleClass = null;
234                 try {
235                     // first we try to get ServletModule from stern.che3.servlet
236                     theServletModuleClass = Class.forName("mircoders.servlet.ServletModule" + moduleName);
237                 }
238                 catch (ClassNotFoundException e) {
239                     // on failure, we try to get it from lib-layer
240                     theServletModuleClass = Class.forName("mir.servlet.ServletModule" + moduleName);
241                 }
242                 Method m = theServletModuleClass.getMethod("getInstance", null);
243                 ServletModule smod = (ServletModule) m.invoke(null, null);
244                 // we put it into map for further reference
245                 servletModuleInstanceHash.put(moduleName, smod);
246                 return smod;
247             }
248             catch (Exception e) {
249                 throw new ServletModuleException("*** error resolving classname for " +
250                                                  moduleName + " -- " + e.toString());
251             }
252         }
253         else
254             return (ServletModule) servletModuleInstanceHash.get(moduleName);
255     }
256
257
258     private void handleError(HttpServletRequest req, HttpServletResponse res,
259                              PrintWriter out, String errorString) {
260
261         try {
262             theLog.printError(errorString);
263             SimpleHash modelRoot = new SimpleHash();
264             modelRoot.put("errorstring", new SimpleScalar(errorString));
265             modelRoot.put("date", new SimpleScalar(StringUtil.date2readableDateTime(new GregorianCalendar())));
266             HTMLTemplateProcessor.process(res, MirConfig.getProp("Mir.ErrorTemplate"), modelRoot, out, getLocale(req));
267             out.close();
268         }
269         catch (Exception e) {
270             System.err.println("Error in ErrorTemplate");
271         }
272     }
273
274     private void handleUserError(HttpServletRequest req, HttpServletResponse res,
275                                  PrintWriter out, String errorString) {
276         try {
277             theLog.printError(errorString);
278             SimpleHash modelRoot = new SimpleHash();
279             modelRoot.put("errorstring", new SimpleScalar(errorString));
280             modelRoot.put("date", new SimpleScalar(StringUtil.date2readableDateTime(new GregorianCalendar())));
281             HTMLTemplateProcessor.process(res, MirConfig.getProp("Mir.UserErrorTemplate"),
282                                           modelRoot, out, getLocale(req));
283             out.close();
284         }
285         catch (Exception e) {
286             System.err.println("Fehler in UserErrorTemplate");
287         }
288
289     }
290
291     /**
292      *  evaluate login for user / password
293      */
294     protected EntityUsers allowedUser(String user, String password) {
295         try {
296             if (usersModule == null) usersModule = new ModuleUsers(DatabaseUsers.getInstance());
297             return usersModule.getUserForLogin(user, password);
298         }
299         catch (Exception e) {
300             theLog.printDebugInfo(e.toString());
301             e.printStackTrace();
302             return null;
303         }
304     }
305
306     // Redirect-methods
307     private void _sendLoginPage(HttpServletResponse res, HttpServletRequest req, PrintWriter out) {
308         String loginTemplate = MirConfig.getProp("Mir.LoginTemplate");//"login.template";
309         //  theLog.printDebugInfo("login template: "+loginTemplate);
310         String sessionUrl = res.encodeURL("");
311         //session = req.getSession(true);
312         try {
313             //theLog.printDebugInfo("login: "+lang);
314             //if(lang==null){
315             //  lang=getAcceptLanguage(req);
316             //}
317             SimpleHash mergeData = new SimpleHash();
318             mergeData.put("session", sessionUrl);
319             HTMLTemplateProcessor.process(res, loginTemplate, mergeData, out, getLocale(req));
320         }
321         catch (HTMLParseException e) {
322             handleError(req, res, out, "Error in logintemplate.");
323         }
324     }
325
326     private void _sendStartPage(HttpServletResponse res, HttpServletRequest req, PrintWriter out, EntityUsers userEntity) {
327         String startTemplate = "admin/start_admin.template";
328         String sessionUrl = res.encodeURL("");
329         try {
330             // merge with logged in user and messages
331             SimpleHash mergeData = new SimpleHash();
332             mergeData.put("session", sessionUrl);
333             mergeData.put("login_user", userEntity);
334             if (messageModule == null) messageModule = new ModuleMessage(DatabaseMessages.getInstance());
335             mergeData.put("messages", messageModule.getByWhereClause(null, "webdb_create desc", 0, 10));
336             HTMLTemplateProcessor.process(res, startTemplate, mergeData, out, getLocale(req));
337         }
338         catch (Exception e) {
339             handleError(req, res, out, "error while trying to send startpage. " + e.toString());
340         }
341     }
342
343     public String getServletInfo() {
344         return "Mir "+MirConfig.getProp("Mir.Version");
345     }
346
347     private void checkLanguage(HttpSession session, HttpServletRequest req) {
348
349         // a lang parameter always sets the language
350         String lang = req.getParameter("lang");
351         if (lang != null) {
352             theLog.printInfo("selected language "+lang+" overrides accept-language");
353             setLanguage(session, lang);
354             setLocale(session, new Locale(lang, ""));
355         }
356         // otherwise store language from accept header in session
357         else if (session.getAttribute("Language") == null) {
358             theLog.printInfo("accept-language is "+req.getLocale().getLanguage());
359             setLanguage(session, req.getLocale().getLanguage());
360             setLocale(session, req.getLocale());
361         }
362     }
363 }
364