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