/********************************************************************** * $Source: /cvsroot/jameica/jameica.webadmin/src/de/willuhn/jameica/webtools/FrontController.java,v $ * $Revision: 1.5 $ * $Date: 2012/03/29 21:11:30 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn software & services * All rights reserved * **********************************************************************/ package de.willuhn.jameica.webtools; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.n3.nanoxml.IXMLElement; import net.n3.nanoxml.IXMLParser; import net.n3.nanoxml.StdXMLReader; import net.n3.nanoxml.XMLParserFactory; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import de.willuhn.datasource.BeanUtil; import de.willuhn.jameica.plugin.Manifest; import de.willuhn.jameica.services.VelocityService; import de.willuhn.jameica.system.Application; import de.willuhn.jameica.util.XPathEmu; import de.willuhn.logging.Logger; import de.willuhn.util.MultipleClassLoader; /** * Der Frontcontroller. */ public class FrontController extends HttpServlet { private String plugin = null; private MultipleClassLoader loader = null; private List<PageConfig> pages = new ArrayList<PageConfig>(); private Map<String,String> beans = new HashMap<String,String>(); /** * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig) */ public void init(ServletConfig config) throws ServletException { super.init(config); //////////////////////////////////////////////////////////////////////////// // Wir holen uns den Namen des Plugins. Ist eines angegeben, // nehmen wir dessen Classloader. this.plugin = config.getInitParameter("plugin"); if (plugin != null && plugin.length() > 0) { Logger.info("trying to determine classloader for plugin " + plugin); try { Manifest mf = Application.getPluginLoader().getManifest(plugin); Logger.info("found plugin (" + mf.getName() + " " + mf.getVersion() + ") - using its classloader"); this.loader = mf.getClassLoader(); } catch (Exception e) { Logger.warn("unable to load plugin, using global classloader: " + e.getMessage()); } } else { this.plugin = null; // sicherstellen, dass es NULL ist } if (this.loader == null) this.loader = Application.getClassLoader(); // //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // Config laden //////////////////////////////////////////////////////////////////////////// // Wir holen uns die webtools-config String s = config.getInitParameter("config"); if (s == null || s.length() == 0) s = "/WEB-INF/webtools.xml"; // //////////////////////////////////////////////////////////////////////////// Logger.info("trying to load webtools config: " + s); InputStream is = config.getServletContext().getResourceAsStream(s); if (is == null) throw new ServletException("config " + s + " not found in servlet context"); else Logger.info("loaded " + config.getServletContext().getRealPath(s)); try { IXMLParser parser = XMLParserFactory.createDefaultXMLParser(); parser.setReader(new StdXMLReader(is)); XPathEmu xpath = new XPathEmu((IXMLElement) parser.parse()); ////////////////////////////////////////////////////////////////////////// // Pages laden IXMLElement[] list = xpath.getElements("pages/page"); if (list == null || list.length == 0) throw new ServletException("webtools config " + s + " contains no page definitions"); for (IXMLElement child:list) { try { this.pages.add(new PageConfig(child)); } catch (Exception e) { Logger.error("error while loading page config: " + e.getMessage() + ", skipping page",e); } } Logger.info("found " + this.pages.size() + " page definitions"); ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // Beans laden list = xpath.getElements("beans/bean"); if (list != null && list.length > 0) { for (IXMLElement child:list) { try { String name = child.getAttribute("name",null); String className = child.getAttribute("class",null); if (name == null) throw new Exception("bean has no name attribute"); if (className == null) throw new Exception("bean has no class attribute"); this.beans.put(name,className); } catch (Exception e) { Logger.error("error while loading bean: " + e.getMessage() + ", skipping bean",e); } } } } catch (ServletException se) { throw se; } catch (Exception e) { throw new ServletException("unable to load webtools config " + s,e); } // //////////////////////////////////////////////////////////////////////////// } /** * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String path = request.getPathInfo(); if (path == null) path = request.getServletPath(); Logger.debug("looking for page definition for: " + path); if (path == null) path = ""; for (PageConfig pc:this.pages) { if (path.matches(pc.getPattern())) { try { // Template mit Context mergen und an Browser liefern VelocityService service = (VelocityService) Application.getBootLoader().getBootable(VelocityService.class); VelocityEngine engine = service.getEngine(this.plugin); RequestConfig cfg = new RequestConfig(this.loader,request,response); // Velocity-Context erzeugen VelocityContext ctx = new VelocityContext(); ctx.put("request", request); ctx.put("response", response); // Globale Beans Iterator<String> i = this.beans.keySet().iterator(); while (i.hasNext()) { String name = i.next(); Object bean = BeanHandler.getBean(cfg,this.beans.get(name)); if (bean != null) ctx.put(name,bean); } // Controller ausfuehren Object controller = BeanHandler.getBean(cfg,pc.getController()); if (controller != null) { // Es kann sein, dass ein Fehler geflogen ist und der User // auf eine Custom-Fehlerseite weitergeleitet wurde. Wenn // diese Fehlerseite ebenfalls eine Webtools-Page samt Controller // ist, wird der gesamte Request incl. der Action an diesen // Controller delegiert. Dieser hat die fehlerausloesende Action // aber natuerlich nicht. Daher markieren wir den Request unten // als fehlerhaft. Sollte anschliessend eine Anfrage hier rein // kommen, die diese Markierung traegt, dann handelt es sich // um eine Custom-Fehlerseite und wir fuehren die Action hier // nicht nochmal aus. if (request.getAttribute("__jameica.webtools.error") == null) { // Request-Properties in Controller uebernehmen BeanHandler.applyRequest(controller,cfg.getRequest()); // Wenn die Page eine Default-Action hat, rufen wir sie immer auf String action = pc.getAction(); if (action != null && action.length() > 0) BeanUtil.invoke(controller,action,null); // Wenn der Request auch eine Action hat, dann die ebenfalls action = request.getParameter("action"); if (action != null && action.length() > 0) BeanUtil.invoke(controller,action,null); } // Controller dem Context bekannt machen ctx.put("c",controller); } // Der Controller hat das Reponse bereits erledigt. Dann brauchen wir // das Template nicht mehr. if (response.isCommitted()) return; // Template ausfuehren Template template = engine.getTemplate(pc.getTemplate()); // TODO: Sollte hier ein Encoding angegeben sein? template.merge(ctx,response.getWriter()); } catch (Exception e) { request.setAttribute("__jameica.webtools.error",e); throw new ServletException(e); } // done return; } } // Wenn wir hier angekommen sind, wurde keine Page gefunden Logger.warn("no page config found for path " + path); response.sendError(HttpServletResponse.SC_NOT_FOUND); } } /********************************************************************** * $Log: FrontController.java,v $ * Revision 1.5 2012/03/29 21:11:30 willuhn * @C Kompatibilitaet zu Jameica 2.2 leider doch nicht moeglich * * Revision 1.4 2012/03/29 20:54:40 willuhn * @C Kompatibilitaet zu Jameica 2.2 wieder hergestellt * * Revision 1.3 2012/03/28 22:28:21 willuhn * @N Einfuehrung eines neuen Interfaces "Plugin", welches von "AbstractPlugin" implementiert wird. Es dient dazu, kuenftig auch Jameica-Plugins zu unterstuetzen, die selbst gar keinen eigenen Java-Code mitbringen sondern nur ein Manifest ("plugin.xml") und z.Bsp. Jars oder JS-Dateien. Plugin-Autoren muessen lediglich darauf achten, dass die Jameica-Funktionen, die bisher ein Object vom Typ "AbstractPlugin" zuruecklieferten, jetzt eines vom Typ "Plugin" liefern. * @C "getClassloader()" verschoben von "plugin.getRessources().getClassloader()" zu "manifest.getClassloader()" - der Zugriffsweg ist kuerzer. Die alte Variante existiert weiterhin, ist jedoch als deprecated markiert. * * Revision 1.2 2011-01-27 16:26:54 willuhn * @N Importieren und Loeschen von SSL-Zertifikaten * * Revision 1.1 2010-10-27 14:32:18 willuhn * @R jameica.webtools ist jetzt Bestandteil von jameica.webadmin. Das separate webtools-Plugin ist nicht mehr noetig * * Revision 1.15 2010/03/04 13:20:43 willuhn * @C Request-Properties nicht auf globale Beans anwenden * * Revision 1.14 2010/02/18 17:09:31 willuhn * *** empty log message *** * * Revision 1.13 2010/02/17 23:04:39 willuhn * @N Default-Action immer ausfuehren * * Revision 1.12 2010/02/01 15:13:36 willuhn * @N Neues Element "beans" fuer globale Beans in webtools.xml * @N Default-Action via Attribut "action" * * Revision 1.11 2010/01/21 10:05:18 willuhn * @N webtools um Default-Action erweitert * * Revision 1.10 2009/08/28 15:02:58 willuhn * @N webtool.xml nach webapps/$context/WEB-INF verschoben - dort kann sie ohne Namenskonflikte mit anderen "webtools.xml" geladen werden * * Revision 1.9 2009/08/24 12:05:33 willuhn * @N Umstellung auf neuen VelocityService - damit funktioniert das Plugin jetzt nur noch mit Jameica 1.9 * * Revision 1.8 2009/08/24 10:49:40 willuhn * *** empty log message *** * * Revision 1.7 2009/08/19 21:45:12 willuhn * @N Fehlerhandling * * Revision 1.6 2009/08/19 15:05:52 willuhn * @C Exception beim Ausfuehren der Action an den Servlet-Container weiterreichen, damit er sich um die Fehlerbehandlung kuemmern kann. Damit kann in web.xml auch eine eigene Fehlerseite definiert werden. * * Revision 1.5 2009/08/07 12:14:50 willuhn * *** empty log message *** * * Revision 1.4 2009/08/05 11:04:00 willuhn * @C Code cleanup * @N Webtools kennt jetzt die Lifecycle-Annotation * * Revision 1.3 2009/08/05 09:03:30 willuhn * @C Annotations in eigenes Package verschoben (sind nicht mehr REST-spezifisch) * * Revision 1.2 2009/08/03 23:44:17 willuhn * *** empty log message *** * * Revision 1.1 2009/08/03 23:17:18 willuhn * @N spartanisches Mini-Web-MVC-Framework mittels Frontcontroller und Velocity * **********************************************************************/