Java tutorial
/* * Copyright 2004-2005 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.hedtech.banner.filters; import com.opensymphony.module.sitemesh.Config; import com.opensymphony.module.sitemesh.DecoratorMapper; import com.opensymphony.module.sitemesh.RequestConstants; import com.opensymphony.sitemesh.Content; import com.opensymphony.sitemesh.ContentProcessor; import com.opensymphony.sitemesh.Decorator; import com.opensymphony.sitemesh.compatability.OldDecorator2NewDecorator; import com.opensymphony.sitemesh.compatability.PageParser2ContentProcessor; import com.opensymphony.sitemesh.webapp.ContainerTweaks; import com.opensymphony.sitemesh.webapp.SiteMeshFilter; import com.opensymphony.sitemesh.webapp.SiteMeshWebAppContext; import grails.util.Environment; import grails.util.GrailsWebUtil; import grails.util.Holders; import net.hedtech.banner.security.FormContext; import org.apache.log4j.Logger; import org.codehaus.groovy.grails.commons.GrailsApplication; import org.codehaus.groovy.grails.support.NullPersistentContextInterceptor; import org.codehaus.groovy.grails.support.PersistenceContextInterceptor; import org.codehaus.groovy.grails.web.context.ServletContextHolder; import org.codehaus.groovy.grails.web.mapping.LinkGenerator; import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes; import org.codehaus.groovy.grails.web.sitemesh.*; import org.codehaus.groovy.grails.web.util.StreamCharBuffer; import org.codehaus.groovy.grails.web.util.WebUtils; import org.springframework.context.ApplicationContext; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.util.UrlPathHelper; import org.zkoss.zk.grails.ZkConfigHelper; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Extends the default page filter to overide the apply decorator behaviour * if the page is a GSP * * @author Graeme Rocher */ public class ZKPageFilter2 extends SiteMeshFilter { public static final String ALREADY_APPLIED_KEY = "com.opensymphony.sitemesh.APPLIED_ONCE"; public static final String FACTORY_SERVLET_CONTEXT_ATTRIBUTE = "sitemesh.factory"; private static final String HTML_EXT = ".html"; private static final String UTF_8_ENCODING = "UTF-8"; private static final String CONFIG_OPTION_GSP_ENCODING = "grails.views.gsp.encoding"; public static final String GSP_SITEMESH_PAGE = GrailsPageFilter.class.getName() + ".GSP_SITEMESH_PAGE"; private FilterConfig filterConfig; private ContainerTweaks containerTweaks; private WebApplicationContext applicationContext; private PersistenceContextInterceptor persistenceInterceptor = new NullPersistentContextInterceptor(); private String defaultEncoding = UTF_8_ENCODING; protected ViewResolver layoutViewResolver; private ContentProcessor contentProcessor; private DecoratorMapper decoratorMapper; private static Map formControllerMap = (Map) ((GrailsApplication) getApplicationContext() .getBean("grailsApplication")).getConfig().get("formControllerMap"); Logger log = Logger.getLogger(ZKPageFilter2.class); @Override public void init(FilterConfig fc) { super.init(fc); this.filterConfig = fc; containerTweaks = new ContainerTweaks(); Config config = new Config(fc); Grails5535Factory defaultFactory = new Grails5535Factory(config); // TODO revert once Sitemesh bug is fixed fc.getServletContext().setAttribute(FACTORY_SERVLET_CONTEXT_ATTRIBUTE, defaultFactory); defaultFactory.refresh(); FactoryHolder.setFactory(defaultFactory); contentProcessor = new PageParser2ContentProcessor(defaultFactory); decoratorMapper = defaultFactory.getDecoratorMapper(); applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(fc.getServletContext()); layoutViewResolver = WebUtils.lookupViewResolver(applicationContext); final GrailsApplication grailsApplication = GrailsWebUtil.lookupApplication(fc.getServletContext()); String encoding = (String) grailsApplication.getFlatConfig().get(CONFIG_OPTION_GSP_ENCODING); if (encoding != null) { defaultEncoding = encoding; } Map<String, PersistenceContextInterceptor> interceptors = applicationContext .getBeansOfType(PersistenceContextInterceptor.class); if (!interceptors.isEmpty()) { persistenceInterceptor = interceptors.values().iterator().next(); } } @Override public void destroy() { super.destroy(); FactoryHolder.setFactory(null); } private String extractRequestPath(HttpServletRequest request) { String servletPath = request.getServletPath(); String pathInfo = request.getPathInfo(); String query = request.getQueryString(); return (servletPath == null ? "" : servletPath) + (pathInfo == null ? "" : pathInfo) + (query == null ? "" : ("?" + query)); } private boolean isZUL(HttpServletRequest request) { String path = extractRequestPath(request); ArrayList<String> arrExtensions = ZkConfigHelper.getSupportExtensions(); if (arrExtensions == null || arrExtensions.size() == 0) { arrExtensions = new ArrayList<String>(); arrExtensions.add("zul"); } for (String sExt : arrExtensions) { if (path.lastIndexOf("." + sExt) != -1) return true; } return false; } private boolean isZK(HttpServletRequest request) { String path = extractRequestPath(request); if (path.indexOf("/zkau") != -1) return true; // // Extended checking in support extension configuration // By default, ["zul"] will be checked here // ArrayList<String> arrExtensions = ZkConfigHelper.getSupportExtensions(); if (arrExtensions == null || arrExtensions.size() == 0) { arrExtensions = new ArrayList<String>(); arrExtensions.add("zul"); } for (String sExt : arrExtensions) { if (path.lastIndexOf("." + sExt) != -1) return true; } final String[] ext = new String[] { ".dsp", ".zhtml", ".svg", ".xml2html" }; for (int i = 0; i < ext.length; i++) { if (path.lastIndexOf(ext[i]) != -1) return true; } return false; } private boolean isRoot(HttpServletRequest request) { String path = (new UrlPathHelper()).getPathWithinApplication(request); if (path.equals("/")) return true; return false; } private void applyFormContext(HttpServletRequest request) { if (!"rmDesktop".equals(request.getParameter("cmd_0"))) { String currentPage = getCurrentPageFromZKRequest(request); log.debug("currentPage = " + currentPage); if (currentPage != null) { List contextList = new ArrayList((List) formControllerMap.get(currentPage.toLowerCase())); // Purely a debugging block if (log.isDebugEnabled()) { if (contextList == null) { log.debug("contextList is null"); } else { log.debug("contextList.size() = " + contextList.size()); StringBuffer sb = new StringBuffer(); for (int i = 0; i < contextList.size(); i++) { if (i == 0) { sb.append(contextList.get(i)); } else { sb.append(",").append(contextList.get(i)); } } log.debug("contextList = " + sb.toString()); } } //FormContext.clear(); FormContext.set(contextList); log.debug("FormContext set."); } } } /* * TODO: This method has been copied from the parent to fix a bug in sitemesh 2.3. When sitemesh 2.4 is release this method and the two private methods below can removed * * Main method of the Filter. * * <p>Checks if the Filter has been applied this request. If not, parses the page * and applies {@link com.opensymphony.module.sitemesh.Decorator} (if found). */ @Override public void doFilter(ServletRequest rq, ServletResponse rs, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) rq; HttpServletResponse response = (HttpServletResponse) rs; ServletContext servletContext = filterConfig.getServletContext(); SiteMeshWebAppContext webAppContext = new SiteMeshWebAppContext(request, response, servletContext); if (filterAlreadyAppliedForRequest(request)) { // Prior to Servlet 2.4 spec, it was unspecified whether the filter should be called again upon an include(). chain.doFilter(request, response); return; } if (isRoot(request)) { //request.getRequestDispatcher("/").forward(request,response); String redirectURL = (String) Holders.getFlatConfig() .get("bannerxe.admin.login.rootContextRedirectURL"); if (null != redirectURL && !"".equals(redirectURL)) { response.sendRedirect(redirectURL); } else { response.sendRedirect("banner.zul?page=mainPage"); } return; } if (isZUL(request)) { applyFormContext(request); // // TODO if disable live // Content content = obtainContent(contentProcessor, webAppContext, request, response, chain); if (content == null || response.isCommitted()) { return; } //applyLive(request, content); new GrailsNoDecorator().render(content, webAppContext); return; } if (isZK(request)) { applyFormContext(request); chain.doFilter(request, response); return; } if (!contentProcessor.handles(webAppContext)) { // Optimization: If the content doesn't need to be processed, bypass SiteMesh. chain.doFilter(request, response); return; } // clear the page in case it is already present request.removeAttribute(RequestConstants.PAGE); if (containerTweaks.shouldAutoCreateSession()) { request.getSession(true); } boolean dispatched = false; try { persistenceInterceptor.init(); Content content = obtainContent(contentProcessor, webAppContext, request, response, chain); if (content == null || response.isCommitted()) { return; } // applyLive(request, content); detectContentTypeFromPage(content, response); com.opensymphony.module.sitemesh.Decorator decorator = decoratorMapper.getDecorator(request, GSPSitemeshPage.content2htmlPage(content)); if (decorator instanceof Decorator) { ((Decorator) decorator).render(content, webAppContext); } else { new OldDecorator2NewDecorator(decorator).render(content, webAppContext); } dispatched = true; } catch (IllegalStateException e) { // Some containers (such as WebLogic) throw an IllegalStateException when an error page is served. // It may be ok to ignore this. However, for safety it is propegated if possible. if (!containerTweaks.shouldIgnoreIllegalStateExceptionOnErrorPage()) { throw e; } } finally { if (!dispatched) { // an error occured request.setAttribute(ALREADY_APPLIED_KEY, null); } if (persistenceInterceptor.isOpen()) { persistenceInterceptor.flush(); persistenceInterceptor.destroy(); } } } private void applyLive(HttpServletRequest request, Content content) throws IOException { if (Environment.getCurrent() == Environment.DEVELOPMENT) { // if ZK Grails in the Dev mode // insert z-it-live.js if (content instanceof GSPSitemeshPage) { GSPSitemeshPage page = (GSPSitemeshPage) content; String pageContent = page.getPage(); if (pageContent == null) { return; } String contextPath = request.getContextPath(); // // src="/zello/zkau/ if (pageContent.indexOf("src=\"" + contextPath + "/zkau/") > 0) { StreamCharBuffer buffer = new StreamCharBuffer(); LinkGenerator grailsLinkGenerator = (LinkGenerator) applicationContext .getBean("grailsLinkGenerator"); String link = grailsLinkGenerator.resource(new HashMap() { { put("dir", "ext/js"); put("file", "z-it-live.js"); put("plugin", "zk"); } }); buffer.getWriter() .write(pageContent.replace("</head>", "<script type=\"text/javascript\" src=\"" + link + "\" charset=\"UTF-8\"></script>\n</head>")); page.setPageBuffer(buffer); } } } } private String detectZULFile(String pageContent, String contextPath) { // detect uu:'/zello/zkau' int i = pageContent.indexOf("uu:'" + contextPath + "/zkau'"); if (i < 0) return null; i += 4; int j = i; while (pageContent.charAt(j) != '\'') { j++; if (j >= pageContent.length()) return null; } return pageContent.substring(i, j); } /** * Continue in filter-chain, writing all content to buffer and parsing * into returned {@link com.opensymphony.module.sitemesh.Page} object. If * {@link com.opensymphony.module.sitemesh.Page} is not parseable, null is returned. */ private Content obtainContent(ContentProcessor contentProcessor, SiteMeshWebAppContext webAppContext, HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { Object oldGspSiteMeshPage = request.getAttribute(GSP_SITEMESH_PAGE); try { request.setAttribute(GSP_SITEMESH_PAGE, new GSPSitemeshPage()); GrailsContentBufferingResponse contentBufferingResponse = new GrailsContentBufferingResponse(response, contentProcessor, webAppContext); setDefaultConfiguredEncoding(request, contentBufferingResponse); chain.doFilter(request, contentBufferingResponse); // TODO: check if another servlet or filter put a page object in the request // Content result = request.getAttribute(PAGE); // if (result == null) { // // parse the page // result = pageResponse.getPage(); // } webAppContext.setUsingStream(contentBufferingResponse.isUsingStream()); return contentBufferingResponse.getContent(); } finally { if (oldGspSiteMeshPage != null) { request.setAttribute(GSP_SITEMESH_PAGE, oldGspSiteMeshPage); } } } private void setDefaultConfiguredEncoding(HttpServletRequest request, GrailsContentBufferingResponse contentBufferingResponse) { UrlPathHelper urlHelper = new UrlPathHelper(); String requestURI = urlHelper.getOriginatingRequestUri(request); // static content? if (requestURI.endsWith(HTML_EXT)) { contentBufferingResponse.setContentType("text/html;charset=" + defaultEncoding); } } private boolean filterAlreadyAppliedForRequest(HttpServletRequest request) { if (request.getAttribute(ALREADY_APPLIED_KEY) == Boolean.TRUE) { return true; } request.setAttribute(ALREADY_APPLIED_KEY, Boolean.TRUE); return false; } private void detectContentTypeFromPage(Content page, HttpServletResponse response) { String contentType = page.getProperty("meta.http-equiv.Content-Type"); if (contentType != null && "text/html".equals(response.getContentType())) { response.setContentType(contentType); } } private String getCurrentPageFromZKRequest(HttpServletRequest request) { String path = extractRequestPath(request); log.debug("current path = " + path); String currentPage = null; if (path.indexOf("/zkau") != -1) { // This is a asynchronous update (AU) call from ZK. There is no zul file in the path so we are going to assume // that the 'page' attribute in session scope is what we should set the current page for the // form context. log.debug("Current page is from the session since the call is through /zhau"); currentPage = (String) request.getSession().getAttribute("page"); } else { log.debug("Current page is coming from the path, since it is being driven from a ZUL."); currentPage = getPageName(path); } // As a last resort we are going to try to fetch the referer from the header since we couldn't find the // currentPage in the session attribute or the path. if (currentPage == null) { String refererURL = request.getHeader("Referer"); log.debug("Current page is still null, so we will inspect the referer which is equal to '" + refererURL + "'"); if (refererURL != null && refererURL.endsWith(".zul")) { currentPage = getPageName(refererURL); } } return currentPage; } private String getPageName(String uri) { // If the URI does not contain a .zul in it than it isn't considered a page and null is returned if (uri.indexOf("banner.zul") == -1) return null; if (uri.indexOf("banner.zul?page=") == -1) return "mainPage"; return getRequestParameter(uri, "page"); } private String getRequestParameter(String queryString, String parameter) { String paramValue = ""; if (queryString != null && !("".equals(queryString.trim()))) { int paramStartIndex = queryString.lastIndexOf(parameter + "="); if (paramStartIndex == -1) { return paramValue; } paramStartIndex += parameter.length() + 1; int paramValueEndIndex = queryString.indexOf('&', paramStartIndex); if (paramValueEndIndex == -1) { paramValueEndIndex = queryString.length(); } try { paramValue = queryString.substring(paramStartIndex, paramValueEndIndex); } catch (StringIndexOutOfBoundsException e) { // Nothing to be done. } } return paramValue; } public static ApplicationContext getApplicationContext() { return (ApplicationContext) ServletContextHolder.getServletContext() .getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT); } }