Klassendatei für XMLDeliveryCache

git-svn-id: https://svn.libreccm.org/ccm/trunk@2153 8810af33-2d31-482b-a856-94f89814c4df
master
jensp 2013-05-14 13:02:10 +00:00
parent 7d362ba2e6
commit 5b4fce41f8
1 changed files with 326 additions and 0 deletions

View File

@ -0,0 +1,326 @@
package com.arsdigita.cms;
import com.arsdigita.caching.CacheTable;
import com.arsdigita.persistence.OID;
import com.arsdigita.xml.Element;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* A cache for generated XML. This class is a singleton. Use {@link #getInstance()} to obtain the only instance of this
* class.
*
* @author Jens Pelzetter <jens@jp-digital.de>
* @version $Id$
*/
public final class XMLDeliveryCache {
private static final String DEFAULT_CONTEXT = "{{DEFAULT_CONTEXT}}";
private static final String LIST_MODE_CONTEXT = "{{LIST_MODE_CONTEXT}}";
private static final XMLDeliveryCache INSTANCE = new XMLDeliveryCache();
/**
* The real cache.
*/
private CacheTable cache = new CacheTable(XMLDeliveryCache.class.getName(),
CMSConfig.getInstance().getXmlCacheSize(),
CMSConfig.getInstance().getXmlCacheSize(),
true);
/**
* Maps from the OID of the master version of an item in the cache to the OID of the item in the cache.
*/
private Map<String, String> cachedItems = new HashMap<String, String>();
/**
* Private constructor
*/
private XMLDeliveryCache() {
//Nothing here at the moment
}
/**
* Retrieves the instance of the XMLDeliveryCache
*
* @return
*/
public static XMLDeliveryCache getInstance() {
return INSTANCE;
}
/**
* Checks if the XML representation of an item is cached.
*
* @param oid The OID of the item.
* @param context The context of the XML output.
* @param listMode Is the XML cached for list mode or normal mode.
* @return
*/
public boolean isCached(final OID oid, final String context, final boolean listMode) {
final CachedItem cachedItem = (CachedItem) cache.get(oid.toString());
if (cachedItem == null) {
return false;
}
final CachedXml cachedXml = cachedItem.get(context);
if (cachedXml == null) {
return false;
}
if (listMode) {
return (cachedXml.getCachedXml(Mode.LIST_MODE) != null);
} else {
return (cachedXml.getCachedXml(Mode.DEFAULT) != null);
}
}
/**
* Convenient method for calling {@link #isCached(OID, java.lang.String, boolean)} with {@code listMode = false}.
*
* @param oid
* @param context
* @return
*/
public boolean isCached(final OID oid, final String context) {
return isCached(oid, context, false);
}
/**
* Convenient method for calling {@link #isCached(OID, java.lang.String, boolean)} with {@code context = ""} and
* {@code listMode = false}.
*
* @param oid
* @return
*/
public boolean isCached(final OID oid) {
return isCached(oid, "", false);
}
/**
* Retrieves the cached XML from the cache and copies the cached XML to the provided parent element. Important:
* Before calling this method check if the XML for the item is cached using
* {@link #isCached(OID, java.lang.String, boolean)}. If this method is called for an item not in the cache this
* method will throw an {@link IllegalArgumentException}!
*
* @param parent The element to which the cached XML is copied.
* @param oid The OID of the item to retrieve.
* @param context The context of the cached XML.
* @param listMode Is the cached XML for the list mode or the normal mode.
*
*/
public void retrieveFromCache(final Element parent,
final OID oid,
final String context,
final boolean listMode) {
final CachedItem cachedItem = (CachedItem) cache.get(oid.toString());
if (cachedItem == null) {
throw new IllegalArgumentException(String.format("The item with the OID '%s' is not cached.",
oid.toString()));
}
final CachedXml cachedXml = cachedItem.get(context);
if (cachedXml == null) {
throw new IllegalArgumentException(String.
format(
"The item with the OID '%s' is not cached for context '%s'",
oid.toString(),
context));
}
Element cacheElem;
if (listMode) {
cacheElem = cachedXml.getCachedXml(Mode.LIST_MODE);
} else {
cacheElem = cachedXml.getCachedXml(Mode.DEFAULT);
}
if (cacheElem == null) {
if (listMode) {
throw new IllegalArgumentException(String.format(
"The item with the OID '%s' is not cached for context '%s' in list mode",
oid.toString(),
context));
} else {
if (listMode) {
throw new IllegalArgumentException(String.format(
"The item with the OID '%s' is not cached for context '%s'.",
oid.toString(),
context));
}
}
}
cacheElem.syncDocs();
final Iterator<Map.Entry<String, String>> attrs = cacheElem.getAttributes().entrySet().iterator();
Map.Entry<String, String> attr;
while (attrs.hasNext()) {
attr = attrs.next();
parent.addAttribute(attr.getKey(), attr.getValue());
}
final Iterator<Element> childs = cacheElem.getChildren().iterator();
while (childs.hasNext()) {
copyElement(parent, childs.next());
}
}
/**
* Convenient method for calling
* {@link #retrieveFromCache(com.arsdigita.xml.Element, OID, java.lang.String, boolean)} with
* {@code listMode = false}.
*
* @param parent
* @param oid
* @param context
*
* @see #retrieveFromCache(Element, OID, String, boolean)
*/
public void retrieveFromCache(final Element parent, final OID oid, final String context) {
retrieveFromCache(parent, oid, context, false);
}
/**
* Convenient method for calling
* {@link #retrieveFromCache(com.arsdigita.xml.Element, OID, java.lang.String, boolean)} with {@code context = ""}
* and {@code listMode = false}.
*
* @param parent
* @param oid
*
* @see #retrieveFromCache(Element, OID, String, boolean)
*/
public void retrieveFromCache(final Element parent, final OID oid) {
retrieveFromCache(parent, oid, "", false);
}
/**
* Cache the XML output of an item for the given context and list mode.
*
* @param oid The OID of the item to cache.
* @param item The item to cache.
* @param parent The root element of the items XML output.
* @param context The context of the XML output.
* @param listMode If the XML is for the list mode.
*/
public void cache(final OID oid,
final ContentItem item,
final Element parent,
final String context,
final boolean listMode) {
CachedItem cachedItem = (CachedItem) cache.get(oid.toString());
if (cachedItem == null) {
cachedItem = new CachedItem();
cache.put(oid.toString(), cachedItem);
}
CachedXml cachedXml = cachedItem.get(context);
if (cachedXml == null) {
cachedXml = new CachedXml();
cachedItem.put(context, cachedXml);
}
final Element cacheElem = new Element("cachedItem");
final Iterator<Map.Entry<String, String>> attrs = parent.getAttributes().entrySet().iterator();
Map.Entry<String, String> attr;
while (attrs.hasNext()) {
attr = attrs.next();
cacheElem.addAttribute(attr.getKey(), attr.getValue());
}
final Iterator<Element> childs = parent.getChildren().iterator();
while (childs.hasNext()) {
copyElement(cacheElem, childs.next());
}
if (listMode) {
cachedXml.putCachedXml(Mode.LIST_MODE, cacheElem);
} else {
cachedXml.putCachedXml(Mode.DEFAULT, cacheElem);
}
if (item.getDraftVersion() != null) {
cachedItems.put(item.getDraftVersion().getOID().toString(), oid.toString());
}
if ((item instanceof ContentPage) && (((ContentPage) item).getContentBundle() != null)) {
cachedItems.put(((ContentPage) item).getContentBundle().getOID().toString(), oid.toString());
}
}
/**
* Removes an object from the cache.
*
* @param oid The OID of the item to remove from the cache or the master id of the item to remove.
*/
public void removeFromCache(final OID oid) {
cache.remove(oid.toString());
final String cachedId = cachedItems.get(oid.toString());
if (cachedId != null) {
cache.remove(cachedId);
cachedItems.remove(oid.toString());
}
}
private void copyElement(final Element parent, final Element element) {
final Element copy = parent.newChildElement(element.getName());
final Iterator attrs = element.getAttributes().entrySet().iterator();
Map.Entry attr;
while (attrs.hasNext()) {
attr = (Map.Entry) attrs.next();
copy.addAttribute((String) attr.getKey(), (String) attr.getValue());
}
final Iterator childs = element.getChildren().iterator();
while (childs.hasNext()) {
copyElement(copy, (Element) childs.next());
}
if (element.getText() != null) {
copy.setText(element.getText());
}
if (element.getCDATASection() != null) {
copy.setCDATASection(element.getCDATASection());
}
}
private class CachedItem {
private final Map<String, CachedXml> cachedXml = new HashMap<String, CachedXml>();
public CachedItem() {
//Nothing
}
public CachedXml get(final String context) {
return cachedXml.get(context);
}
public void put(final String context, final CachedXml cachedXml) {
this.cachedXml.put(context, cachedXml);
}
}
private class CachedXml {
private final Map<Mode, Element> cachedXml = new EnumMap<Mode, Element>(Mode.class);
public CachedXml() {
//Nothing
}
public Element getCachedXml(final Mode mode) {
return cachedXml.get(mode);
}
public void putCachedXml(final Mode mode, final Element element) {
cachedXml.put(mode, element);
}
}
private enum Mode {
DEFAULT,
LIST_MODE,}
}