001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.cache;
011:
012: import java.util.*;
013:
014: import org.mmbase.storage.search.*;
015: import org.mmbase.module.core.MMObjectNode;
016:
017: /**
018: * Query result cache used for getRelatedNodes from MMObjectNodes. Entries are invalidated on the
019: * normal QueryResultCache way, but also if the one node from which the related nodes were requested is
020: * removed from the Node Cache itself.
021: *
022: * @author Michiel Meeuwissen
023: * @version $Id: RelatedNodesCache.java,v 1.11 2007/02/11 19:21:11 nklasens Exp $
024: * @see org.mmbase.module.core.MMObjectNode#getRelatedNodes
025: * @since MMBase-1.7
026: */
027:
028: public class RelatedNodesCache extends QueryResultCache {
029:
030: // There will be only one list cache, and here it is:
031: private static RelatedNodesCache relatedNodesCache;
032:
033: public static RelatedNodesCache getCache() {
034: return relatedNodesCache;
035: }
036:
037: static {
038: relatedNodesCache = new RelatedNodesCache(300);
039: relatedNodesCache.putCache();
040: }
041:
042: public String getName() {
043: return "RelatedNodesCache";
044: }
045:
046: public String getDescription() {
047: return "Caches related nodes of a certain node";
048: }
049:
050: // nodenumber -> set of keys
051: // Used to sync this cache with node-cache. If node not any more in node-cache, then we decide to also remove its related nodes.
052: // This seems a plausible thing to do.
053:
054: private Map<Integer, Set<SearchQuery>> numberToKeys = new HashMap<Integer, Set<SearchQuery>>();
055:
056: public synchronized List<MMObjectNode> put(SearchQuery query,
057: List<MMObjectNode> queryResult) {
058: // test cache policy before caching
059: if (!checkCachePolicy(query))
060: return null;
061: Integer number = (query.getSteps().get(0)).getNodes().first();
062: Set<SearchQuery> keys = numberToKeys.get(number);
063: if (keys == null) {
064: keys = new HashSet<SearchQuery>();
065: numberToKeys.put(number, keys);
066: }
067: keys.add(query);
068: return super .put(query, queryResult);
069: }
070:
071: public synchronized List<MMObjectNode> remove(Object key) {
072: SearchQuery query = (SearchQuery) key;
073: Integer number = (query.getSteps().get(0)).getNodes().first();
074: Set<SearchQuery> keys = numberToKeys.get(number);
075: if (keys != null) {
076: keys.remove(query);
077: if (keys.size() == 0)
078: numberToKeys.remove(number);
079: }
080: return super .remove(key);
081: }
082:
083: synchronized void removeNode(Integer number) {
084: Set<SearchQuery> keys = numberToKeys.get(number);
085: if (keys != null) {
086: Iterator<SearchQuery> i = keys.iterator();
087: while (i.hasNext()) {
088: super .remove(i.next());
089: }
090: numberToKeys.remove(number);
091: }
092: }
093:
094: /**
095: * Creates the Node list cache.
096: */
097: private RelatedNodesCache(int size) {
098: super (size);
099: }
100:
101: public void clear() {
102: super.clear();
103: numberToKeys.clear();
104: }
105: }
|