org.pentaho.reporting.platform.plugin.cache.PentahoDataCache.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.reporting.platform.plugin.cache.PentahoDataCache.java

Source

/*
 * This program is free software; you can redistribute it and/or modify it under the 
 * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software 
 * Foundation.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this 
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 
 * or from the Free Software Foundation, Inc., 
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * Copyright 2010-2013 Pentaho Corporation.  All rights reserved.
 */

package org.pentaho.reporting.platform.plugin.cache;

import java.util.Set;

import javax.swing.table.TableModel;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.platform.api.engine.ICacheManager;
import org.pentaho.platform.api.engine.ILogoutListener;
import org.pentaho.platform.api.engine.IPentahoSession;
import org.pentaho.platform.engine.core.system.PentahoSessionHolder;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.reporting.engine.classic.core.ClassicEngineBoot;
import org.pentaho.reporting.engine.classic.core.cache.CachableTableModel;
import org.pentaho.reporting.engine.classic.core.cache.DataCache;
import org.pentaho.reporting.engine.classic.core.cache.DataCacheKey;
import org.pentaho.reporting.engine.classic.core.cache.DataCacheManager;

/**
 * A simple data cache that wraps around the plain in-memory data-cache. That cache is stored on the user's
 * session and shared across all reports run by that user in that session.
 *
 * @author Thomas Morgner.
 */
public class PentahoDataCache implements DataCache, ILogoutListener {

    private static final Log log = LogFactory.getLog(PentahoDataCache.class);

    private static final String CACHE_NAME = "report-dataset-cache";

    /**
     * this as a public class so that if necessary someone can get access to a session
     * key and clear the cache in their own way via javascript rule / etc
     */
    public static class CompositeKey {
        public String sessionId;
        public DataCacheKey dataCacheKey;

        public CompositeKey(String sessionId, DataCacheKey dataCacheKey) {
            this.sessionId = sessionId;
            this.dataCacheKey = dataCacheKey;
        }

        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            final CompositeKey that = (CompositeKey) o;

            if (!sessionId.equals(that.sessionId)) {
                return false;
            }
            if (!dataCacheKey.equals(that.dataCacheKey)) {
                return false;
            }

            return true;
        }

        public int hashCode() {
            int result = sessionId.hashCode();
            result = 31 * result + dataCacheKey.hashCode();
            return result;
        }
    }

    private static class PentahoDataCacheManager implements DataCacheManager {
        private ICacheManager cacheManager;

        private PentahoDataCacheManager() {
            cacheManager = PentahoSystem.getCacheManager(null); // cache manager gets loaded just once...
        }

        public void clearAll() {
            if (cacheManager != null) {
                cacheManager.clearRegionCache(CACHE_NAME);
            }
        }

        public void shutdown() {
            if (cacheManager != null) {
                cacheManager.removeRegionCache(CACHE_NAME);
            }
        }

        @SuppressWarnings("unchecked")
        public void killSessionCache(IPentahoSession session) {
            if (cacheManager != null) {
                try {
                    Set cachedObjects = cacheManager.getAllKeysFromRegionCache(CACHE_NAME);
                    if (cachedObjects != null) {
                        for (Object k : cachedObjects) {
                            if (k instanceof CompositeKey) {
                                CompositeKey key = (CompositeKey) k;
                                if (key.sessionId.equals(session.getId())) {
                                    cacheManager.removeFromRegionCache(CACHE_NAME, key);
                                }
                            }
                        }
                    }
                } catch (Throwable e) {
                    // due to a known issue in hibernate cache
                    // the getAll* methods of ICacheManager throw a NullPointerException if 
                    // cache values are null (this can happen due to cache object timeouts)
                    // please see: http://opensource.atlassian.com/projects/hibernate/browse/HHH-3248
                    if (log.isDebugEnabled()) {
                        log.debug("", e);
                    }
                }
            }
        }
    }

    private PentahoDataCacheManager manager;
    private ICacheManager cacheManager;
    private int maximumRows;

    public PentahoDataCache() {
        if (log.isDebugEnabled()) {
            log.debug("Initializing");
        }
        maximumRows = ClassicEngineBoot.getInstance().getExtendedConfig()
                .getIntProperty("org.pentaho.reporting.platform.plugin.cache.PentahoDataCache.CachableRowLimit");

        if (log.isDebugEnabled()) {
            log.debug("Maximum Rows: " + maximumRows);
        }

        cacheManager = PentahoSystem.getCacheManager(null); // cache manager gets loaded just once...
        manager = new PentahoDataCacheManager();
        if (cacheManager != null) {
            if (!cacheManager.cacheEnabled(CACHE_NAME)) {
                if (!cacheManager.addCacheRegion(CACHE_NAME)) {
                    cacheManager = null;
                    manager.cacheManager = null;
                    throw new IllegalStateException("PentahoDataCache (" + CACHE_NAME + ") cannot be initialized");
                }
            }
        }

        PentahoSystem.addLogoutListener(this); // So you can remove a users' region when their session disappears
    }

    public synchronized TableModel get(final DataCacheKey key) {
        if (cacheManager == null) {
            return null;
        }

        final IPentahoSession session = PentahoSessionHolder.getSession();

        if (log.isDebugEnabled()) {
            log.debug("looking up key for session " + session.getId());
        }

        return (TableModel) cacheManager.getFromRegionCache(CACHE_NAME, new CompositeKey(session.getId(), key));
    }

    public synchronized TableModel put(final DataCacheKey key, final TableModel model) {
        if (log.isDebugEnabled()) {
            log.debug("put() called");
        }

        final IPentahoSession session = PentahoSessionHolder.getSession();
        if (cacheManager != null) {
            if (model.getRowCount() > maximumRows) {

                if (log.isDebugEnabled()) {
                    log.debug("too many rows (" + model.getRowCount() + " > " + maximumRows + ") not caching.");
                }
                return model;
            }

            // Only copy if safe to do so. Check for whitelist of good column types ..
            if (CachableTableModel.isSafeToCache(model) == false) {
                if (log.isDebugEnabled()) {
                    log.debug("model is not safe to cache. not caching.");
                }
                return model;
            }

            if (log.isDebugEnabled()) {
                log.debug("placing model in cache for session " + session.getId() + " (rows="
                        + model.getColumnCount() + ")");
            }
            final TableModel cacheModel = new CachableTableModel(model);
            cacheManager.putInRegionCache(CACHE_NAME, new CompositeKey(session.getId(), key), cacheModel);
        }
        return model;
    }

    public DataCacheManager getCacheManager() {
        return manager;
    }

    @Override
    public void onLogout(IPentahoSession session) {

        if (log.isDebugEnabled()) {
            log.debug("killing session cache for " + session.getId());
        }
        manager.killSessionCache(session);

    }
}