Java tutorial
/* * Copyright (C) 2007-2013 Crafter Software Corporation. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.craftercms.engine.view; import java.util.ArrayList; import java.util.List; import java.util.Locale; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.craftercms.commons.http.RequestContext; import org.craftercms.commons.lang.Callback; import org.craftercms.core.service.CachingOptions; import org.craftercms.core.util.cache.CacheTemplate; import org.craftercms.engine.mobile.UserAgentTemplateDetector; import org.craftercms.engine.model.SiteItem; import org.craftercms.engine.scripting.Script; import org.craftercms.engine.scripting.ScriptFactory; import org.craftercms.engine.scripting.SiteItemScriptResolver; import org.craftercms.engine.security.CrafterPageAccessManager; import org.craftercms.engine.service.SiteItemService; import org.craftercms.engine.service.UrlTransformationService; import org.craftercms.engine.service.context.SiteContext; import org.craftercms.engine.properties.SiteProperties; import org.springframework.beans.factory.annotation.Required; import org.springframework.core.Ordered; import org.springframework.web.context.support.WebApplicationObjectSupport; import org.springframework.web.servlet.View; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.view.RedirectView; import org.springframework.web.servlet.view.UrlBasedViewResolver; /** * {@link org.springframework.web.servlet.ViewResolver} that resolves to {@link CrafterPageView}s. This resolver * retrieves the Crafter page from the content store and searches in the page DOM for the actual view name. The * returned {@link CrafterPageView} then adds the page and the site navigation to the model, obtains the actual * page view name from the delegated view resolver and delegates rendering to that view. * * @author Alfonso Vasquez */ public class CrafterPageViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered { private static final String PAGE_CONST_KEY_ELEM = "page"; private static final Log logger = LogFactory.getLog(CrafterPageViewResolver.class); protected int order; protected boolean cacheUrlTransformations; protected String renderUrlToStoreUrlTransformerName; protected String storeUrlToRenderUrlTransformerName; protected String toFullHttpsUrlTransformerName; protected UrlTransformationService urlTransformationService; protected CacheTemplate cacheTemplate; protected CachingOptions cachingOptions; protected SiteItemService siteItemService; protected String pageViewNameXPathQuery; protected String redirectUrlXPathQuery; protected String contentTypeXPathQuery; protected String redirectContentType; protected String disabledXPathQuery; protected String mimeTypeXPathQuery; protected String forceHttpsXPathQuery; protected SiteItemScriptResolver scriptResolver; protected ViewResolver delegatedViewResolver; protected UserAgentTemplateDetector userAgentTemplateDetector; protected CrafterPageAccessManager accessManager; public CrafterPageViewResolver() { order = 10; cachingOptions = CachingOptions.DEFAULT_CACHING_OPTIONS; } @Override public int getOrder() { return order; } public void setOrder(int order) { this.order = order; } public void setCacheUrlTransformations(boolean cacheUrlTransformations) { this.cacheUrlTransformations = cacheUrlTransformations; } @Required public void setRenderUrlToStoreUrlTransformerName(String renderUrlToStoreUrlTransformerName) { this.renderUrlToStoreUrlTransformerName = renderUrlToStoreUrlTransformerName; } @Required public void setStoreUrlToRenderUrlTransformerName(String storeUrlToRenderUrlTransformerName) { this.storeUrlToRenderUrlTransformerName = storeUrlToRenderUrlTransformerName; } @Required public void setToFullHttpsUrlTransformerName(String toFullHttpsUrlTransformerName) { this.toFullHttpsUrlTransformerName = toFullHttpsUrlTransformerName; } @Required public void setUrlTransformationService(UrlTransformationService urlTransformationService) { this.urlTransformationService = urlTransformationService; } @Required public void setCacheTemplate(CacheTemplate cacheTemplate) { this.cacheTemplate = cacheTemplate; } public void setCachingOptions(CachingOptions cachingOptions) { this.cachingOptions = cachingOptions; } @Required public void setSiteItemService(SiteItemService siteItemService) { this.siteItemService = siteItemService; } @Required public void setPageViewNameXPathQuery(String pageViewNameXPathQuery) { this.pageViewNameXPathQuery = pageViewNameXPathQuery; } @Required public void setRedirectUrlXPathQuery(String redirectUrlXPathQuery) { this.redirectUrlXPathQuery = redirectUrlXPathQuery; } @Required public void setContentTypeXPathQuery(String contentTypeXPathQuery) { this.contentTypeXPathQuery = contentTypeXPathQuery; } @Required public void setRedirectContentType(String redirectContentType) { this.redirectContentType = redirectContentType; } @Required public void setDisabledXPathQuery(String disabledXPathQuery) { this.disabledXPathQuery = disabledXPathQuery; } @Required public void setMimeTypeXPathQuery(String mimeTypeXPathQuery) { this.mimeTypeXPathQuery = mimeTypeXPathQuery; } @Required public void setScriptResolver(SiteItemScriptResolver scriptResolver) { this.scriptResolver = scriptResolver; } @Required public void setForceHttpsXPathQuery(String forceHttpsXPathQuery) { this.forceHttpsXPathQuery = forceHttpsXPathQuery; } @Required public void setDelegatedViewResolver(ViewResolver delegatedViewResolver) { this.delegatedViewResolver = delegatedViewResolver; } @Required public void setUserAgentTemplateDetector(UserAgentTemplateDetector userAgentTemplateDetector) { this.userAgentTemplateDetector = userAgentTemplateDetector; } @Required public void setAccessManager(CrafterPageAccessManager accessManager) { this.accessManager = accessManager; } @Override public View resolveViewName(String renderUrl, Locale locale) throws Exception { String storeUrl = urlTransformationService.transform(renderUrlToStoreUrlTransformerName, renderUrl, cacheUrlTransformations); View view = getCachedLocalizedView(storeUrl, locale); if (view != null && view instanceof CrafterPageView) { CrafterPageView pageView = (CrafterPageView) view; if (SiteProperties.isRedirectToTargetedUrl()) { String finalStoreUrl = pageView.getPage().getStoreUrl(); String finalRenderUrl = urlTransformationService.transform(storeUrlToRenderUrlTransformerName, finalStoreUrl, cacheUrlTransformations); renderUrl = FilenameUtils.normalizeNoEndSeparator(renderUrl); finalRenderUrl = FilenameUtils.normalizeNoEndSeparator(finalRenderUrl); if (!renderUrl.equals(finalRenderUrl)) { return getRedirectView(finalRenderUrl, true); } } accessManager.checkAccess(pageView.getPage()); } return view; } protected SiteItem getPage(String url) { SiteItem page = siteItemService.getSiteItem(url); if (page == null) { if (logger.isDebugEnabled()) { logger.debug("Crafter page descriptor not found at " + url); } } return page; } protected View getRedirectView(String redirectUrl, boolean relative) { View view = new RedirectView(redirectUrl, relative, true); return applyLifecycleMethods(UrlBasedViewResolver.REDIRECT_URL_PREFIX + redirectUrl, view); } protected View getCurrentPageHttpsRedirectView() { String currentUrl = RequestContext.getCurrent().getRequest().getRequestURI(); String fullHttpsUrl = urlTransformationService.transform(toFullHttpsUrlTransformerName, currentUrl); return getRedirectView(fullHttpsUrl, false); } protected View getCachedLocalizedView(final String url, final Locale locale) { final SiteContext siteContext = SiteContext.getCurrent(); if (siteContext != null) { return cacheTemplate.getObject(siteContext.getContext(), cachingOptions, () -> { SiteItem page = getPage(url); if (page != null) { String redirectUrl = page.getItem().queryDescriptorValue(redirectUrlXPathQuery); String contentType = page.getItem().queryDescriptorValue(contentTypeXPathQuery); String forceHttps = page.getItem().queryDescriptorValue(forceHttpsXPathQuery); if (StringUtils.isNotEmpty(contentType) && StringUtils.equalsIgnoreCase(redirectContentType, contentType) && StringUtils.isNotEmpty(redirectUrl)) { if (logger.isDebugEnabled()) { logger.debug("Redirecting page @ " + url + " to URL " + redirectUrl); } return getRedirectView(redirectUrl, true); } else if (StringUtils.isNotEmpty(forceHttps) && Boolean.parseBoolean(forceHttps)) { if (logger.isDebugEnabled()) { logger.debug("Forcing HTTPS on page @ " + url); } return getCurrentPageHttpsRedirectView(); } else { UserAgentAwareCrafterPageView view = new UserAgentAwareCrafterPageView(); view.setServletContext(getServletContext()); view.setPage(page); view.setLocale(locale); view.setSiteItemService(siteItemService); view.setPageViewNameXPathQuery(pageViewNameXPathQuery); view.setMimeTypeXPathQuery(mimeTypeXPathQuery); view.setDelegatedViewResolver(delegatedViewResolver); view.setUserAgentTemplateDetector(userAgentTemplateDetector); loadScripts(siteContext.getScriptFactory(), page, view); view.addDependencyKey(page.getItem().getKey()); return applyLifecycleMethods(page.getStoreUrl(), view); } } else { // Return null to continue with the ViewResolverChain return null; } }, url, locale, PAGE_CONST_KEY_ELEM); } else { // Return null to continue with the ViewResolverChain return null; } } protected void loadScripts(ScriptFactory scriptFactory, SiteItem page, CrafterPageView view) { if (scriptFactory != null) { List<String> scriptUrls = scriptResolver.getScriptUrls(page); if (CollectionUtils.isNotEmpty(scriptUrls)) { if (logger.isDebugEnabled()) { logger.debug("Scripts associated to page " + page.getStoreUrl() + ": " + scriptUrls); } List<Script> scripts = new ArrayList<Script>(scriptUrls.size()); for (String scriptUrl : scriptUrls) { Script script = scriptFactory.getScript(scriptUrl); scripts.add(script); view.addDependencyKey(script.getKey()); } view.setScripts(scripts); } } } protected View applyLifecycleMethods(String viewName, View view) { return (View) getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, viewName); } }