pt.webdetails.cda.cache.CacheScheduleManager.java Source code

Java tutorial

Introduction

Here is the source code for pt.webdetails.cda.cache.CacheScheduleManager.java

Source

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

package pt.webdetails.cda.cache;

import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParseException;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.PriorityQueue;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.hibernate.Session;
import org.pentaho.platform.api.engine.IParameterProvider;
import org.pentaho.platform.api.engine.IPluginResourceLoader;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import pt.webdetails.cda.CdaContentGenerator;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.pentaho.platform.api.engine.IPentahoSession;
import org.pentaho.platform.engine.core.system.StandaloneSession;
import org.pentaho.reporting.libraries.base.config.Configuration;
import org.quartz.CronExpression;
import pt.webdetails.cda.CdaBoot;
import pt.webdetails.cda.PluginHibernateException;
import pt.webdetails.cda.utils.PluginHibernateUtil;
import pt.webdetails.cda.utils.Util;

/**
 *
 * @author pdpi
 */
public class CacheScheduleManager {

    private static final String ENCODING = "UTF-8";
    static Log logger = LogFactory.getLog(CacheScheduleManager.class);
    final String PLUGIN_PATH = PentahoSystem.getApplicationContext()
            .getSolutionPath("system/" + CdaContentGenerator.PLUGIN_NAME);
    public static int DEFAULT_MAX_AGE = 3600; // 1 hour
    PriorityQueue<CachedQuery> queue;

    //  private static final String ENCODING = "UTF-8";

    enum functions {
        LIST, CHANGE, RELOAD, DELETE, PERSIST, MONITOR, DETAILS, TEST, EXECUTE, IMPORT, CACHED, GETDETAILS, CACHEOVERVIEW, REMOVECACHE
    }

    private static CacheScheduleManager _instance;

    public static synchronized CacheScheduleManager getInstance() {
        if (_instance == null) {
            _instance = new CacheScheduleManager();
        }
        return _instance;
    }

    public CacheScheduleManager() {
        initialize();
    }

    public void handleCall(IParameterProvider requestParams, OutputStream out) {
        String method = requestParams.getParameter("method").toString();
        try {
            switch (functions.valueOf(method.toUpperCase())) {
            case CHANGE:
                change(requestParams, out);
                break;
            case RELOAD:
                load(requestParams, out);
                break;
            case LIST:
                list(requestParams, out);
                break;
            case EXECUTE:
                execute(requestParams, out);
                break;
            case DELETE:
                delete(requestParams, out);
                break;
            case IMPORT:
                importQueries(requestParams, out);
                break;
            }
        } catch (Exception e) {
            logger.error(e);
        }
    }

    public void register(Query query) {
    }

    private void initialize() {
        try {
            initHibernate();
            initQueue();
        } catch (PluginHibernateException ex) {
            logger.warn("Found PluginHibernateException while initializing CacheScheduleManager "
                    + Util.getExceptionDescription(ex));
        }
    }

    public void render(IParameterProvider requestParams, OutputStream out) {
        //TODO:
    }

    private void load(IParameterProvider requestParams, OutputStream out) throws Exception {
        Session s = getHibernateSession();
        Long id = Long.decode(requestParams.getParameter("id").toString());
        Query q = (Query) s.load(Query.class, id);
        if (q == null) {
            out.write("{}".getBytes(ENCODING));
            logger.error("Couldn' get Query with id=" + id.toString());
        }
        try {
            JSONObject json = q.toJSON();
            out.write(json.toString(2).getBytes(ENCODING));
        } catch (Exception e) {
            logger.error(e);
        }
        s.close();
    }

    private void monitor(IParameterProvider requestParams, OutputStream out) {
        return; //NYI!
    }

    private void persist(IParameterProvider requestParams, OutputStream out) throws Exception {

        Long id = Long.decode(requestParams.getParameter("id").toString());
        Session s = getHibernateSession();
        s.beginTransaction();

        UncachedQuery uq = (UncachedQuery) s.load(UncachedQuery.class, id);
        CachedQuery cq = uq.cacheMe();
        if (uq != null) {
            s.delete(s);
        }
        JSONObject json = uq.toJSON();
        out.write(json.toString(2).getBytes(ENCODING));
        s.flush();
        s.getTransaction().commit();
        s.close();
    }

