package com.udapsoft.waf.system.controller; import java.io.IOException; import java.net.URL; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.StringTokenizer; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.transaction.HeuristicMixedException; import javax.transaction.HeuristicRollbackException; import javax.transaction.NotSupportedException; import javax.transaction.RollbackException; import javax.transaction.SystemException; import javax.transaction.UserTransaction; import kr.co.hsnc.common.base.WAFFactory; import kr.co.hsnc.common.base.WAFLogger; import kr.co.hsnc.common.loader.FileChangeListener; import kr.co.hsnc.common.loader.FileMonitor; import kr.co.hsnc.j2ee.waf.controller.web.action.ActionHandler; import kr.co.hsnc.j2ee.waf.controller.web.util.WebKeys; import kr.co.hsnc.j2ee.waf.view.template.Screen; import kr.co.hsnc.j2ee.waf.view.template.ScreenDefinitionDAO; import kr.co.hsnc.j2ee.waf.view.template.Screens; import com.udapsoft.waf.system.HandlerStorage; public class FrontController extends HttpServlet implements FileChangeListener { private static final long serialVersionUID = 4556105374329449270L; private HashMap allScreens; private ServletConfig config; private ServletContext context; private String defaultLocale; private boolean cachePreviousScreenAttributes = false; private boolean cachePreviousScreenParameters = false; private static final String PREVIOUS_SCREEN = "PREVIOUS"; private boolean isDebug = false; // FileChangeListener Variables private long interval = 2000L; private FileMonitor monitor; private SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); /** * Called by the servlet container to indicate to a servlet that the servlet * is being placed into service. * * @param config * ServletConfig * @exception ServletException * - if an exception occurs that interrupts the servlet's * normal operation. */ public void init(ServletConfig config) throws ServletException { super.init(config); this.config = config; this.context = config.getServletContext(); this.monitor = FileMonitor.getInstance(); // enable the caching of previous screen attributes String cachePreviousScreenAttributesString = config.getInitParameter("cache_previous_screen_attributes"); if (cachePreviousScreenAttributesString != null) { if (cachePreviousScreenAttributesString.toLowerCase().equals("true")) { WAFLogger.sys("FrontController: Enabled caching of previous screen attributes."); cachePreviousScreenAttributes = true; } } // enable the caching of previous screen parameters String cachePreviousScreenParametersString = config.getInitParameter("cache_previous_screen_parameters"); if (cachePreviousScreenParametersString != null) { if (cachePreviousScreenParametersString.toLowerCase().equals("true")) { WAFLogger.sys("FrontController: Enabled caching of previous screen parameters."); cachePreviousScreenParameters = true; } } allScreens = new HashMap(); defaultLocale = config.getInitParameter("default_locale"); if (defaultLocale == null) { defaultLocale = (Locale.getDefault()).toString(); } String locales = config.getInitParameter("locales"); if (locales != null) { StringTokenizer strTok = new StringTokenizer(locales, ","); while (strTok.hasMoreTokens()) { initScreens(config.getServletContext(), strTok.nextToken()); } } } /** * FileChangeListener.fileChanged() Implementation.... * * @param fileName * screendefinitions file name. */ public void fileChanged(String fileName) { WAFLogger.sys("[" + this.formatter.format(Calendar.getInstance().getTime()) + "] FrontController.fileChanged()... -> " + fileName); initScreens(context, defaultLocale); } /** * initialize screens. * * @param context * ServletContext. * @param language * locale language. */ protected synchronized void initScreens(ServletContext context, String language) { URL screenDefinitionURL = null; String screenDefinitionRealPath = null; try { screenDefinitionURL = context.getResource("/WEB-INF/screendefinitions_" + language + ".xml"); screenDefinitionRealPath = context.getRealPath("/WEB-INF/screendefinitions_" + language + ".xml"); this.monitor.addFileChangeListener(this, screenDefinitionRealPath, this.interval); } catch (java.net.MalformedURLException ex) { WAFLogger.sys("FrontController.initScreens(): malformed URL exception: " + ex); } catch (java.io.IOException ex) { WAFLogger.sys("FrontController.initScreens(): IOException: " + ex); } if (screenDefinitionURL != null) { Screens screenDefinitions = ScreenDefinitionDAO.loadScreenDefinitions(screenDefinitionURL); if (screenDefinitions != null) { allScreens.put(language, screenDefinitions); } else { WAFLogger.sys("Template Servlet Error Loading Screen Definitions: Confirm that file at URL /WEB-INF/screendefinitions_" + language + ".xml contains the screen definitions"); } } else { WAFLogger.sys("Template Servlet Error Loading Screen Definitions: URL /WEB-INF/screendefinitions_" + language + ".xml not found"); } } /** * Called by the servlet container to indicate to a servlet that the servlet * is being placed into service. * * @param request * HttpServletRequest * @param response * HttpServletResponse * @exception ServletException * if an exception occurs that interferes with the servlet's * normal operation occurred * @exception IOException * if an input or output exception occurs */ public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { request.setAttribute("WAF.TIMESTAMP", new Long(System.currentTimeMillis())); /** * 브라우저 Cache Expire 시키기 */ if (request.getProtocol().compareTo("HTTP/1.0") == 0) { response.setHeader("Pragma", "no-cache"); } else if (request.getProtocol().compareTo("HTTP/1.1") == 0) { response.setHeader("Cache-Control", "no-cache"); } response.setDateHeader("Expires", 0); String screenName = null; String localeString = null; String currentURI = request.getRequestURI(); if (request.getSession().getAttribute(WebKeys.CURRENT_URI) != null) { request.getSession().removeAttribute(WebKeys.CURRENT_URI); } request.getSession().setAttribute(WebKeys.CURRENT_URI, currentURI); debug(" currentURI=" + currentURI); String languageParam = request.getParameter("locale"); // The language when specified as a parameter overrides the language set // in the session if (request.getSession().getAttribute(WebKeys.LOCALE) == null) { Locale locale = new Locale(defaultLocale.substring(0, 2), defaultLocale.substring(3, 5)); request.getSession().setAttribute(WebKeys.LOCALE, locale); } if (languageParam != null) { localeString = languageParam; } else if (request.getSession().getAttribute(WebKeys.LOCALE) != null) { localeString = ((Locale) request.getSession().getAttribute( WebKeys.LOCALE)).toString(); } if (allScreens.get(localeString) == null) { localeString = defaultLocale; } // get the screen name // int lastPathSeparator = currentURI.lastIndexOf("/") + 1; // int lastDot = currentURI.lastIndexOf("."); String currentScreen = currentURI.substring(request.getContextPath().length()); int lastDot = currentScreen.lastIndexOf("."); // if (lastPathSeparator != -1 && lastDot != -1 && lastDot > // lastPathSeparator) { if (lastDot != -1) { // screenName = currentURI.substring(lastPathSeparator, lastDot); screenName = currentScreen.substring(0, lastDot); } debug(" screenName=" + screenName); // check if request is for the previous screen if (screenName.equals(PREVIOUS_SCREEN)) { String longScreenName = (String) request.getSession().getAttribute( WebKeys.PREVIOUS_SCREEN); int lastDot2 = longScreenName.lastIndexOf("."); if (lastDot2 != -1 && lastDot2 > 0) { screenName = longScreenName.substring(0, lastDot2); } // put the request attributes stored in the session in the request if (cachePreviousScreenParameters) { Map previousParams = (Map) request.getSession().getAttribute(WebKeys.PREVIOUS_REQUEST_PARAMETERS); Map params = (Map) request.getParameterMap(); Iterator it = previousParams.keySet().iterator(); while (it.hasNext()) { String key = (String) it.next(); Object value = previousParams.get(key); params.put(key, (String[]) value); } } // put in the previous request attributes if (cachePreviousScreenAttributes) { Map previousAttributes = (Map) request.getSession().getAttribute(WebKeys.PREVIOUS_REQUEST_ATTRIBUTES); Iterator it2 = previousAttributes.keySet().iterator(); // put the request attributes stored in the session in the // request while (it2.hasNext()) { String key = (String) it2.next(); Object value = previousAttributes.get(key); request.setAttribute(key, value); } } } else { String extension = currentURI.substring(lastDot, currentURI.length()); request.getSession().setAttribute(WebKeys.PREVIOUS_SCREEN, screenName + extension); if (cachePreviousScreenParameters) { // copy all the parameters into a new map HashMap newParams = new HashMap(); Map params = (Map) request.getParameterMap(); Iterator it = params.keySet().iterator(); // put the request attributes stored in the session in the // request while (it.hasNext()) { String key = (String) it.next(); Object value = params.get(key); newParams.put(key, value); } request.getSession().setAttribute(WebKeys.PREVIOUS_REQUEST_PARAMETERS, newParams); } if (cachePreviousScreenAttributes) { // put the request attributes into a map HashMap attributes = new HashMap(); Enumeration enums = request.getAttributeNames(); while (enums.hasMoreElements()) { String key = (String) enums.nextElement(); Object value = request.getAttribute(key); attributes.put(key, value); } request.getSession().setAttribute(WebKeys.PREVIOUS_REQUEST_ATTRIBUTES, attributes); } } // get the screen information for the coresponding language Screen screen = null; if (screenName != null) { Screens localeScreens = (Screens) allScreens.get(localeString); if (localeScreens != null) { // ********************************************************************** if (request.getSession().getAttribute(WebKeys.SCREENS) == null) { request.getSession().setAttribute(WebKeys.SCREENS, localeScreens); } // ********************************************************************** screen = (Screen) localeScreens.getScreen(screenName); } // default to the default locale screen if it was not defined in the // locale specific definitions if (screen == null) { WAFLogger.debug("Screen not Found loading default from " + defaultLocale); localeScreens = (Screens) allScreens.get(defaultLocale); screen = (Screen) localeScreens.getScreen(screenName); } if (screen != null) { String handler = screen.getHandler(); debug("##### -> handler = " + (handler == "" ? "NULL" : handler)); if (handler != "") { // ********************************************************************** request.setAttribute(HandlerStorage.KEY, currentURI + "_" + request.getParameter("event")); String screenname = processRequest(request, response, handler); if (screenname != null) { screenName = screenname; screen = (Screen) localeScreens.getScreen(screenName); debug(" 1 screenName = " + screenName); } } debug(" 2 screenName = " + screenName); request.setAttribute(WebKeys.CURRENT_SCREEN, screen); String templateName = localeScreens.getTemplate(screenName); debug(" 3 templateName = " + templateName); if (templateName != null) { insertTemplate(request, response, templateName); } } else { WAFLogger.debug("Error: Definition for screen " + screenName + " not found"); response.setStatus(javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY); response.setHeader("Location", request.getContextPath() + "/error.screen?code=WAF-400¶m1=" + screenName); } } } /** * process request. * * @param request * HttpServletRequest * @param response * HttpServletResponse * @param handlerName * handler name */ protected String processRequest(HttpServletRequest request, HttpServletResponse response, String handlerName) { String screen = null; // FlowHandler handler = null; ActionHandler handler = null; try { debug("processRequest()...1 " + handlerName); // handler = // (FlowHandler)getClass().getClassLoader().loadClass(handlerName).newInstance(); /* * if ( request.getSession().getAttribute(handlerName) == null) { * debug("processRequest()...1-1 "); * //request.getSession().setAttribute(handlerName, * getClass().getClassLoader * ().loadClass(handlerName).newInstance()); * request.getSession().setAttribute(handlerName, * WAFFactory.getInstance(handlerName)); } handler = * (ActionHandler)request.getSession().getAttribute(handlerName); */ handler = (ActionHandler) WAFFactory.getInstance(handlerName); // invoke the processFlow(HttpServletRequest) handler.doStart(request); debug("processRequest()...2 " + handler); // flowResult = handler.processFlow(request); screen = handler.doHandle(request); debug("processRequest()...3 screen=" + screen); handler.doEnd(request); } catch (Exception e) { WAFLogger.debug("[Exception]FrontController.processRequest()... " + e); WAFLogger.errorStackTraceeElement(e); } finally { handler = null; } return screen; } /** * insert template. * * @param request * HttpServletRequest * @param response * HttpServletResponse * @param templateName * template name * @exception ServletException * if an exception occurs that interferes with the servlet's * normal operation occurred * @exception IOException * if an input or output exception occurs */ protected void insertTemplate(HttpServletRequest request, HttpServletResponse response, String templateName) throws IOException, ServletException { // This method tries to wrap the request dispatcher call with-in // a transaction for making the local EJB access efficient. However, // it is not a fatal error, if such a transaction can not be started // for some reason, so it handles them gracefully. boolean tx_started = false; UserTransaction ut = null; try { // Lookup the UserTransaction object InitialContext ic = new InitialContext(); ut = (UserTransaction) ic.lookup("java:comp/UserTransaction"); ut.begin(); // start the transaction. tx_started = true; /*************************************************************/ // RollbackException ut.setTransactionTimeout(300); // 5 minutes /*************************************************************/ } catch (NamingException ne) { // it should not have happened, but it is a recoverable error. // Just dont start the transaction. // ne.printStackTrace(); } catch (NotSupportedException nse) { // Again this is a recoverable error. nse.printStackTrace(); } catch (SystemException se) { // Again this is a recoverable error. se.printStackTrace(); } try { context.getRequestDispatcher(templateName).forward(request, response); } finally { // commit the transaction if it was started earlier successfully. try { if (tx_started && ut != null) { ut.commit(); } } catch (IllegalStateException re) { re.printStackTrace(); } catch (RollbackException re) { re.printStackTrace(); } catch (HeuristicMixedException hme) { hme.printStackTrace(); } catch (HeuristicRollbackException hre) { hre.printStackTrace(); } catch (SystemException se) { se.printStackTrace(); } } } private void debug(Object obj) { if (isDebug) WAFLogger.debug("[FrontController]" + obj); } }