Package com.impetus.kundera.persistence.context

Source Code of com.impetus.kundera.persistence.context.CacheBase

/**
* Copyright 2012 Impetus Infotech.
*
* Licensed 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 com.impetus.kundera.persistence.context;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.impetus.kundera.graph.Node;
import com.impetus.kundera.graph.NodeLink;
import com.impetus.kundera.graph.ObjectGraph;
import com.impetus.kundera.graph.ObjectGraphUtils;
import com.impetus.kundera.lifecycle.states.ManagedState;
import com.impetus.kundera.metadata.model.EntityMetadata;
import com.impetus.kundera.persistence.PersistenceDelegator;
import com.impetus.kundera.property.PropertyAccessorHelper;
import com.impetus.kundera.utils.ObjectUtils;

/**
* Base class for all cache required in persistence context
*
* @author amresh.singh
*/
public class CacheBase
{
    private static Logger log = LoggerFactory.getLogger(CacheBase.class);

    private Map<String, Node> nodeMappings;

    private Set<Node> headNodes;

    private com.impetus.kundera.cache.Cache l2Cache;

    private PersistenceCache persistenceCache;

    public CacheBase(com.impetus.kundera.cache.Cache l2Cache, PersistenceCache pc)
    {
        this.headNodes = new HashSet<Node>();
        this.nodeMappings = new ConcurrentHashMap<String, Node>();
        this.l2Cache = l2Cache;
        this.persistenceCache = pc;
    }

    public Node getNodeFromCache(String nodeId, PersistenceDelegator pd)
    {
        Node node = nodeMappings.get(nodeId);
        // if not present in first level cache, check from second level cache.
        return node != null ? node : lookupL2Cache(nodeId, pd);
    }

    public Node getNodeFromCache(Object entity, EntityMetadata entityMetadata, PersistenceDelegator pd)
    {
        if (entity == null)
        {
            throw new IllegalArgumentException("Entity is null, can't check whether it's in persistence context");
        }
        Object primaryKey = PropertyAccessorHelper.getId(entity, entityMetadata);

        if (primaryKey == null)
        {
            throw new IllegalArgumentException("Primary key not set into entity");
        }
        String nodeId = ObjectGraphUtils.getNodeId(primaryKey, entity.getClass());
        return getNodeFromCache(nodeId, pd);
    }

    public synchronized void addNodeToCache(Node node)
    {
        // Make a deep copy of Node data and and set into node
        // Original data object is now detached from Node and is possibly
        // referred by user code
        Object nodeDataCopy = ObjectUtils.deepCopy(node.getData(), node.getPersistenceDelegator().getKunderaMetadata());
        node.setData(nodeDataCopy);

        /*
         * check if this node already exists in cache node mappings If yes,
         * update parents and children links Otherwise, just simply add the node
         * to cache node mappings
         */

        processNodeMapping(node);

        if (l2Cache != null)
        {
            l2Cache.put(node.getNodeId(), node.getData());
        }
    }

    public void processNodeMapping(Node node)
    {
        if (nodeMappings.containsKey(node.getNodeId()))
        {
            Node existingNode = nodeMappings.get(node.getNodeId());

            if (existingNode.getParents() != null)
            {
                if (node.getParents() == null)
                {
                    node.setParents(new HashMap<NodeLink, Node>());
                }
                node.getParents().putAll(existingNode.getParents());
            }

            if (existingNode.getChildren() != null)
            {
                if (node.getChildren() == null)
                {
                    node.setChildren(new HashMap<NodeLink, Node>());
                }
                node.getChildren().putAll(existingNode.getChildren());
            }

            nodeMappings.put(node.getNodeId(), node);
            logCacheEvent("ADDED TO ", node.getNodeId());
        }
        else
        {
            logCacheEvent("ADDED TO ", node.getNodeId());
            nodeMappings.put(node.getNodeId(), node);
        }

        // If it's a head node, add this to the list of head nodes in
        // Persistence Cache
        if (node.isHeadNode())
        {
            node.getPersistenceCache().getMainCache().addHeadNode(node);
        }
    }

    public synchronized void removeNodeFromCache(Node node)
    {
        if (getHeadNodes().contains(node))
        {
            getHeadNodes().remove(node);
        }

        if (nodeMappings.get(node.getNodeId()) != null)
        {
            nodeMappings.remove(node.getNodeId());
        }

        evictFroml2Cache(node);
        logCacheEvent("REMOVED FROM ", node.getNodeId());
        node = null; // Eligible for GC
    }

    public void addGraphToCache(ObjectGraph graph, PersistenceCache persistenceCache)
    {
        // Add each node in the graph to cache
        for (String key : graph.getNodeMapping().keySet())
        {
            Node thisNode = graph.getNodeMapping().get(key);
            addNodeToCache(thisNode);

            // Remove all those head nodes in persistence cache, that are there
            // in Graph as a non-head node
            if (!thisNode.isHeadNode() && persistenceCache.getMainCache().getHeadNodes().contains(thisNode))
            {
                persistenceCache.getMainCache().getHeadNodes().remove(thisNode);
            }
        }
        // Add head Node to list of head nodes
        addHeadNode(graph.getHeadNode());
    }

    private void logCacheEvent(String eventType, String nodeId)
    {
        if (log.isDebugEnabled())
        {
            log.debug("Node: " + nodeId + ":: " + eventType + " Persistence Context");
        }
    }

    /**
     * @param nodeMappings
     *            the nodeMappings to set
     */
    public void setNodeMappings(Map<String, Node> nodeMappings)
    {
        this.nodeMappings = nodeMappings;
    }

    public synchronized void addHeadNode(Node headNode)
    {
        headNodes.add(headNode);
    }

    public int size()
    {
        return nodeMappings.size();
    }

    public Collection<Node> getAllNodes()
    {
        return nodeMappings.values();
    }

    /**
     *
     */
    public void clear()
    {
        if (this.nodeMappings != null)
        {
            this.nodeMappings.clear();
        }

        if (this.headNodes != null)
        {
            this.headNodes.clear();
        }

        if (this.l2Cache != null)
        {
            l2Cache.evictAll();
        }
    }

    /**
     * @return the headNodes
     */
    public Set<Node> getHeadNodes()
    {
        return Collections.synchronizedSet(headNodes);
    }

    private Node lookupL2Cache(String nodeId, PersistenceDelegator pd)
    {
        Node node = null;
        if (l2Cache != null)
        {
            Object entity = l2Cache.get(nodeId);
            if (entity != null)
            {
                node = new Node(nodeId, entity.getClass(), new ManagedState(), this.persistenceCache,
                        nodeId.substring(nodeId.indexOf("$") + 1), pd);
                node.setData(entity);
            }
        }

        return node;
    }

    private void evictFroml2Cache(Node node)
    {
        if (l2Cache != null)
        {
            this.l2Cache.evict(node.getDataClass(), node.getNodeId());
        }
    }
}
TOP

Related Classes of com.impetus.kundera.persistence.context.CacheBase

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.