    public void called(String file, String id, Boolean hit) {
        return; //not implemented yet!
        /*
        Session s = getSession();
        Query q;
        List l = s.createQuery("from CachedQuery where cdaFile=? and dataAccessId=?") //
        .setString(0, file) //
        .setString(1, id) //
        .list();
            
        if (l.size() == 0)
        {
        // No results, create a new (uncached) query object.
        q = new UncachedQuery();
        }
        else if (l.size() == 1)
        {
        q = (Query) l.get(0);
        }
        else
        {
        q = (Query) l.get(0);
        // Find correct params set
        //
        }
        q.registerRequest(hit);
        s.save(q);
         */
    }

    private void change(IParameterProvider requestParams, OutputStream out) throws Exception {
        String jsonString = requestParams.getParameter("object").toString();
        JSONTokener jsonTokener = new JSONTokener(jsonString);
        try {
            Query q;
            JSONObject json = new JSONObject(jsonTokener);
            if (json.has("cronString")) {
                String cronString = json.getString("cronString");
                try {
                    CronExpression ce = new CronExpression(cronString);
                } catch (Exception e) {
                    logger.error("Failed to parse Cron string \"" + cronString + "\"");
                    out.write("{\"status\": \"error\", \"message\": \"failed to parse Cron String\"}"
                            .getBytes(ENCODING));
                    return;
                }
                q = new CachedQuery(json);
                if (q != null) {
                    queue.add((CachedQuery) q);
                    CacheActivator.reschedule(queue);
                }
            } else {
                q = new UncachedQuery(json);
            }

            Session s = getHibernateSession();
            s.beginTransaction();
            s.save(q);
            s.flush();
            s.getTransaction().commit();
            s.close();

        } catch (JSONException jse) {
            out.write("".getBytes(ENCODING));
        }

        out.write("{\"status\": \"ok\"}".getBytes(ENCODING));
    }

    private void list(IParameterProvider requestParams, OutputStream out) throws PluginHibernateException {
        JSONObject list = new JSONObject();
        JSONObject meta = new JSONObject();
        JSONArray queries = new JSONArray();
        Session s = getHibernateSession();
        List l = s.createQuery("from CachedQuery").list();
        for (Object o : l) {
            queries.put(((Query) o).toJSON());
        }
        try {

            meta.put("nextExecution", queue.size() > 0 ? queue.peek().getNextExecution().getTime() : 0);
            list.put("queries", queries);
            list.put("meta", meta);
        } catch (Exception e) {
            logger.error(e);
        }
        try {
            out.write(list.toString(2).getBytes(ENCODING));
        } catch (Exception e) {
            logger.error(e);
        } finally {
            s.close();
        }
    }

    private void importQueries(IParameterProvider requestParams, OutputStream out) throws Exception {
        String jsonString = requestParams.getParameter("object").toString();
        JSONTokener jsonTokener = new JSONTokener(jsonString);
        try {
            Query q;
            JSONObject json;
            Session s = getHibernateSession();
            s.beginTransaction();
            JSONObject root = new JSONObject(jsonTokener);
            JSONArray ja = root.getJSONArray("queries");
            for (int i = 0; i < ja.length(); i++) {
                json = ja.getJSONObject(i);
                if (json.has("cronString")) {
                    q = new CachedQuery(json);
                    queue.add((CachedQuery) q);
                    CacheActivator.reschedule(queue);
                } else {
                    q = new UncachedQuery(json);
                }
                s.save(q);

            }
            s.flush();
            s.getTransaction().commit();
            s.close();
        } catch (JSONException jse) {
            logger.error("Error importing queries: " + Util.getExceptionDescription(jse));
            out.write("".getBytes(ENCODING));
        }
    }

    private void execute(IParameterProvider requestParams, OutputStream out) throws PluginHibernateException {
        Long id = Long.decode(requestParams.getParameter("id").toString());
        Session s = getHibernateSession();
        CachedQuery q = (CachedQuery) s.load(CachedQuery.class, id);

        if (q == null) {
            // Query doesn't exist or is not set for auto-caching
            return;
        }
        try {
            q.execute();
            q.updateNext();
            CacheActivator.reschedule(queue);
            out.write("{\"status\": \"ok\"}".getBytes(ENCODING));
        } catch (Exception ex) {
            logger.error(ex);
            try {
                out.write("{\"status\": \"error\"}".getBytes(ENCODING));
            } catch (Exception ex1) {
                logger.error(ex1);
            }
        } finally {
            s.beginTransaction();
            s.update(q);
            s.flush();
            s.getTransaction().commit();
            s.close();
        }
    }

    private void delete(IParameterProvider requestParams, OutputStream out) throws PluginHibernateException {
        Long id = Long.decode(requestParams.getParameter("id").toString());
        Session s = getHibernateSession();
        s.beginTransaction();

        Query q = (Query) s.load(Query.class, id);
        s.delete(q);

        for (CachedQuery cq : queue) {
            if (cq.getId() == id) {
                queue.remove(cq);
            }
        }

        s.flush();
        s.getTransaction().commit();
        s.close();
    }

    private Session getHibernateSession() throws PluginHibernateException {

        return PluginHibernateUtil.getSession();

    }

    class SortByTimeDue implements Comparator<CachedQuery> {

        public int compare(CachedQuery o1, CachedQuery o2) {
            return (int) (o1.getNextExecution().getTime() - o2.getNextExecution().getTime());
        }
    }

    private void initQueue() throws PluginHibernateException {
        Session s = getHibernateSession();
        s.beginTransaction();

        List l = s.createQuery("from CachedQuery").list();
        this.queue = new PriorityQueue<CachedQuery>(20, new SortByTimeDue());
        for (Object o : l) {
            CachedQuery cq = (CachedQuery) o;
            if (cq.getLastExecuted() == null) {
                cq.setLastExecuted(new Date(0L));
            }
            Date nextExecution;
            try {
                nextExecution = new CronExpression(cq.getCronString()).getNextValidTimeAfter(new Date());
            } catch (ParseException ex) {
                nextExecution = new Date(0);
                logger.error("Failed to schedule " + cq.toString());
            }
            cq.setNextExecution(nextExecution);
            this.queue.add(cq);

            s.save(cq);
        }

        s.flush();
        s.getTransaction().commit();
        s.close();
    }

    public static void initHibernate() throws PluginHibernateException {

        // Get hbm file
        IPluginResourceLoader resLoader = PentahoSystem.get(IPluginResourceLoader.class, null);
        InputStream in = resLoader.getResourceAsStream(CdaContentGenerator.class, "cachemanager.hbm.xml");

        // Close session and rebuild
        PluginHibernateUtil.closeSession();
        org.hibernate.cfg.Configuration configuration = PluginHibernateUtil.getConfiguration();
        //if (configuration.getClassMapping(CachedQuery.class.getCanonicalName()) == null)
        //{
        configuration.addInputStream(in);
        try {
            PluginHibernateUtil.rebuildSessionFactory();
        } catch (Exception e) {
            return;
        }
        //}
    }

    /**
     * Initializes the CacheScheduleManager from a cold boot. Ensures all essential cached queries
     * are populated at boot time, and sets up the first query timer.
     */
    public void coldInit() throws PluginHibernateException {

        Configuration config = CdaBoot.getInstance().getGlobalConfig();
        String executeAtStart = config.getConfigProperty("pt.webdetails.cda.cache.executeAtStart");
        if (executeAtStart.equals("true")) {
            IPentahoSession session = new StandaloneSession("CDA");

            // run all queries
            Session s = getHibernateSession();
            List<CachedQuery> cachedQueries = s.createQuery("from CachedQuery").list();
            for (CachedQuery cq : cachedQueries) {
                try {
                    cq.execute();
                } catch (Exception ex) {
                    logger.error("Error executing " + cq.toString() + ":" + ex.toString());
                }
            }
            s.close();
        }

        CacheActivator.reschedule(queue);
        CacheActivator.rescheduleBackup();
    }

    /**
     * Re-initializes the CacheScheduleManager after. Should be called after a plug-in installation
     * at runtime, to ensure the query queue is kept consistent
     */
    public void hotInit() {
        return; //NYI
    }

    public PriorityQueue<CachedQuery> getQueue() {
        return queue;
    }

}