Java tutorial
/* * Copyright 2000-2011 Enonic AS * http://www.enonic.com/license */ package com.enonic.cms.server.service.portal.mvc.controller; import java.io.IOException; import java.io.OutputStream; import java.util.HashSet; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.enonic.cms.api.plugin.ext.http.HttpProcessor; import com.enonic.cms.api.plugin.ext.http.HttpResponseFilter; import com.enonic.cms.core.plugin.ExtensionManager; import com.enonic.cms.core.plugin.ExtensionManagerAccessor; import com.enonic.cms.domain.portal.PortalRenderingException; import org.apache.commons.lang.StringUtils; import org.joda.time.DateTime; import org.joda.time.Interval; import org.springframework.web.servlet.ModelAndView; import com.google.common.base.Preconditions; import com.enonic.esl.util.DigestUtil; import com.enonic.cms.framework.util.HttpCacheControlSettings; import com.enonic.cms.framework.util.HttpServletUtil; import com.enonic.cms.store.dao.SiteDao; import com.enonic.cms.store.dao.UserDao; import com.enonic.cms.business.SiteBasePathResolver; import com.enonic.cms.business.SitePropertiesService; import com.enonic.cms.business.SitePropertyNames; import com.enonic.cms.business.SiteRedirectAndForwardHelper; import com.enonic.cms.business.portal.rendering.tracing.RenderTrace; import com.enonic.cms.domain.Attribute; import com.enonic.cms.domain.SiteBasePath; import com.enonic.cms.domain.SiteBasePathAndSitePath; import com.enonic.cms.domain.SiteBasePathAndSitePathToStringBuilder; import com.enonic.cms.domain.SiteKey; import com.enonic.cms.domain.SitePath; import com.enonic.cms.domain.portal.PortalRequest; import com.enonic.cms.domain.portal.PortalResponse; import com.enonic.cms.domain.portal.RedirectInstruction; import com.enonic.cms.domain.security.user.User; import com.enonic.cms.domain.security.user.UserEntity; import com.enonic.cms.domain.structure.SiteEntity; /** * May 26, 2009 */ public class PortalRenderResponseServer { private final static String EXECUTED_PLUGINS = "EXECUTED_PLUGINS"; private static final int SECOND_IN_MILLIS = 1000; private SitePropertiesService sitePropertiesService; private SiteRedirectAndForwardHelper siteRedirectAndForwardHelper; private UserDao userDao; private SiteDao siteDao; public ModelAndView serveResponse(PortalRequest request, PortalResponse response, HttpServletResponse httpResponse, HttpServletRequest httpRequest) throws IOException { if (response.hasRedirectInstruction()) { return serveRedirect(response, httpResponse, httpRequest); } else if (response.isForwardToSitePath()) { return serveForwardToSitePathResponse(response, httpRequest); } else { return servePageResponse(request, response, httpResponse, httpRequest); } } private ModelAndView servePageResponse(PortalRequest request, PortalResponse response, HttpServletResponse httpResponse, HttpServletRequest httpRequest) throws IOException { HttpServletUtil.setDateHeader(httpResponse, request.getRequestTime().toDate()); final SitePath requestedPath = request.getSitePath(); final SiteKey requestedSiteKey = requestedPath.getSiteKey(); final UserEntity requester = userDao.findByKey(request.getRequester()); final SiteEntity site = siteDao.findByKey(requestedSiteKey); final boolean cacheHeadersEnabled = resolveCacheHeadersEnabledForSite(requestedSiteKey); boolean forceNoCache = false; if (isInPreviewMode(httpRequest) || RenderTrace.isTraceOn()) { forceNoCache = true; final DateTime expirationTime = request.getRequestTime(); setHttpCacheHeaders(requester, request.getRequestTime(), expirationTime, httpResponse, forceNoCache, site); } else if (cacheHeadersEnabled) { forceNoCache = resolveForceNoCacheForSite(requestedSiteKey); final DateTime expirationTime = resolveExpirationTime(request.getRequestTime(), response.getExpirationTime()); setHttpCacheHeaders(requester, request.getRequestTime(), expirationTime, httpResponse, forceNoCache, site); } // filter response with any response plugins String content = filterResponseWithPlugins(httpRequest, response.getContent(), response.getHttpContentType()); response.setContent(content); boolean handleEtagLogic = cacheHeadersEnabled && !forceNoCache; if (handleEtagLogic) { // Handling etag logic if cache headers are enabled if (StringUtils.isEmpty(content)) { httpResponse.setContentType(response.getHttpContentType()); writeContent(httpResponse, response.getContentAsBytes()); } else { final String etagFromContent = resolveEtag(content); final boolean contentIsModified = isContentModified(httpRequest, etagFromContent); if (contentIsModified) { HttpServletUtil.setEtag(httpResponse, etagFromContent); httpResponse.setContentType(response.getHttpContentType()); writeContent(httpResponse, response.getContentAsBytes()); } else { httpResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } else { httpResponse.setContentType(response.getHttpContentType()); writeContent(httpResponse, response.getContentAsBytes()); } return null; } private String resolveEtag(String content) { Preconditions.checkArgument(StringUtils.isNotEmpty(content)); return "content_" + DigestUtil.generateSHA(content); } private boolean isContentModified(HttpServletRequest req, String etagFromContent) { return HttpServletUtil.isContentModifiedAccordingToIfNoneMatchHeader(req, etagFromContent); } private void writeContent(HttpServletResponse httpResponse, byte[] content) throws IOException { httpResponse.setContentLength(content.length); OutputStream out = httpResponse.getOutputStream(); out.write(content); } private void setHttpCacheHeaders(final User requester, final DateTime requestTime, final DateTime expirationTime, final HttpServletResponse httpResponse, final boolean forceNoCache, final SiteEntity site) { final Interval maxAge = new Interval(requestTime, expirationTime); @SuppressWarnings({ "UnnecessaryLocalVariable" }) boolean notCachableByClient = forceNoCache; if (notCachableByClient) { HttpServletUtil.setCacheControlNoCache(httpResponse); } else { HttpCacheControlSettings cacheControlSettings = new HttpCacheControlSettings(); // To eliminate proxy caching of pages (decided by TSI) cacheControlSettings.publicAccess = false; boolean setCacheTimeToZero = dynamicResolversEnabled(site); if (setCacheTimeToZero) { cacheControlSettings.maxAgeSecondsToLive = new Long(0); HttpServletUtil.setExpiresHeader(httpResponse, requestTime.toDate()); } else { cacheControlSettings.maxAgeSecondsToLive = maxAge.toDurationMillis() / SECOND_IN_MILLIS; HttpServletUtil.setExpiresHeader(httpResponse, expirationTime.toDate()); } HttpServletUtil.setCacheControl(httpResponse, cacheControlSettings); } } private boolean dynamicResolversEnabled(SiteEntity site) { return site.isDeviceClassificationEnabled() || site.isLocalizationEnabled(); } private ModelAndView serveRedirect(PortalResponse response, HttpServletResponse httpResponse, HttpServletRequest httpRequest) throws IOException { RedirectInstruction redirectInstruction = response.getRedirectInstruction(); int redirectStatus = redirectInstruction.isPermanentRedirect() ? HttpServletResponse.SC_MOVED_PERMANENTLY : HttpServletResponse.SC_MOVED_TEMPORARILY; if (redirectInstruction.hasRedirectSitePath()) { return serveRedirectToSitePath(redirectInstruction.getRedirectSitePath(), redirectStatus, httpResponse, httpRequest); } else if (redirectInstruction.hasRedirectUrl()) { return serveRedirectResponse(redirectInstruction.getRedirectUrl()); } else { throw new IllegalStateException("Redirect must have target url or sitepath set"); } } private ModelAndView serveRedirectToSitePath(SitePath toSitePath, int redirectStatus, HttpServletResponse httpResponse, HttpServletRequest httpRequest) throws IOException { SiteBasePath siteBasePath = SiteBasePathResolver.resolveSiteBasePath(httpRequest, toSitePath.getSiteKey()); SiteBasePathAndSitePath siteBasePathAndSitePath = new SiteBasePathAndSitePath(siteBasePath, toSitePath); SiteBasePathAndSitePathToStringBuilder siteBasePathAndSitePathToStringBuilder = new SiteBasePathAndSitePathToStringBuilder(); siteBasePathAndSitePathToStringBuilder.setEncoding("UTF-8"); siteBasePathAndSitePathToStringBuilder.setHtmlEscapeParameterAmps(false); siteBasePathAndSitePathToStringBuilder.setIncludeFragment(true); siteBasePathAndSitePathToStringBuilder.setIncludeParamsInPath(true); siteBasePathAndSitePathToStringBuilder.setUrlEncodePath(true); String redirectUrl = siteBasePathAndSitePathToStringBuilder.toString(siteBasePathAndSitePath); String encodedRedirectUrl = httpResponse.encodeRedirectURL(redirectUrl); if (redirectStatus == HttpServletResponse.SC_MOVED_PERMANENTLY) { httpResponse.setStatus(redirectStatus); httpResponse.setHeader("Location", encodedRedirectUrl); return null; } else { httpResponse.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); httpResponse.setHeader("Location", encodedRedirectUrl); return null; } } private ModelAndView serveForwardToSitePathResponse(PortalResponse response, HttpServletRequest httpRequest) { return siteRedirectAndForwardHelper.getForwardModelAndView(httpRequest, response.getForwardToSitePath()); } private ModelAndView serveRedirectResponse(String redirectUrl) { return new ModelAndView("redirect:" + redirectUrl); } private DateTime resolveExpirationTime(DateTime requestTime, DateTime expirationTime) { if (expirationTime == null) { return requestTime; } if (expirationTime.isBefore(requestTime)) { return requestTime; } return expirationTime; } private String filterResponseWithPlugins(HttpServletRequest httpRequest, String response, String contentType) { try { ExtensionManager pluginManager = ExtensionManagerAccessor.getExtensionManager(); SitePath originalSitePath = (SitePath) httpRequest.getAttribute(Attribute.ORIGINAL_SITEPATH); @SuppressWarnings({ "unchecked" }) Set<HttpProcessor> executedPlugins = (Set<HttpProcessor>) httpRequest.getAttribute(EXECUTED_PLUGINS); if (executedPlugins == null) { executedPlugins = new HashSet<HttpProcessor>(); httpRequest.setAttribute(EXECUTED_PLUGINS, executedPlugins); } for (HttpResponseFilter plugin : pluginManager.findMatchingHttpResponseFilters(originalSitePath)) { if (!executedPlugins.contains(plugin)) { response = plugin.filterResponse(httpRequest, response, contentType); executedPlugins.add(plugin); } } return response; } catch (Exception e) { throw new PortalRenderingException("Response filter plugin failed: " + e.getMessage(), e); } } private boolean resolveCacheHeadersEnabledForSite(final SiteKey requestedSiteKey) { return sitePropertiesService.getPropertyAsBoolean(SitePropertyNames.PAGE_CACHE_HEADERS_ENABLED, requestedSiteKey); } private boolean resolveForceNoCacheForSite(final SiteKey requestedSiteKey) { return sitePropertiesService.getPropertyAsBoolean(SitePropertyNames.PAGE_CACHE_HEADERS_FORCENOCACHE, requestedSiteKey); } private boolean isInPreviewMode(HttpServletRequest httpRequest) { String previewEnabled = (String) httpRequest.getAttribute(Attribute.PREVIEW_ENABLED); return "true".equals(previewEnabled); } public void setSitePropertiesService(SitePropertiesService sitePropertiesService) { this.sitePropertiesService = sitePropertiesService; } public void setSiteRedirectAndForwardHelper(SiteRedirectAndForwardHelper siteRedirectAndForwardHelper) { this.siteRedirectAndForwardHelper = siteRedirectAndForwardHelper; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void setSiteDao(SiteDao siteDao) { this.siteDao = siteDao; } }