/* =============================================================================== * * Part of the InfoGlue Content Management Platform (www.infoglue.org) * * =============================================================================== * * Copyright (C) * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2, as published by the * Free Software Foundation. See the file LICENSE.html for more information. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY, including 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, write to the Free Software Foundation, Inc. / 59 Temple * Place, Suite 330 / Boston, MA 02111-1307 / USA. * * =============================================================================== */ package org.infoglue.deliver.invokers; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.zip.GZIPOutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.exolab.castor.jdo.Database; import org.infoglue.cms.applications.common.VisualFormatter; import org.infoglue.cms.controllers.kernel.impl.simple.ContentVersionController; import org.infoglue.cms.controllers.kernel.impl.simple.PageDeliveryMetaDataController; import org.infoglue.cms.controllers.kernel.impl.simple.RepositoryController; import org.infoglue.cms.entities.content.ContentVersionVO; import org.infoglue.cms.entities.content.SmallestContentVersionVO; import org.infoglue.cms.entities.management.LanguageVO; import org.infoglue.cms.entities.management.PageDeliveryMetaDataEntityVO; import org.infoglue.cms.entities.management.PageDeliveryMetaDataVO; import org.infoglue.cms.entities.management.RepositoryVO; import org.infoglue.cms.entities.structure.SiteNode; import org.infoglue.cms.entities.structure.SiteNodeVO; import org.infoglue.cms.exception.Bug; import org.infoglue.cms.exception.NoBaseTemplateFoundException; import org.infoglue.cms.exception.SystemException; import org.infoglue.cms.io.FileHelper; import org.infoglue.cms.util.CmsPropertyHandler; import org.infoglue.deliver.applications.databeans.DatabaseWrapper; import org.infoglue.deliver.applications.databeans.DeliveryContext; import org.infoglue.deliver.cache.PageCacheHelper; import org.infoglue.deliver.controllers.kernel.URLComposer; import org.infoglue.deliver.controllers.kernel.impl.simple.LanguageDeliveryController; import org.infoglue.deliver.controllers.kernel.impl.simple.NodeDeliveryController; import org.infoglue.deliver.controllers.kernel.impl.simple.TemplateController; import org.infoglue.deliver.portal.PortalController; import org.infoglue.deliver.util.CacheController; import org.infoglue.deliver.util.CompressionHelper; import org.infoglue.deliver.util.JSMin; import org.infoglue.deliver.util.RequestAnalyser; import org.infoglue.deliver.util.Timer; /** * @author Mattias Bogeblad * * This interface defines what a Invoker of a page have to be able to do. * The invokers are used to deliver a page to the user in a certain fashion. * */ public abstract class PageInvoker { private final static Logger logger = Logger.getLogger(PageInvoker.class.getName()); private static CompressionHelper compressionHelper = new CompressionHelper(); private final static VisualFormatter vf = new VisualFormatter(); private DatabaseWrapper dbWrapper = null; private HttpServletRequest request = null; private HttpServletResponse response = null; private TemplateController templateController = null; private DeliveryContext deliveryContext = null; private String pageString = null; /*public PageInvoker() { } */ /** * The default constructor for PageInvokers. * @param request * @param response * @param templateController * @param deliveryContext */ /* public PageInvoker(HttpServletRequest request, HttpServletResponse response, TemplateController templateController, DeliveryContext deliveryContext) { this.request = request; this.response = response; this.templateController = templateController; this.deliveryContext = deliveryContext; this.templateController.setDeliveryContext(this.deliveryContext); } */ /** * This method should return an instance of the class that should be used for page editing inside the tools or in working. * Makes it possible to have an alternative to the ordinary delivery optimized class. */ public abstract PageInvoker getDecoratedPageInvoker(TemplateController templateController, DeliveryContext deliveryContext) throws SystemException; /** * The default initializer for PageInvokers. * @param request * @param response * @param templateController * @param deliveryContext */ public void setParameters(DatabaseWrapper dbWrapper, HttpServletRequest request, HttpServletResponse response, TemplateController templateController, DeliveryContext deliveryContext) { this.dbWrapper = dbWrapper; this.request = request; this.response = response; this.templateController = templateController; this.deliveryContext = deliveryContext; this.templateController.setDeliveryContext(this.deliveryContext); } public Database getDatabase() throws SystemException { /* if(this.db == null || this.db.isClosed() || !this.db.isActive()) { beginTransaction(); } */ return dbWrapper.getDatabase(); } /** * This is the method that will deliver the page to the user. It can have special * handling of all sorts to enable all sorts of handlers. An example of uses might be to * be to implement a WAP-version of page delivery where you have to set certain headers in the response * or a redirect page which just redirects you to another page. */ public abstract void invokePage() throws SystemException, Exception; /** * This method is used to send the page out to the browser or other device. * Override this if you need to set other headers or do other specialized things. */ public void deliverPage() throws NoBaseTemplateFoundException, Exception { if(logger.isInfoEnabled()) { logger.info("PageKey:" + this.getDeliveryContext().getPageKey()); logger.info("PageCache:" + this.getDeliveryContext().getDisablePageCache()); } LanguageVO languageVO = LanguageDeliveryController.getLanguageDeliveryController().getLanguageVO(getDatabase(), this.getTemplateController().getLanguageId()); if(logger.isInfoEnabled()) logger.info("languageVO:" + languageVO); if(languageVO == null) throw new SystemException("There was no such active language for the page with languageId:" + this.getTemplateController().getLanguageId()); String isPageCacheOn = CmsPropertyHandler.getIsPageCacheOn(); String refresh = this.getRequest().getParameter("refresh"); String pageCacheName = "pageCache"; // + this.getTemplateController().getRepositoryId(); String pageCacheExtraName = "pageCacheExtra"; // + this.getTemplateController().getRepositoryId(); if(logger.isInfoEnabled()) logger.info("isPageCacheOn:" + isPageCacheOn); if(isPageCacheOn.equalsIgnoreCase("true") && (refresh == null || !refresh.equalsIgnoreCase("true")) && getRequest().getMethod().equals("GET")) { Map cachedExtraData = null; Integer pageCacheTimeout = (Integer)CacheController.getCachedObjectFromAdvancedCache("pageCacheExtra", this.getDeliveryContext().getPageKey() + "_pageCacheTimeout"); if(pageCacheTimeout == null) pageCacheTimeout = this.getTemplateController().getPageCacheTimeout(); if(pageCacheTimeout != null && pageCacheTimeout > 0) { Object pageCacheFileName = CacheController.getCachedObjectFromAdvancedCache(pageCacheName, this.getDeliveryContext().getPageKey(), pageCacheTimeout.intValue(), false, "utf-8", false); if(pageCacheFileName == null || pageCacheFileName.equals("")) { PageCacheHelper.getInstance().clearPageCacheASAP(this.getDeliveryContext().getPageKey()); } } Class[] argsClasses = new Class[2]; argsClasses[0] = String.class; argsClasses[1] = String.class; Object[] args = new Object[]{pageCacheName, pageCacheExtraName}; this.pageString = (String)CacheController.getCachedObjectFromAdvancedCache(pageCacheName, this.getDeliveryContext().getPageKey(), true, "utf-8", true, this, this.getClass().getMethod("invokeAndDecoratePage", argsClasses), args, this); cachedExtraData = (Map)CacheController.getCachedObjectFromAdvancedCache(pageCacheExtraName, this.getDeliveryContext().getPageKey()); if(this.pageString != null) this.getDeliveryContext().setIsCachedResponse(true); logger.info("this.getDeliveryContext().getIsCachedResponse():" + this.getDeliveryContext().getIsCachedResponse()); if(this.getDeliveryContext().getIsCachedResponse()) { String usedEntitiesString = null; if(CmsPropertyHandler.getOperatingMode().equals("0")) { usedEntitiesString = (String)CacheController.getCachedObjectFromAdvancedCache("pageCacheExtra", this.getDeliveryContext().getPageKey() + "_entitiesAsByte"); } else { byte[] usedEntitiesByteArray = (byte[])CacheController.getCachedObjectFromAdvancedCache("pageCacheExtra", this.getDeliveryContext().getPageKey() + "_entitiesAsByte"); if(usedEntitiesByteArray != null) usedEntitiesString = compressionHelper.decompress(usedEntitiesByteArray); } if(logger.isInfoEnabled()) logger.info("usedEntitiesString:" + usedEntitiesString); if(usedEntitiesString != null) { String[] usedEntities = StringUtils.split(usedEntitiesString, "|"); for(String usedEntity : usedEntities) { if(usedEntity.startsWith("content_")) this.getDeliveryContext().addUsedContent(usedEntity); else if(usedEntity.startsWith("contentVersion_")) this.getDeliveryContext().addUsedContentVersion(usedEntity); else if(usedEntity.startsWith("siteNode_")) this.getDeliveryContext().addUsedSiteNode(usedEntity); else if(usedEntity.startsWith("siteNodeVersion_")) this.getDeliveryContext().addUsedSiteNodeVersion(usedEntity); } } } getLastModifiedDateTime(true); if(cachedExtraData != null) this.getDeliveryContext().populateExtraData(cachedExtraData); //Caching the pagePath this.getDeliveryContext().setPagePath((String)CacheController.getCachedObject("pagePathCache", this.getDeliveryContext().getPageKey())); if(this.getDeliveryContext().getPagePath() == null) { this.getDeliveryContext().setPagePath(this.getTemplateController().getCurrentPagePath()); if(!this.getTemplateController().getIsPageCacheDisabled() && !this.getDeliveryContext().getDisablePageCache()) //Caching page path if not disabled CacheController.cacheObject("pagePathCache", this.getDeliveryContext().getPageKey(), this.getDeliveryContext().getPagePath()); } if(logger.isInfoEnabled()) logger.info("Done caching the pagePath..."); } else { invokePage(); this.pageString = getPageString(); //TEST getLastModifiedDateTime(false); //END TEST pageString = decorateHeadAndPageWithVarsFromComponents(pageString); this.getDeliveryContext().setPagePath(this.templateController.getCurrentPagePath()); } if(this.getRequest().getParameter("includeUsedEntities") != null && this.getRequest().getParameter("includeUsedEntities").equals("true") && (!CmsPropertyHandler.getOperatingMode().equals("3") || CmsPropertyHandler.getLivePublicationThreadClass().equalsIgnoreCase("org.infoglue.deliver.util.SelectiveLivePublicationThread"))) { StringBuilder sb = new StringBuilder("<usedEntities>"); String[] usedEntities = this.getDeliveryContext().getAllUsedEntities(); for(int i=0; i<usedEntities.length; i++) sb.append(usedEntities[i]).append(","); sb.append("</usedEntities>"); if(this.getTemplateController().getPageContentType() != null && (this.getTemplateController().getPageContentType().equalsIgnoreCase("text/css") || this.getTemplateController().getPageContentType().equalsIgnoreCase("text/javascript"))) this.pageString = this.pageString + "/*" + sb.toString() + "*/"; else this.pageString = this.pageString + "<!--" + sb.toString() + "-->"; } String contentType = this.getTemplateController().getPageContentType(); if(this.deliveryContext.getContentType() != null && !contentType.equalsIgnoreCase(this.deliveryContext.getContentType())) contentType = this.deliveryContext.getContentType(); if(!CmsPropertyHandler.getOperatingMode().equals("3")) { getResponse().setHeader("Cache-Control","no-cache"); getResponse().setHeader("Pragma","no-cache"); getResponse().setDateHeader ("Expires", 0); } //logger.info("pageString before:" + pageString); //pageString = decorateHeadAndPageWithVarsFromComponents(pageString); //logger.info("pageString after:" + pageString); try { //logger.info("ContentType:" + contentType); String charSet = languageVO.getCharset(); if(contentType.indexOf("charset=") > -1) { try { int startIndex = contentType.indexOf("charset="); int endIndex = contentType.indexOf(";", startIndex + 1); if(endIndex != -1) charSet = contentType.substring(startIndex + "charset=".length(), endIndex).trim(); else charSet = contentType.substring(startIndex + "charset=".length()).trim(); if(logger.isInfoEnabled()) logger.info("Found a user defined charset: " + charSet); } catch(Exception e) { logger.warn("Error parsing charset:" + e.getMessage()); } this.getResponse().setContentType(contentType); } else this.getResponse().setContentType(contentType + "; charset=" + languageVO.getCharset()); if(logger.isInfoEnabled()) logger.info("Using charset: " + charSet); Iterator headersIterator = this.getDeliveryContext().getHttpHeaders().keySet().iterator(); while(headersIterator.hasNext()) { String key = (String)headersIterator.next(); Object valueObject = this.getDeliveryContext().getHttpHeaders().get(key); if(valueObject instanceof Date) { Date value = (Date)valueObject; this.getResponse().setDateHeader(key, value.getTime()); } else { String value = (String)valueObject; this.getResponse().setHeader(key, value); } } if(logger.isInfoEnabled()) logger.info("contentType:" + contentType + "; charset=" + languageVO.getCharset()); String compressPageResponse = CmsPropertyHandler.getCompressPageResponse(); if(logger.isInfoEnabled()) logger.info("compressPageResponse:" + compressPageResponse); if(compressPageResponse != null && compressPageResponse.equalsIgnoreCase("true")) { OutputStream out = null; String encodings = this.getRequest().getHeader("Accept-Encoding"); if (encodings != null && encodings.indexOf("gzip") != -1) { this.getResponse().setHeader("Content-Encoding", "gzip"); out = new GZIPOutputStream(this.getResponse().getOutputStream()); } else if (encodings != null && encodings.indexOf("compress") != -1) { this.getResponse().setHeader("Content-Encoding", "x-compress"); out = new ZipOutputStream(this.getResponse().getOutputStream()); ((ZipOutputStream)out).putNextEntry(new ZipEntry("dummy name")); } else { out = this.getResponse().getOutputStream(); } if(pageString != null) out.write(pageString.getBytes(charSet)); else out.write("Error: got null pagestring".getBytes(charSet)); out.flush(); out.close(); } else { PrintWriter out = this.getResponse().getWriter(); out.println(pageString); out.flush(); out.close(); } if(logger.isInfoEnabled()) logger.info("sent all data to client:" + pageString.length()); } catch(IllegalStateException e) { logger.error("There was an IllegalStateException when trying to write output for URL: " + this.getTemplateController().getOriginalFullURL() + "\nMessage: " + e.getMessage()); } //New solution which enables us to defeat individual page caches in flow. try { String pageKey = this.getDeliveryContext().getPageKey(); if(logger.isInfoEnabled()) logger.info("pageKey:" + pageKey); if(refresh != null && refresh.equalsIgnoreCase("true")) { String originalQueryString = this.getDeliveryContext().getOriginalQueryString(); logger.info("originalQueryString:" + originalQueryString); logger.info("Clearing page cache...."); if(originalQueryString.equalsIgnoreCase("refresh=true")) pageKey = pageKey.replaceFirst("refresh=true","null"); else if(originalQueryString.indexOf("&refresh=true") > -1) pageKey = pageKey.replaceFirst("&refresh=true",""); else if(originalQueryString.indexOf("refresh=true&") == 0) pageKey = pageKey.replaceFirst("refresh=true&",""); logger.info("pageKey:" + pageKey); //Timer t = new Timer(); CacheController.clearPageCache(pageKey); //t.printElapsedTime("Clearing page cache took..."); //CacheController.clearCaches(SiteNodeImpl.class.getName(), "" + this.getTemplateController().getSiteNodeId(), null); //t.printElapsedTime("Clearing caches took..."); } } catch (Exception e) { logger.error("Could not clear the pagecache:" + e.getMessage()); } } public String invokeAndDecoratePage(String pageCacheName, String pageCacheExtraName) throws SystemException, Exception, Bug { if(this.pageString == null) { invokePage(); this.pageString = getPageString(); //TEST getLastModifiedDateTime(false); //END TEST this.pageString = decorateHeadAndPageWithVarsFromComponents(pageString); } else { if(logger.isInfoEnabled()) logger.info("There was a cached copy..."); // + pageString); } return this.pageString; } private void getLastModifiedDateTime(boolean useContentLookup) throws Bug { //if(CmsPropertyHandler.getOperatingMode().equals("3") && CmsPropertyHandler.getSetDerivedLastModifiedInLive().equalsIgnoreCase("false")) // return; //Integer maxNumberOfVersionsForDerivedLastModifiedInLive = CmsPropertyHandler.getMaxNumberOfVersionsForDerivedLastModifiedInLive(); Date lastModifiedDateTime = null; logger.info("useContentLookup:" + useContentLookup); logger.info("UsedContentVersions:" + this.deliveryContext.getUsedContentVersions().size()); logger.info("UsedContents:" + this.deliveryContext.getUsedContents().size()); if(this.deliveryContext.getUsedContents().size() > 1000 && CmsPropertyHandler.getOperatingMode().equals("0")) logger.warn("The page " + this.deliveryContext.getSiteNodeId() + "(" + this.deliveryContext.getOriginalFullURL() + ") has unhealthy number of relations"); Timer t = new Timer(); if(this.deliveryContext.getUsedContentVersions().size() > 0 || (useContentLookup && this.deliveryContext.getUsedContents().size() > 0)) { try { SmallestContentVersionVO lastContentVersionVO = null; if(useContentLookup) lastContentVersionVO = ContentVersionController.getContentVersionController().getLatestContentVersionVOByContentIds(this.deliveryContext.getUsedContents(), getDatabase()); else lastContentVersionVO = ContentVersionController.getContentVersionController().getLatestContentVersionVO(this.deliveryContext.getUsedContentVersions(), getDatabase()); logger.info("lastContentVersionVO:" + lastContentVersionVO); if(lastContentVersionVO != null) lastModifiedDateTime = lastContentVersionVO.getModifiedDateTime(); logger.info("lastModifiedDateTime from cvVO:" + lastContentVersionVO.getModifiedDateTime()); } catch (Exception e) { e.printStackTrace(); } /* Iterator userContentVersionIterator = this.deliveryContext.getUsedContentVersions().iterator(); int processed = 0; while(userContentVersionIterator.hasNext()) { String usedContentVersion = (String)userContentVersionIterator.next(); if(usedContentVersion != null && usedContentVersion.startsWith("contentVersion_")) { try { String versionId = usedContentVersion.substring(15); if(!versionId.equals("null") && !versionId.equals("")) { processed++; Integer contentVersionId = new Integer(versionId); //SmallestContentVersionVO contentVersion = ContentVersionController.getContentVersionController().getSmallestContentVersionVOWithId(contentVersionId, getDatabase()); ContentVersionVO contentVersion = ContentVersionController.getContentVersionController().getSmallContentVersionVOWithId(contentVersionId, getDatabase()); if(lastModifiedDateTime == null || contentVersion.getModifiedDateTime().after(lastModifiedDateTime)) { lastModifiedDateTime = contentVersion.getModifiedDateTime(); System.out.println("lastModifiedDateTime:" + lastModifiedDateTime); } } } catch (Exception e) { logger.warn("Could not use the versionId:" + usedContentVersion + " - reason:" + e.getMessage()); } } if(lastModifiedDateTime != null) { long current = System.currentTimeMillis() - lastModifiedDateTime.getTime(); if(processed > maxNumberOfVersionsForDerivedLastModifiedInLive || current < (1000 * 60 * 10)) break; } } */ if(lastModifiedDateTime != null) { logger.info("The page gets " + lastModifiedDateTime); this.deliveryContext.setLastModifiedDateTime(lastModifiedDateTime); } } long elapsedTime = t.getElapsedTime(); RequestAnalyser.getRequestAnalyser().registerComponentStatistics("getLastModifiedDateTime", elapsedTime); } protected String decorateHeadAndPageWithVarsFromComponents(String pageString) { pageString = this.getTemplateController().decoratePage(pageString); StringBuilder sb = null; Timer t = new Timer(); this.generateExtensionBundles(this.getTemplateController().getDeliveryContext().getScriptExtensionHeadBundles(), "text/javascript", "head"); this.generateExtensionBundles(this.getTemplateController().getDeliveryContext().getScriptExtensionBodyBundles(), "text/javascript", "body"); this.generateExtensionBundles(this.getTemplateController().getDeliveryContext().getCSSExtensionBundles(), "text/css", "head"); List htmlHeadItems = this.getTemplateController().getDeliveryContext().getHtmlHeadItems(); if(htmlHeadItems != null && htmlHeadItems.size() > 0) { int indexOfHeadEndTag = pageString.indexOf("</head"); if(indexOfHeadEndTag == -1) indexOfHeadEndTag = pageString.indexOf("</HEAD"); if(indexOfHeadEndTag != -1) { sb = new StringBuilder(pageString); String headerItems = ""; Iterator htmlHeadItemsIterator = htmlHeadItems.iterator(); while(htmlHeadItemsIterator.hasNext()) { String value = (String)htmlHeadItemsIterator.next(); //logger.info("headItem:" + value); headerItems = headerItems + value + "\n"; } sb.insert(indexOfHeadEndTag, headerItems); //pageString = sb.toString(); } } List<String> htmlBodyEndItems = this.getTemplateController().getDeliveryContext().getHtmlBodyEndItems(); if(htmlBodyEndItems != null && htmlBodyEndItems.size() > 0) { if(sb == null) sb = new StringBuilder(pageString); int indexOfBodyEndTag = sb.indexOf("</body"); if(indexOfBodyEndTag == -1) indexOfBodyEndTag = sb.indexOf("</BODY"); if(indexOfBodyEndTag != -1) { String bodyItems = ""; Iterator htmlBodyItemsIterator = htmlBodyEndItems.iterator(); while(htmlBodyItemsIterator.hasNext()) { String value = (String)htmlBodyItemsIterator.next(); //logger.info("headItem:" + value); bodyItems = bodyItems + value + "\n"; } sb.insert(indexOfBodyEndTag, bodyItems); //pageString = sb.toString(); } } RequestAnalyser.getRequestAnalyser().registerComponentStatistics("pageInvoker", t.getElapsedTime()); try { int lastModifiedDateTimeIndex; if(sb == null) lastModifiedDateTimeIndex = pageString.indexOf("<ig:lastModifiedDateTime"); else lastModifiedDateTimeIndex = sb.indexOf("<ig:lastModifiedDateTime"); //logger.info("OOOOOOOOOOOOO lastModifiedDateTimeIndex:" + lastModifiedDateTimeIndex); if(lastModifiedDateTimeIndex > -1) { if(sb == null) sb = new StringBuilder(pageString); int lastModifiedDateTimeEndIndex = sb.indexOf("</ig:lastModifiedDateTime>", lastModifiedDateTimeIndex); String tagInfo = sb.substring(lastModifiedDateTimeIndex, lastModifiedDateTimeEndIndex); //logger.info("tagInfo:" + tagInfo); String dateFormat = "yyyy-MM-dd HH:mm"; int formatStartIndex = tagInfo.indexOf("format"); if(formatStartIndex > -1) { int formatEndIndex = tagInfo.indexOf("\"", formatStartIndex + 8); if(formatEndIndex > -1) dateFormat = tagInfo.substring(formatStartIndex + 8, formatEndIndex); } //logger.info("dateFormat:" + dateFormat); String dateString = vf.formatDate(this.getTemplateController().getDeliveryContext().getLastModifiedDateTime(), this.getTemplateController().getLocale(), dateFormat); //logger.info("dateString:" + dateString); sb.replace(lastModifiedDateTimeIndex, lastModifiedDateTimeEndIndex + "</ig:lastModifiedDateTime>".length(), dateString); //logger.info("Replaced:" + lastModifiedDateTimeIndex + " to " + lastModifiedDateTimeEndIndex + "</ig:lastModifiedDateTime>".length() + " with " + dateString); } } catch (Exception e) { logger.error("Problem setting lastModifiedDateTime:" + e.getMessage(), e); } if(sb != null) pageString = sb.toString(); return pageString; } private void generateExtensionBundles(Map<String,Set<String>> extensionBundles, String contentType, String targetElement) { Timer t = new Timer(); Set<String> bundledSignatures = new HashSet<String>(); Iterator<String> scriptExtensionBundlesIterator = extensionBundles.keySet().iterator(); while(scriptExtensionBundlesIterator.hasNext()) { String bundleName = scriptExtensionBundlesIterator.next(); if(logger.isInfoEnabled()) logger.info("bundleName:" + bundleName); Set<String> scriptExtensionFileNames = extensionBundles.get(bundleName); if(scriptExtensionFileNames != null && scriptExtensionFileNames.size() > 0) { String scriptBundle = ""; int i = 0; String filePath = CmsPropertyHandler.getDigitalAssetPath0(); while(filePath != null) { try { File extensionsDirectory = new File(filePath + File.separator + "extensions"); extensionsDirectory.mkdirs(); File extensionsBundleFile = new File(filePath + File.separator + "extensions" + File.separator + bundleName + ".js"); if(contentType.equalsIgnoreCase("text/css")) extensionsBundleFile = new File(filePath + File.separator + "extensions" + File.separator + bundleName + ".css"); if(!extensionsBundleFile.exists()) { if(logger.isInfoEnabled()) logger.info("No script - generating:" + bundleName); if(scriptBundle.equals("")) { Iterator<String> scriptExtensionFileNamesIterator = scriptExtensionFileNames.iterator(); while(scriptExtensionFileNamesIterator.hasNext()) { String scriptExtensionFileName = scriptExtensionFileNamesIterator.next(); if(logger.isInfoEnabled()) logger.info("scriptExtensionFileName:" + scriptExtensionFileName); try { File file = new File(filePath + File.separator + scriptExtensionFileName); String signature = "" + file.getName() + "_" + file.length(); if(logger.isInfoEnabled()) logger.info("Checking file:" + filePath + File.separator + scriptExtensionFileName); if(file.exists() && !bundledSignatures.contains(signature)) { StringBuffer content = new StringBuffer(FileHelper.getFileAsStringOpt(file)); //Wonder what is the best signature.. bundledSignatures.add(signature); //If CSS we should change url:s to point to the original folder if(contentType.equalsIgnoreCase("text/css")) { if(logger.isInfoEnabled()) logger.info("contentType:" + contentType); String extensionPath = file.getPath().substring(extensionsDirectory.getPath().length() + 1, file.getPath().lastIndexOf("/") + 1); if(logger.isInfoEnabled()) logger.info("extensionPath:" + extensionPath); int urlStartIndex = content.indexOf("url("); while(urlStartIndex > -1) { if(content.charAt(urlStartIndex + 4) == '"' || content.charAt(urlStartIndex + 4) == '\'') content.insert(urlStartIndex + 5, extensionPath); else content.insert(urlStartIndex + 4, extensionPath); urlStartIndex = content.indexOf("url(", urlStartIndex + extensionPath.length()); } } //logger.info("transformed content:" + content.substring(0, 500)); scriptBundle = scriptBundle + "\n\n" + content; } else { if(logger.isInfoEnabled()) logger.info("Not adding:" + signature + " as " + file.exists() + ":" + bundledSignatures.contains(signature)); } } catch (Exception e) { logger.warn("Error trying to parse file and bundle it (" + scriptExtensionFileName + "):" + e.getMessage()); } } } if(logger.isInfoEnabled()) logger.info("scriptBundle:" + scriptBundle.length()); if(scriptBundle != null && !scriptBundle.equals("")) { if(contentType.equalsIgnoreCase("text/javascript")) { try { JSMin jsmin = new JSMin(new ByteArrayInputStream(scriptBundle.getBytes()), new FileOutputStream(extensionsBundleFile)); jsmin.jsmin(); } catch (FileNotFoundException e) { e.printStackTrace(); } } else { FileHelper.writeToFile(extensionsBundleFile, scriptBundle, false); } if(logger.isInfoEnabled()) logger.info("extensionsBundleFile:" + extensionsBundleFile.length()); } } i++; filePath = CmsPropertyHandler.getProperty("digitalAssetPath." + i); } catch (Exception e) { logger.warn("Error trying to write bundled scripts:" + e.getMessage()); } } try { SiteNodeVO siteNodeVO = NodeDeliveryController.getNodeDeliveryController(deliveryContext).getSiteNodeVO(getDatabase(), getTemplateController().getSiteNodeId()); String dnsName = CmsPropertyHandler.getWebServerAddress(); if(siteNodeVO != null) { RepositoryVO repositoryVO = RepositoryController.getController().getRepositoryVOWithId(siteNodeVO.getRepositoryId(), getDatabase()); if(repositoryVO.getDnsName() != null && !repositoryVO.getDnsName().equals("")) dnsName = repositoryVO.getDnsName(); } String bundleUrl = ""; String bundleUrlTag = ""; if(contentType.equalsIgnoreCase("text/javascript")) { bundleUrl = URLComposer.getURLComposer().composeDigitalAssetUrl(dnsName, "extensions", bundleName + ".js", deliveryContext); bundleUrlTag = "<script type=\"text/javascript\" src=\"" + bundleUrl + "\"></script>"; } else if(contentType.equalsIgnoreCase("text/css")) { bundleUrl = URLComposer.getURLComposer().composeDigitalAssetUrl(dnsName, "extensions", bundleName + ".css", deliveryContext); bundleUrlTag = "<link href=\"" + bundleUrl + "\" rel=\"stylesheet\" type=\"text/css\" />"; } if(targetElement.equalsIgnoreCase("head")) this.getTemplateController().getDeliveryContext().getHtmlHeadItems().add(bundleUrlTag); else this.getTemplateController().getDeliveryContext().getHtmlBodyEndItems().add(bundleUrlTag); } catch (Exception e) { logger.warn("Error trying get assetBaseUrl:" + e.getMessage()); } } } if(logger.isInfoEnabled()) t.printElapsedTime("Generating bundles took"); } /** * This method is used to allow pagecaching on a general level. */ public void cachePage() { } public final DeliveryContext getDeliveryContext() { return deliveryContext; } public final HttpServletRequest getRequest() { return request; } public final HttpServletResponse getResponse() { return response; } public final TemplateController getTemplateController() { return templateController; } public String getPageString() { return pageString; } public void setPageString(String string) { if(string != null && this.deliveryContext.getTrimResponse()) string = string.trim(); pageString = string; } /** * Creates and returns a defaultContext, currently with the templateLogic * and if the portal support is enabled the portalLogic object. * (Added to avoid duplication of context creation in the concrete * implementations of pageInvokers) * @author robert * @return A default context with the templateLogic and portalLogic object in it. */ public Map getDefaultContext() { Map context = new HashMap(); context.put("templateLogic", getTemplateController()); // -- check if the portal is active String portalEnabled = CmsPropertyHandler.getEnablePortal() ; boolean active = ((portalEnabled != null) && portalEnabled.equals("true")); if (active) { PortalController pController = new PortalController(getRequest(), getResponse(), getTemplateController().getDeliveryContext()); context.put(PortalController.NAME, pController); if(logger.isInfoEnabled()) { logger.info("PortalController.NAME:" + PortalController.NAME); logger.info("pController:" + pController); } } return context; } }