📄 cacheservermemoryservice.java
字号:
package org.jahia.services.htmlcache;import java.util.Hashtable;import java.util.Enumeration;import java.util.Vector;import java.util.Set;import java.util.HashSet;import java.util.Iterator;import java.util.Map;import java.util.HashMap;import java.util.Date;import java.io.*;import javax.xml.parsers.*;import org.w3c.dom.*;import org.jahia.utils.JahiaTools;import org.jahia.utils.JahiaConsole;import org.jahia.settings.JahiaPrivateSettings;import org.jahia.exceptions.JahiaInitializationException;/** * This class provides an in-memory implementation of the output cache server * service. It also allows for an optional configuration file in XML format. * This file is used to reduce the number of userAgent entries, but mapping * this way : * * userAgent -> group * * This allows the definition of groups such as Netscape4, IE, Netscape/Linux, * etc and can be customized by the users in order to match their deployment * needs. A standard configuration will be provided for Jahia to use by default. * The code of this implementation should behave correctly if this file doesn't * exist though... * * The format of the XML file is the following : * * <?xml version="1.0" encoding="ISO-8859-1"?> * <cacheconfig> * <parameters> * <max-entries>10000</max-entries> * <debug-mode>off</debug-mode> * </parameters> * <agentgroups> * <group> * <name> * ...groupname... * </name> * <regexps> * <regexp value="regexpstring"/> * ... more regexp tags... * </regexps> * <agents> * <agent value="useragentstring"/> * ...more agent tags... * </agents> * </group> * ...more groups... * </agentgroups> * </cacheconfig> * * @author Serge Huber */public class CacheServerMemoryService extends CacheServerService { private static CacheServerMemoryService m_Instance; private static final String KEY_SEPARATOR = "###"; private static final String CONFIG_FILE_NAME = "cacheconfig.xml"; private static final String TAG_PARAMETERS = "parameters"; private static final String TAG_MAX_ENTRIES = "max-entries"; private static final String TAG_DEBUG_MODE = "debug-mode"; private static final String TAG_GROUP = "group"; private static final String TAG_NAME = "name"; private static final String TAG_AGENT = "agent"; private static final String TAG_REGEXP = "regexp"; private static final String ATTR_VALUE = "value"; private static final String DEFAULT_GROUP_NAME = "defaultgroup"; /** * This class is used to build a linked list for cache entries. This * list is used to quickly know which are the cache entries that we * updated last. This way we can remove the oldest entries quickly * (they are at the beginning of the list) * <p>Copyright: Copyright (c) 2002</p> * <p>Company: Jahia Inc.</p> * @author Serge Huber * @version 3.0 */ private class CacheNode { private CacheNode previousNode; private CacheNode nextNode; private CacheEntry cacheEntry; private String cacheKey; public CacheNode(CacheNode previousNode, CacheNode nextNode, String cacheKey, CacheEntry entry) { this.previousNode = previousNode; this.nextNode = nextNode; this.cacheKey = cacheKey; this.cacheEntry = entry; } public CacheNode getPreviousNode() { return previousNode; } public CacheNode getNextNode() { return nextNode; } public CacheEntry getCacheEntry() { return cacheEntry; } public String getCacheKey() { return cacheKey; } public void setPreviousNode(CacheNode previousNode) { this.previousNode = previousNode; } public void setNextNode(CacheNode nextNode) { this.nextNode = nextNode; } public void setCacheEntry(CacheEntry entry) { this.cacheEntry = entry; } } // we will create two "dummy" entries for these entries, because this // greatly reduces the complexities of the logic involved in handling // the linked list. Check the private constructor of this class to see // how this is handled. private final CacheNode beforeFirstNode; private final CacheNode afterLastNode; /* * Default max value in output cache if not specified in the configuration * file */ private static final int DEFAULT_MAX_CACHE_ENTRIES = 10000; private int maxCacheEntries = DEFAULT_MAX_CACHE_ENTRIES; private Map cacheTable = new HashMap(); private Hashtable userAgentMap = new Hashtable(); private boolean useGroupMap = false; private boolean automaticUserAgentAdd = true; private Vector userAgentGroupList = new Vector(); private UserAgentGroup defaultUserAgentGroup = null; private boolean debugActivated = false; private String configFileName; private CacheServerMemoryService() { // the order in which we do this initialization is critical. beforeFirstNode = new CacheNode(null, null, "DUMMY_BEFORE_FIRST_NODE_ENTRY", null); afterLastNode = new CacheNode(beforeFirstNode, null, "DUMMY_AFTER_LAST_NODE_ENTRY", null); beforeFirstNode.setNextNode(afterLastNode); } /** * return the singleton instance */ public static synchronized CacheServerMemoryService getInstance(){ if ( m_Instance == null ){ m_Instance = new CacheServerMemoryService(); } return m_Instance; } public void init( JahiaPrivateSettings jSettings ) throws JahiaInitializationException { String configPath = jSettings.jahiaOutputCacheConfigDiskPath; File configFile = new File(configPath + File.separator + CONFIG_FILE_NAME); if (configFile.exists()) { configFileName = configPath + File.separator + CONFIG_FILE_NAME; processConfigFile(configFile); } else { JahiaConsole.println("CacheServerMemoryService.init", "Config file not found in " + configPath + File.separator + CONFIG_FILE_NAME); } JahiaConsole.println("CacheServerMemoryService.init", "Initialized"); } public CacheEntry getEntry(String pageID, String userName, String userAgent) { String cacheKey = buildCacheKey(pageID, userName, userAgent); CacheNode resultNode; if (cacheTable.containsKey(cacheKey)) { Object value = cacheTable.get(cacheKey); if (value instanceof CacheNode) { resultNode = (CacheNode) value; synchronized (cacheTable) { // first let's check if this cache entry has expired. if (resultNode.getCacheEntry().getExpirationDate() != null) { Date now = new Date(); if (resultNode.getCacheEntry().getExpirationDate().compareTo(now) < 0) { // entry has expired, we must remove it and then exit. JahiaConsole.println ("CacheServerMemoryService", "Cache entry has expired, ignoring entry and removing...") ; removeCacheNode(cacheKey); return null; } } int hits = resultNode.getCacheEntry().getHits(); resultNode.getCacheEntry().setHits(hits+1); resultNode.getCacheEntry().setLastAccessDate(new Date()); this.debugDisplayCacheAccessList("getEntry before"); // let's remove the node from the list first CacheNode previousNode = resultNode.getPreviousNode(); CacheNode nextNode = resultNode.getNextNode(); previousNode.setNextNode(nextNode); nextNode.setPreviousNode(previousNode); // add the current node at the end afterLastNode.getPreviousNode().setNextNode(resultNode); resultNode.setPreviousNode(afterLastNode.getPreviousNode()); resultNode.setNextNode(afterLastNode); afterLastNode.setPreviousNode(resultNode); this.debugDisplayCacheAccessList("getEntry after"); } // JahiaConsole.println("CacheServerMemoryServer.getHTML", "Found key <" + cacheKey + ">"); return resultNode.getCacheEntry(); } else { return null; } } else { return null; } } public void setEntry(String pageID, String userName, String userAgent, CacheEntry entry) { String cacheKey = buildCacheKey(pageID, userName, userAgent); JahiaConsole.println("CacheServerMemoryServer.setEntry", "Adding/updating key <" + cacheKey + ">, cache size before set=" + cacheTable.size()); synchronized (cacheTable) { if (cacheTable.size() >= maxCacheEntries) { JahiaConsole.println("CacheServerMemoryService.setEntry", "Cache full, flushing entries..."); while (cacheTable.size() >= maxCacheEntries) { CacheNode firstNode = beforeFirstNode.getNextNode(); // remove entry from linked list beforeFirstNode.setNextNode(firstNode.getNextNode()); firstNode.getNextNode().setPreviousNode(beforeFirstNode); JahiaConsole.println("CacheServerMemoryService.setEntry", "Removing entry " + firstNode.getCacheKey() + "..."); // remove entry from cache table cacheTable.remove(firstNode.getCacheKey()); } } CacheNode curNode = (CacheNode) cacheTable.get(cacheKey); if (curNode == null) { // insert the new cache entry just before the afterLastNode entry, // making it effectively the last "real" entry. curNode = new CacheNode(afterLastNode.getPreviousNode(), afterLastNode, cacheKey, entry); afterLastNode.getPreviousNode().setNextNode(curNode); afterLastNode.setPreviousNode(curNode); } else { curNode.setCacheEntry(entry); } this.debugDisplayCacheAccessList("setEntry");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -