blob: 235294555e657addf73a61764f5cb208167febfc [file] [log] [blame]
/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.ofbiz.widget.model;
import org.apache.ofbiz.base.util.UtilGenerics;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
/**
* Utility to support different handling of code blocks in an html template:
* 1. Inline javascript tags are turned into external javascript tags for better compliance of Content Security Policy.
* These external javascript tags are placed at the bottom of the html page. The scripts are retrieved via the getJs
* request handler.
*/
public final class MultiBlockHtmlTemplateUtil {
private static final String MODULE = MultiBlockHtmlTemplateUtil.class.getName();
public static final String FTL_WRITER = "WriterForFTL";
private static final String SCRIPT_LINKS_FOR_BODY_END = "ScriptLinksForBodyEnd";
private static int maxScriptCacheSizePerUserSession = 15;
private static int estimatedConcurrentUserSessions = 250;
/**
* Store inline script extracted from freemarker template for a user session.
* Number of inline scripts for a user session will be constraint by {@link MultiBlockHtmlTemplateUtil#maxScriptCacheSizePerUserSession}
* {@link MultiBlockHtmlTemplateUtil#cleanupScriptCache(HttpSession)} will be called to remove entry when session ends.
*/
private static LinkedHashMap<String, Map<String, String>> scriptCache =
new LinkedHashMap<String, Map<String, String>>() {
private static final long serialVersionUID = 1L;
protected boolean removeEldestEntry(Map.Entry<String, Map<String, String>> eldest) {
return size() > estimatedConcurrentUserSessions;
}
};
private MultiBlockHtmlTemplateUtil() { }
/**
* add script link for page footer.
* @param request
* @param filePath
*/
public static void addScriptLinkForFoot(final HttpServletRequest request, final String filePath) {
Set<String> scriptLinks = UtilGenerics.cast(request.getAttribute(SCRIPT_LINKS_FOR_BODY_END));
if (scriptLinks == null) {
// use of LinkedHashSet to maintain insertion order
scriptLinks = new LinkedHashSet<>();
request.setAttribute(SCRIPT_LINKS_FOR_BODY_END, scriptLinks);
}
scriptLinks.add(filePath);
}
/**
* get the script links for page footer. Also @see {@link org.apache.ofbiz.webapp.ftl.ScriptTagsFooterTransform}
* @param request
* @return
*/
public static Set<String> getScriptLinksForFoot(HttpServletRequest request) {
Set<String> scriptLinks = UtilGenerics.cast(request.getAttribute(SCRIPT_LINKS_FOR_BODY_END));
return scriptLinks;
}
/**
* put script in cache for retrieval by the browser
* @param context
* @param fileName
* @param fileContent
* @return key used to store the script
*/
public static String putScriptInCache(Map<String, Object> context, String fileName, String fileContent) {
HttpSession session = (HttpSession) context.get("session");
String sessionId = session.getId();
Map<String, String> scriptMap = UtilGenerics.cast(scriptCache.get(sessionId));
if (scriptMap == null) {
// use of LinkedHashMap to limit size of the map
scriptMap = new LinkedHashMap<String, String>() {
private static final long serialVersionUID = 1L;
protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
return size() > maxScriptCacheSizePerUserSession;
}
};
scriptCache.put(sessionId, scriptMap);
}
String key = fileName;
if (scriptMap.containsKey(fileName)) {
int counter = 1;
key = fileName + "-" + counter;
while (scriptMap.containsKey(key)) {
counter++;
key = fileName + "-" + counter;
}
}
scriptMap.put(key, fileContent);
return key;
}
/**
* Remove script from cache after reading.
* @param session
* @param fileName
* @return script to be sent back to browser
*/
public static String getScriptFromCache(HttpSession session, final String fileName) {
Map<String, String> scriptMap = UtilGenerics.cast(scriptCache.get(session.getId()));
if (scriptMap != null && scriptMap.containsKey(fileName)) {
return scriptMap.remove(fileName);
}
return "";
}
/**
* cleanup the script cache when user session is invalidated.
* @param session
*/
public static void cleanupScriptCache(HttpSession session) {
scriptCache.remove(session.getId());
}
}