org.pentaho.platform.repository.subscription.SubscriptionRepository.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.platform.repository.subscription.SubscriptionRepository.java

Source

/*
 * This program is free software; you can redistribute it and/or modify it under the 
 * terms of the GNU General Public License, version 2 as published by the Free Software 
 * Foundation.
 *
 * You should have received a copy of the GNU General Public License along with this 
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.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 General Public License for more details.
 *
 * 
 * Copyright 2005-2008 Pentaho Corporation.  All rights reserved. 
 * 
 * @created Oct 7, 2005 
 * @author James Dixon
 */

package org.pentaho.platform.repository.subscription;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.pentaho.commons.connection.IPentahoResultSet;
import org.pentaho.platform.api.engine.ICacheManager;
import org.pentaho.platform.api.engine.IPentahoSession;
import org.pentaho.platform.api.engine.ISubscriptionScheduler;
import org.pentaho.platform.api.engine.SubscriptionSchedulerException;
import org.pentaho.platform.api.repository.IContentItem;
import org.pentaho.platform.api.repository.IContentItemFile;
import org.pentaho.platform.api.repository.IContentLocation;
import org.pentaho.platform.api.repository.IContentRepository;
import org.pentaho.platform.api.repository.ISchedule;
import org.pentaho.platform.api.repository.ISubscribeContent;
import org.pentaho.platform.api.repository.ISubscription;
import org.pentaho.platform.api.repository.ISubscriptionRepository;
import org.pentaho.platform.api.repository.SubscriptionRepositoryCheckedException;
import org.pentaho.platform.api.repository.SubscriptionRepositoryException;
import org.pentaho.platform.engine.core.solution.ActionInfo;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.repository.hibernate.HibernateUtil;
import org.pentaho.platform.repository.messages.Messages;
import org.pentaho.platform.util.UUIDUtil;

public class SubscriptionRepository implements ISubscriptionRepository {
    private static final byte[] SyncLock = new byte[0];

    private static final Log logger = LogFactory.getLog(SubscriptionRepository.class);

    private static final ISubscriptionScheduler subscriptionScheduler = PentahoSystem
            .get(ISubscriptionScheduler.class, null);

    public Log getLogger() {
        return SubscriptionRepository.logger;
    }

    public SubscriptionRepository() {
        super();
    }

    // TODO sbarkdull, this needs to be modified to support repeat count, repeat interval, start date and end date.
    public Element importSchedules(final Document doc) {
        Element resultElement = DocumentHelper.createElement("importSchedulesResults"); //$NON-NLS-1$

        if (doc == null) {
            Element ele = resultElement.addElement("message") //$NON-NLS-1$
                    .addText(Messages.getString("PRO_SUBSCRIPTREP.DOCUMENT_IS_NULL")); //$NON-NLS-1$
            ele.addAttribute("result", "ERROR"); //$NON-NLS-1$ //$NON-NLS-2$
            return (resultElement);
        }

        List scheduleNodes = doc.selectNodes("//schedules/*"); //$NON-NLS-1$
        if (scheduleNodes.size() == 0) {
            Element ele = resultElement.addElement("message") //$NON-NLS-1$
                    .addText(Messages.getString("PRO_SUBSCRIPTREP.NO_SCHEDULES_DEFINED")); //$NON-NLS-1$
            ele.addAttribute("result", "WARNING"); //$NON-NLS-1$ //$NON-NLS-2$
            return (resultElement);
        }

        synchronized (SubscriptionRepository.SyncLock) {

            Node scheduleNode = null;
            String schedName, schedDesc, schedRef, cronString, schedGroup;
            ISchedule aSchedule;
            // List schedList;

            try {
                SubscriptionRepository.logger
                        .info(Messages.getString("PRO_SUBSCRIPTREP.USER_IMPORT_PROCESSING_SCHEDULES", //$NON-NLS-1$
                                Integer.toString(scheduleNodes.size())));
                for (int i = 0; i < scheduleNodes.size(); i++) {
                    scheduleNode = (Node) scheduleNodes.get(i);
                    schedRef = scheduleNode.selectSingleNode("@ref").getText(); //$NON-NLS-1$
                    schedName = scheduleNode.selectSingleNode("@name").getText(); //$NON-NLS-1$
                    schedDesc = scheduleNode.selectSingleNode("@description").getText(); //$NON-NLS-1$
                    schedGroup = scheduleNode.selectSingleNode("@group").getText(); //$NON-NLS-1$
                    cronString = scheduleNode.getText();

                    try {
                        aSchedule = getScheduleByScheduleReference(schedRef);
                        if (aSchedule != null) {
                            aSchedule.setCronString(cronString);
                            aSchedule.setDescription(schedDesc);
                            aSchedule.setGroup(schedGroup);
                            aSchedule.setTitle(schedName);
                            resultElement.addElement("modified").addText(schedRef); //$NON-NLS-1$
                            SubscriptionRepository.logger.info(Messages
                                    .getString("PRO_SUBSCRIPTREP.MODIFIED_SUBSCRIPTION_SCHEDULE", schedRef)); //$NON-NLS-1$
                        } else {
                            aSchedule = addCronSchedule(schedName, schedRef, schedDesc, cronString, schedGroup,
                                    null, null);
                            resultElement.addElement("added").addText(schedRef); //$NON-NLS-1$
                            SubscriptionRepository.logger.info(
                                    Messages.getString("PRO_SUBSCRIPTREP.ADDED_SUBSCRIPTION_SCHEDULE", schedRef)); //$NON-NLS-1$
                        }
                        SubscriptionRepository.subscriptionScheduler.getCronSummary(cronString); // Throws an exception if invalid                        
                    } catch (Exception e) {
                        resultElement.addElement("message") //$NON-NLS-1$
                                .addText(Messages.getString("PRO_SUBSCRIPTREP.ERROR_OCCURRED_WITH_SCHEDULE", //$NON-NLS-1$
                                        schedRef, e.getLocalizedMessage()));
                        SubscriptionRepository.logger
                                .warn(Messages.getString("PRO_SUBSCRIPTREP.EXCEPTION_WITH_SCHEDULE", schedRef), e); //$NON-NLS-1$
                    }
                }

            } catch (Exception e) {
                Element ele = resultElement.addElement("message").addText( //$NON-NLS-1$
                        Messages.getString("PRO_SUBSCRIPTREP.ERROR_PROCESSING_IMPORTS") + e.getLocalizedMessage()); //$NON-NLS-1$
                ele.addAttribute("result", "ERROR"); //$NON-NLS-1$ //$NON-NLS-2$
                SubscriptionRepository.logger
                        .error(Messages.getString("PRO_SUBSCRIPTREP.EXCEPTION_PROCESSING_IMPORTS"), e); //$NON-NLS-1$
                return (resultElement);
            }
        }
        return (resultElement);
    }

    public Element importContent(final Document doc) {
        Element resultElement = DocumentHelper.createElement("importContentResults"); //$NON-NLS-1$

        if (doc == null) {
            Element ele = resultElement.addElement("message") //$NON-NLS-1$
                    .addText(Messages.getString("PRO_SUBSCRIPTREP.DOCUMENT_IS_NULL")); //$NON-NLS-1$
            ele.addAttribute("result", "ERROR"); //$NON-NLS-1$//$NON-NLS-2$
            return (resultElement);
        }

        List contentNodes = doc.selectNodes("//subscription-content/*"); //$NON-NLS-1$
        if (contentNodes.size() == 0) {
            Element ele = resultElement.addElement("message") //$NON-NLS-1$
                    .addText(Messages.getString("PRO_SUBSCRIPTREP.NO_SCHEDULES_DEFINED")); //$NON-NLS-1$
            ele.addAttribute("result", "WARNING"); //$NON-NLS-1$//$NON-NLS-2$
            return (resultElement);
        }

        synchronized (SubscriptionRepository.SyncLock) {

            Node contentNode = null;
            Node tempNode = null;
            String actionRef, contentType, allowAllSchedules;
            ISubscribeContent subscribeContent = null;

            List schedList = getSchedules();
            Map scheduleMap = new HashMap();
            Map groupMap = new HashMap();

            for (int j = 0; j < schedList.size(); ++j) {
                Schedule aSchedule = (Schedule) schedList.get(j);
                scheduleMap.put(aSchedule.getScheduleReference(), aSchedule);
                List groupList = (List) groupMap.get(aSchedule.getGroup());
                if (groupList == null) {
                    groupList = new ArrayList();
                    groupMap.put(aSchedule.getGroup(), groupList);
                }
                groupList.add(aSchedule);
            }

            try {
                SubscriptionRepository.logger.info(Messages.getString(
                        "PRO_SUBSCRIPTREP.USER_PROCESSING_CONTENT_NODES", Integer.toString(contentNodes.size()))); //$NON-NLS-1$
                for (int i = 0; i < contentNodes.size(); i++) {
                    contentNode = (Node) contentNodes.get(i);
                    actionRef = contentNode.selectSingleNode("@action").getText(); //$NON-NLS-1$
                    contentType = contentNode.selectSingleNode("@type").getText(); //$NON-NLS-1$
                    tempNode = contentNode.selectSingleNode("@allowAllSchedules"); //$NON-NLS-1$
                    if (tempNode != null) {
                        allowAllSchedules = tempNode.getText();
                    } else {
                        allowAllSchedules = "false"; //$NON-NLS-1$
                    }

                    try {
                        subscribeContent = getContentByActionReference(actionRef);
                        if (subscribeContent != null) {
                            subscribeContent.setType(contentType);
                            resultElement.addElement("modified").addText(actionRef); //$NON-NLS-1$
                            SubscriptionRepository.logger.info(Messages
                                    .getString("PRO_SUBSCRIPTREP.MODIFIED_SUBSCRIPTION_CONTENT", actionRef)); //$NON-NLS-1$
                        } else {
                            subscribeContent = addContent(actionRef, contentType);
                            resultElement.addElement("added").addText(actionRef); //$NON-NLS-1$
                            SubscriptionRepository.logger.info(
                                    Messages.getString("PRO_SUBSCRIPTREP.ADDED_SUBSCRIPTION_CONTENT", actionRef)); //$NON-NLS-1$
                        }

                    } catch (Exception e) {
                        resultElement.addElement("message").addText(Messages.getString( //$NON-NLS-1$
                                "PRO_SUBSCRIPTREP.ERROR_WITH_CONTENT", actionRef, e.getLocalizedMessage())); //$NON-NLS-1$ 
                        SubscriptionRepository.logger
                                .warn(Messages.getString("PRO_SUBSCRIPTREP.ERROR_WITH_CONTENT_LOG", actionRef), e); //$NON-NLS-1$ 
                    }

                    List contentSchedules = new ArrayList();
                    if ("true".equalsIgnoreCase(allowAllSchedules)) { //$NON-NLS-1$
                        contentSchedules.addAll(schedList);
                    } else {

                        List suppliedSchedules = contentNode.selectNodes("schedule"); //$NON-NLS-1$
                        if (suppliedSchedules != null) {
                            for (int j = 0; j < suppliedSchedules.size(); j++) {
                                tempNode = (Node) suppliedSchedules.get(j);
                                String schName = tempNode.getText();
                                if (schName != null) {
                                    Object aSchedule = scheduleMap.get(schName);
                                    if (aSchedule != null) {
                                        contentSchedules.add(aSchedule);
                                    }
                                }
                            }
                        }

                        List suppliedGroups = contentNode.selectNodes("group"); //$NON-NLS-1$
                        if (suppliedGroups != null) {
                            for (int j = 0; j < suppliedGroups.size(); j++) {
                                tempNode = (Node) suppliedGroups.get(j);
                                String grpName = tempNode.getText();
                                if (grpName != null) {
                                    List groupList = (List) groupMap.get(grpName);
                                    if (groupList != null) {
                                        contentSchedules.addAll(groupList);
                                    }
                                }
                            }
                        }
                    }
                    HibernateUtil.beginTransaction(); // Need to do this or the schedules don't get saved if the content item is new
                    subscribeContent.setSchedules(contentSchedules);
                    HibernateUtil.commitTransaction();
                }
            } catch (Exception e) {
                Element ele = resultElement.addElement("message").addText( //$NON-NLS-1$
                        Messages.getString("PRO_SUBSCRIPTREP.ERROR_PROCESSING_IMPORTS") + e.getLocalizedMessage()); //$NON-NLS-1$
                ele.addAttribute("result", "ERROR"); //$NON-NLS-1$ //$NON-NLS-2$
                SubscriptionRepository.logger
                        .error(Messages.getString("PRO_SUBSCRIPTREP.EXCEPTION_PROCESSING_IMPORTS"), e); //$NON-NLS-1$
                return (resultElement);
            }

        }
        return (resultElement);
    }

    public boolean addSubscription(final ISubscription subscription) {
        if ((subscription.getId() != null) && (subscription.getTitle() != null)) {
            // commented by sbarkdull HibernateUtil.beginTransaction();
            Session session = HibernateUtil.getSession();
            session.save(subscription);
            // subscriptionMap.put( subscription.getId(), subscription );
            // commented by sbarkdull HibernateUtil.commitTransaction();
            return true;
        } else {
            // TODO log an error
            return false;
        }
    }

    @SuppressWarnings("unchecked")
    public List<ISubscription> getSubscriptionsForSchedule(final ISchedule schedule) {
        if (schedule == null) {
            return new ArrayList<ISubscription>();
        }
        Session session = HibernateUtil.getSession();
        Query qry = session
                .getNamedQuery("org.pentaho.platform.repository.subscription.Schedule.findSubscriptionsBySchedule") //$NON-NLS-1$
                .setCacheable(true);
        qry.setEntity("schedule", schedule); //$NON-NLS-1$
        return qry.list();
    }

    public List<ISubscription> getSubscriptionsForSchedule(final String scheduleId) {
        return getSubscriptionsForSchedule(this.getScheduleByScheduleReference(scheduleId));
    }

    public IPentahoResultSet getSubscriptions(final String scheduleId, final IPentahoSession session,
            final String solution, final String path, final String action, final String parameterNames[]) {
        IPentahoResultSet results = new SubscriptionResultSet(scheduleId, session, parameterNames, solution, path,
                action);
        return results;
    }

    public void addContent(final ISubscribeContent content) {
        if (getContentByActionReference(content.getActionReference()) != null) {
            throw new SubscriptionRepositoryException(Messages
                    .getString("PRO_SUBSCRIPTREP.ACTION_SEQUENCE_ALREADY_EXISTS", content.getActionReference())); //$NON-NLS-1$ 
        }

        // commented by sbarkdull     HibernateUtil.beginTransaction();
        Session session = HibernateUtil.getSession();
        session.save(content);
        // commented by sbarkdull     HibernateUtil.commitTransaction();
        clearSessionCaches();
    }

    public void deleteContent(final ISubscribeContent content) {
        //  commented by wseyler    HibernateUtil.beginTransaction();
        Session session = HibernateUtil.getSession();
        session.delete(content);
        //  commented by wseyler    HibernateUtil.commitTransaction();
        clearSessionCaches();
    }

    private void clearSessionCaches() {
        ICacheManager cm = PentahoSystem.getCacheManager(null); // TODO sbarkdull, need to get real session in here
        if (cm != null) {
            //cm.killSessionCaches();
            // TODO Need to find a way for kill all session caches
            cm.killSessionCaches();
        }
    }

    public ISubscribeContent addContent(final String actionRef, final String contentType) {
        ISubscribeContent newContent = new SubscribeContent(UUIDUtil.getUUIDAsString(), actionRef, contentType);
        addContent(newContent);
        return (newContent);
    }

    /**
     * For each action sequence path in the actionRefs array, if there is not already
     * content in the subscription repository for that action sequence, add it. If the
     * content is already in the subscription repository, do nothing. 
     * Return the a list of the content that is associated with each action sequence
     * in the actionRefs parameter, regardless of if it was newly added, or already
     * existed.
     */
    public List<ISubscribeContent> addContent(final String actionRefs[])
            throws SubscriptionRepositoryCheckedException {

        List<ISubscribeContent> newContents = new ArrayList<ISubscribeContent>();
        List<ISubscribeContent> allContent = getAllContent();
        Map<String, ISubscribeContent> existingContentActionRef = new HashMap<String, ISubscribeContent>();
        for (ISubscribeContent content : allContent) {
            existingContentActionRef.put(content.getActionReference(), content);
        }
        for (String actionRef : actionRefs) {
            if (!existingContentActionRef.containsKey(actionRef)) {
                ISubscribeContent newContent = addContent(actionRef, ""); //$NON-NLS-1$
                newContents.add(newContent);
            } else {
                newContents.add(existingContentActionRef.get(actionRef));
            }
        }
        return newContents;
    }

    /**
     * If an action sequence currently in the subscription repository is not
     * in the actionRefs array parameter, remove it from the subscription repository.
     * If an action sequence in the actionRefs array is not already in the subscription
     * repository, add it to the subscription repository. If the action sequence in the
     * actionRefs array is already in the subscription repository, do nothing.
     */
    public void setContent(final String actionRefs[]) throws Exception {
        List<String> keepList = new ArrayList<String>(Arrays.asList(actionRefs)); // Strings
        List<ISubscribeContent> allContent = getAllContent();
        List<ISubscribeContent> deleteList = new ArrayList<ISubscribeContent>(); // SubscribeContent
        for (ISubscribeContent content : allContent) {
            if (keepList.contains(content.getActionReference())) {
                keepList.remove(content.getActionReference());
            } else {
                deleteList.add(content);
            }
        }

        for (int i = 0; i < keepList.size(); ++i) {
            addContent((String) keepList.get(i), ""); //$NON-NLS-1$
        }

        for (int i = 0; i < deleteList.size(); ++i) {
            deleteSubscribeContent((SubscribeContent) deleteList.get(i));
        }
    }

    public ISubscribeContent editContent(final String contentId, final String actionRef, final String contentType) {

        ISubscribeContent oldCont = getContentById(contentId);
        if (oldCont != null) {
            // Any null values keep previous values
            if (actionRef != null) {
                oldCont.setActionReference(actionRef);
            }
            if (contentType != null) {
                oldCont.setType(contentType);
            }
            return (oldCont);
        }

        return (null);
    }

    public boolean deleteContentForSchedule(final String contentId, final String schedId)
            throws SubscriptionRepositoryCheckedException {
        ISubscribeContent content = getContentById(contentId);
        ISchedule sched = getSchedule(schedId);
        return (deleteContentForSchedule(content, sched));
    }

    // maybe this should be called deleteScheduleFromContent?
    public boolean deleteContentForSchedule(final ISubscribeContent content, final ISchedule sched)
            throws SubscriptionRepositoryCheckedException {
        if (content == null) {
            return (false);
        }
        return (content.removeSchedule(sched));
    }

    public boolean addContentForSchedule(final String contentId, final String schedId)
            throws SubscriptionRepositoryCheckedException {
        ISubscribeContent content = getContentById(contentId);
        ISchedule sched = getSchedule(schedId);
        return (addContentForSchedule(content, sched));
    }

    public boolean addContentForSchedule(final ISubscribeContent content, final ISchedule sched)
            throws SubscriptionRepositoryCheckedException {
        if (content == null) {
            return (false);
        }
        content.addSchedule(sched);
        return (true);
    }

    public void setSchedulesForContent(final String scheduleId[], final String contentId) throws Exception {
        ISubscribeContent content = getContentById(contentId);

        List schedList = new ArrayList();
        for (String element : scheduleId) {
            ISchedule sched = getSchedule(element);
            if (sched != null) {
                schedList.add(sched);
            }
        }

        content.setSchedules(schedList);
    }

    public void addContentForSchedule(final String contentIds[], final String schedId)
            throws SubscriptionRepositoryCheckedException {
        ISchedule sched = getSchedule(schedId);

        for (String contentId : contentIds) {
            ISubscribeContent content = getContentById(contentId);
            addContentForSchedule(content, sched);
        }
    }

    public void setContentForSchedule(final String contentIds[], final String schedId) throws Exception {
        ISchedule sched = getSchedule(schedId);

        List<ISubscribeContent> allContent = getAllContent();
        for (String contentId : contentIds) {
            ISubscribeContent content = getContentById(contentId);
            addContentForSchedule(content, sched);
            allContent.remove(content);
        }

        for (int i = 0; i < allContent.size(); ++i) {
            SubscribeContent content = (SubscribeContent) allContent.get(i);
            deleteContentForSchedule(content, sched);
        }
    }

    public ISubscribeContent getContentById(final String theId) {
        Session session = HibernateUtil.getSession();
        try {
            return (ISubscribeContent) session.get(SubscribeContent.class, theId);
        } catch (HibernateException ex) {
            throw new SubscriptionRepositoryException(
                    Messages.getErrorString("PRO_SUBSCRIPTREP.ERROR_0001_GETTING_SUBSCRIPTION", theId), ex); //$NON-NLS-1$
        }
    }

    @SuppressWarnings("unchecked")
    public List<ISubscribeContent> getAllContent() {
        Session session = HibernateUtil.getSession();
        Query qry = session
                .getNamedQuery("org.pentaho.platform.repository.subscription.SubscribeContent.getAllContent") //$NON-NLS-1$
                .setCacheable(true);
        return qry.list();
    }

    public ISubscribeContent getContentByActionReference(final String actionReference) {
        Session session = HibernateUtil.getSession();
        Query qry = session.getNamedQuery(
                "org.pentaho.platform.repository.subscription.SubscribeContent.findSubscriptionContentByActionRef") //$NON-NLS-1$
                .setCacheable(true);
        qry.setString("searchTerm", actionReference); //$NON-NLS-1$
        Object rtn = null;
        try {
            rtn = qry.uniqueResult();
        } catch (Exception ignored) {
            // sbarkdull, added the logging statement, original author believed the exception can be ignored.
            logger.error("Exception being ignored: ", ignored); //$NON-NLS-1$
        }
        return (SubscribeContent) rtn;
    }

    @SuppressWarnings("unchecked")
    public List<ISubscribeContent> getContentBySchedule(final ISchedule schedule) {
        Session session = HibernateUtil.getSession();
        Query qry = session
                .getNamedQuery(
                        "org.pentaho.platform.repository.subscription.SubscribeContent.findContentBySchedule") //$NON-NLS-1$
                .setCacheable(true);
        qry.setParameter("schedule", schedule); //$NON-NLS-1$
        return (qry.list());
    }

    public Document getUserSubscriptions(final String user, final String contentId, final IPentahoSession session) {
        Document document = DocumentHelper.createDocument();
        Element subscriptionsNode = document.addElement("subscriptions"); //$NON-NLS-1$
        addSubscriptionsToDocument(user, contentId, subscriptionsNode, null, session);
        return document;
    }

    public void deleteUserSubscriptions(final String user) {
        //
        Session session = HibernateUtil.getSession();
        Query qry = session.getNamedQuery(
                "org.pentaho.platform.repository.subscription.Subscription.findUserSubscriptionsForDeletion") //$NON-NLS-1$
                .setCacheable(true);
        qry.setString("searchUser", user); //$NON-NLS-1$
        SubscriptionRepository.logger.warn(Messages.getErrorString("PRO_SUBSCRIPTREP.USER_REMOVING_USER", user)); //$NON-NLS-1$
        List subscriptions = qry.list();
        Subscription subscriptToDelete = null;
        for (int i = 0; i < subscriptions.size(); i++) {
            subscriptToDelete = (Subscription) subscriptions.get(i);
            HibernateUtil.makeTransient(subscriptToDelete);
        }
        HibernateUtil.flushSession();
    }

    @SuppressWarnings("unchecked")
    public List<ISubscription> getUserSubscriptionsToContentReference(final String user, final String contentId) {
        Session session = HibernateUtil.getSession();
        ISubscribeContent content = this.getContentByActionReference(contentId);
        if (content == null) {
            return new ArrayList<ISubscription>();
        }
        Query qry = session
                .getNamedQuery("org.pentaho.platform.repository.subscription.Subscription.findUserSubscriptions") //$NON-NLS-1$
                .setCacheable(true);
        qry.setString("searchUser", user); //$NON-NLS-1$
        qry.setEntity("searchContent", content); //$NON-NLS-1$
        return qry.list();
    }

    @SuppressWarnings("unchecked")
    public List<ISubscription> getUserSubscriptions(final String user) {
        Session session = HibernateUtil.getSession();
        Query qry = session
                .getNamedQuery("org.pentaho.platform.repository.subscription.Subscription.findAllUserSubscriptions") //$NON-NLS-1$
                .setCacheable(true);
        qry.setString("searchUser", user); //$NON-NLS-1$
        return qry.list();
    }

    @SuppressWarnings("unchecked")
    public List<ISubscription> getAllSubscriptions() {
        Session session = HibernateUtil.getSession();
        Query qry = session
                .getNamedQuery("org.pentaho.platform.repository.subscription.Subscription.getAllSubscriptions") //$NON-NLS-1$
                .setCacheable(true);
        return qry.list();
    }

    public void addSubscriptionsToDocument(final String user, final String contentId,
            final Element subscriptionsNode, final String editId, final IPentahoSession session) {
        List<ISubscription> userSubsToContent = getUserSubscriptionsToContentReference(user, contentId);
        if (userSubsToContent == null) {
            return;
        }
        for (int i = 0; i < userSubsToContent.size(); i++) {
            ISubscription subscription = userSubsToContent.get(i);
            addSubscriptionToDocument(subscription, subscriptionsNode, editId, session);
        }
    }

    /**
     * Returns true if the subscription name is unique for the user/contentId
     * 
     * @param Name
     *            the schedule name to check for uniqueness
     * @param user
     *            the user that owns the schedules
     * @param contentId
     *            The action sequence separated by slashes
     * @return
     */
    public boolean checkUniqueSubscriptionName(final String name, final String user, final String contentId) {
        if (name == null) {
            return true;
        }
        List userSubsToContent = getUserSubscriptionsToContentReference(user, contentId);
        if (userSubsToContent == null) {
            return true;
        }
        for (int i = 0; i < userSubsToContent.size(); i++) {
            Subscription subscription = (Subscription) userSubsToContent.get(i);
            if (name.equals(subscription.getTitle())) {
                return false;
            }
        }

        return true;
    }

    public void addSchedulesToDocument(final String user, final String contentId, final Element schedulesNode,
            final String editId) {
        // now see if there are schedules
        ISubscribeContent content = this.getContentByActionReference(contentId);
        if (content == null) {
            return;
        }
        List schedules = content.getSchedules();
        Iterator scheduleIterator = schedules.iterator();
        Schedule schedule;
        while (scheduleIterator.hasNext()) {
            schedule = (Schedule) scheduleIterator.next();
            if (schedule != null) {
                Element scheduleNode = schedulesNode.addElement("schedule"); //$NON-NLS-1$
                scheduleNode.addElement("id").setText(schedule.getId()); //$NON-NLS-1$
                scheduleNode.addElement("title").setText(schedule.getTitle()); //$NON-NLS-1$
                scheduleNode.addElement("group").setText(schedule.getGroup()); //$NON-NLS-1$
                scheduleNode.addElement("schedRef").setText(schedule.getScheduleReference()); //$NON-NLS-1$
                // see if this schedule is currently selected
                /*
                 * if( selectedSchedules.contains( schedule.getId() ) ) {
                 * scheduleNode.addAttribute( "selected", "true" );
                 * //$NON-NLS-1$//$NON-NLS-2$ }
                 */
            }
        }
    }

    public void addSubscriptionToDocument(final ISubscription subscription, final Element subscriptionsNode,
            final String editId, final IPentahoSession session) {

        Element node = subscriptionsNode.addElement("subscription"); //$NON-NLS-1$
        if (subscription.getTitle() == null) {
            node.addElement("title").setText("Unknown"); //$NON-NLS-1$ //$NON-NLS-2$
        } else {
            node.addElement("title").setText(subscription.getTitle()); //$NON-NLS-1$
        }
        node.addElement("content-id").setText(subscription.getContent().getId()); //$NON-NLS-1$
        node.addElement("id").setText(subscription.getId()); //$NON-NLS-1$
        node.addElement("user").setText(subscription.getUser()); //$NON-NLS-1$
        if ((editId != null) && editId.equals(subscription.getId())) {
            node.addAttribute("edit", "true"); //$NON-NLS-1$//$NON-NLS-2$
        }
        int type = subscription.getType();
        switch (type) {
        case Subscription.TYPE_PERSONAL:
            node.addElement("type").setText("personal"); //$NON-NLS-1$//$NON-NLS-2$
            break;
        case Subscription.TYPE_GROUP:
            node.addElement("type").setText("group"); //$NON-NLS-1$//$NON-NLS-2$
            break;
        case Subscription.TYPE_ROLE:
            node.addElement("type").setText("role"); //$NON-NLS-1$//$NON-NLS-2$
            break;
        }
        Map parameters = subscription.getParameters();
        Iterator parameterIterator = parameters.keySet().iterator();
        Element parametersNode = node.addElement("parameters"); //$NON-NLS-1$
        while (parameterIterator.hasNext()) {
            String name = (String) parameterIterator.next();
            Object value = parameters.get(name);
            Element parameterNode = parametersNode.addElement("parameter"); //$NON-NLS-1$
            parameterNode.addElement("name").setText(name); //$NON-NLS-1$
            parameterNode.addElement("value").setText(value.toString()); //$NON-NLS-1$
        }
        // now add the archives
        IContentItem contentItem = getContentItem(subscription.getId(), session);
        if (contentItem != null) {
            List contentFiles = contentItem.getFileVersions();
            if ((contentFiles != null) && (contentFiles.size() > 0)) {
                Element archivesNode = node.addElement("archives"); //$NON-NLS-1$
                Iterator contentFileIterator = contentFiles.iterator();
                while (contentFileIterator.hasNext()) {
                    IContentItemFile file = (IContentItemFile) contentFileIterator.next();
                    Date date = file.getFileDateTime();
                    // TODO make this format driven from configuration
                    SimpleDateFormat format = new SimpleDateFormat("MM-dd-yyyy hh:mm aa"); //$NON-NLS-1$
                    String fileId = file.getId();
                    Element archiveNode = archivesNode.addElement("archive"); //$NON-NLS-1$
                    archiveNode.addElement("id").setText(fileId); //$NON-NLS-1$
                    archiveNode.addElement("date").setText(format.format(date)); //$NON-NLS-1$
                    archiveNode.addElement("size").setText(Long.toString(file.getFileSize())); //$NON-NLS-1$
                    archiveNode.addElement("mimetype").setText(contentItem.getMimeType()); //$NON-NLS-1$
                }
            }
        }
    }

    public ISubscription getSubscriptionById(final String theId) {
        Session session = HibernateUtil.getSession();
        try {
            return (ISubscription) session.get(Subscription.class, theId);
        } catch (HibernateException ex) {
            throw new SubscriptionRepositoryException(
                    Messages.getErrorString("PRO_SUBSCRIPTREP.ERROR_0001_GETTING_SUBSCRIPTION", theId), ex); //$NON-NLS-1$
        }
    }

    public ISubscription getSubscription(final String subscriptionId, final IPentahoSession session) {
        if (session == null) {
            // TODO surface an error
            return null;
        }
        if (!session.isAuthenticated()) {
            // TODO surface an error
            return null;
        }
        ISubscription subscription = getSubscriptionById(subscriptionId);
        if (subscription == null) {
            // TODO surface an error
            return null;
        }
        if (subscription.getUser().equals(session.getName())) {
            return subscription;
        }
        // TODO surface an error
        return null;
    }

    public void init(final IPentahoSession session) {
        HibernateUtil.beginTransaction();
    }

    public List<ISchedule> getSchedules() {
        Session session = HibernateUtil.getSession();
        Query qry = session.getNamedQuery("org.pentaho.platform.repository.subscription.Schedule.getAllSchedules") //$NON-NLS-1$
                .setCacheable(true);
        return qry.list();
    }

    public List<ISchedule> syncSchedules() throws Exception {
        return (SubscriptionRepository.subscriptionScheduler.syncSchedule(getSchedules()));
    }

    public List<ISchedule> getSchedulesByTitle(final String title) {
        Session session = HibernateUtil.getSession();
        Query qry = session
                .getNamedQuery("org.pentaho.platform.repository.subscription.Schedule.findScheduleByTitle") //$NON-NLS-1$
                .setCacheable(true);
        qry.setString("searchTerm", title); //$NON-NLS-1$
        return qry.list();
    }

    public ISchedule getScheduleByScheduleReference(final String scheduleReference) {
        Session session = HibernateUtil.getSession();
        Query qry = session
                .getNamedQuery("org.pentaho.platform.repository.subscription.Schedule.findSchedulesByReference") //$NON-NLS-1$
                .setCacheable(true);
        qry.setString("searchTerm", scheduleReference); //$NON-NLS-1$
        return (Schedule) qry.uniqueResult();
    }

    public boolean deleteSubscription(final String subscriptionId, final IPentahoSession session) {
        if (session == null) {
            return false;
        }
        if (!session.isAuthenticated()) {
            return false;
        }
        ISubscription subscription = getSubscription(subscriptionId, session);
        if (subscription == null) {
            // TODO throw a warning here
            return false;
        }
        if (subscription.getUser().equals(session.getName())) {

            HibernateUtil.makeTransient(subscription);
            return true;
        } else {
            // TODO throw an error here
            return false;
        }
    }

    public boolean deleteSubscription(final String subscriptionId) throws SubscriptionRepositoryCheckedException {
        ISubscription subscription = getSubscriptionById(subscriptionId);
        if (subscription == null) {
            throw new SubscriptionRepositoryException(
                    Messages.getString("PRO_SUBSCRIPTREP.SUBSCRIPTION_ID_NOT_FOUND", subscriptionId)); //$NON-NLS-1$         }
        }
        HibernateUtil.makeTransient(subscription);
        return true;
    }

    public boolean deleteSubscriptionForSchedule(final ISubscription subscription, final ISchedule sched)
            throws SubscriptionRepositoryCheckedException {
        return subscription.deleteSchedule(sched);
    }

    public boolean deleteSchedule(final ISchedule sched) throws SubscriptionRepositoryCheckedException {
        if (sched == null) {
            return (false);
        }

        List<ISubscribeContent> contentList = getContentBySchedule(sched);
        for (ISubscribeContent content : contentList) {
            deleteContentForSchedule(content, sched);
        }

        HibernateUtil.makeTransient(sched);
        HibernateUtil.flushSession();
        try {
            SubscriptionRepository.subscriptionScheduler.syncSchedule(sched.getScheduleReference(), null);
        } catch (SubscriptionSchedulerException e) {
            HibernateUtil.rollbackTransaction();
            throw new SubscriptionRepositoryCheckedException("Failed to delete schedule with name "
                    + sched.getScheduleReference() + " and id " + sched.getId(), e);
        }
        return true;
    }

    public boolean deleteScheduleById(final String scheduleId) throws SubscriptionRepositoryCheckedException {
        ISchedule sched = getSchedule(scheduleId);
        if (sched == null) {
            throw new SubscriptionRepositoryCheckedException(
                    Messages.getString("PRO_SUBSCRIPTREP.SCHEDULE_ID_NOT_FOUND", scheduleId)); //$NON-NLS-1$         }
        }
        return deleteSchedule(sched);
    }

    public boolean deleteSubscribeContent(final ISubscribeContent subContent)
            throws SubscriptionSchedulerException {
        HibernateUtil.makeTransient(subContent);
        HibernateUtil.flushSession();
        clearSessionCaches();
        return true;
    }

    public boolean deleteSubscribeContentById(final String subContentId) throws SubscriptionSchedulerException {
        ISubscribeContent content = getContentById(subContentId);
        return deleteSubscribeContent(content);
    }

    public void addSchedule(final ISchedule schedule) throws SubscriptionRepositoryCheckedException {
        if (getScheduleByScheduleReference(schedule.getScheduleReference()) != null) {
            throw new SubscriptionRepositoryCheckedException(Messages
                    .getString("PRO_SUBSCRIPTREP.SCHEDULE_REF_NOT_UNIQUE_ADD", schedule.getScheduleReference())); //$NON-NLS-1$ 
        }
        // commented by sbarkdull     HibernateUtil.beginTransaction();
        Session session = HibernateUtil.getSession();
        session.save(schedule);
        try {
            SubscriptionRepository.subscriptionScheduler.syncSchedule(null, schedule);
            // commented by sbarkdull       HibernateUtil.commitTransaction();
        } catch (SubscriptionSchedulerException e) {
            // TODO sbarkdull, at this point the transaction needs to be aborted, but how!!!
            HibernateUtil.rollbackTransaction();
            throw new SubscriptionRepositoryCheckedException("", e); // TODO sbarkdull, error msg? //$NON-NLS-1$
        }
    }

    public ISchedule addCronSchedule(final String title, final String scheduleRef, final String description,
            final String cronString, final String group, Date startDate, Date endDate)
            throws SubscriptionRepositoryCheckedException {
        Schedule newSched = new Schedule(UUIDUtil.getUUIDAsString(), title, scheduleRef, description, cronString,
                group, startDate, endDate);
        addSchedule(newSched);
        return (newSched);
    }

    public ISchedule addRepeatSchedule(String title, String scheduleRef, String description, Integer repeatCount,
            Integer repeatInterval, String group, Date startDate, Date endDate)
            throws SubscriptionRepositoryCheckedException {
        Schedule newSched = new Schedule(UUIDUtil.getUUIDAsString(), title, scheduleRef, description, repeatCount,
                repeatInterval, group, startDate, endDate);
        addSchedule(newSched);
        return newSched;
    }

    public ISchedule editCronSchedule(final String id, final String title, final String scheduleRef,
            final String description, final String cronString, final String group, Date startDate, Date endDate)
            throws SubscriptionRepositoryCheckedException {

        ISchedule oldSched = getSchedule(id);
        if (oldSched != null) {
            String oldScheduleReference = oldSched.getScheduleReference();

            // Any null values keep previous values
            if (scheduleRef != null) {
                if ((!oldScheduleReference.equals(scheduleRef))
                        && (getScheduleByScheduleReference(scheduleRef) != null)) {
                    throw new SubscriptionRepositoryException(
                            Messages.getString("PRO_SUBSCRIPTREP.SCHEDULE_REF_NOT_UNIQUE_EDIT", scheduleRef)); //$NON-NLS-1$
                }
                oldSched.setScheduleReference(scheduleRef);
            }

            if (title != null) {
                oldSched.setTitle(title);
            }
            if (description != null) {
                oldSched.setDescription(description);
            }
            if (cronString != null) {
                oldSched.setCronString(cronString);
            }
            if (group != null) {
                oldSched.setGroup(group);
            }
            oldSched.setStartDate(startDate);
            oldSched.setEndDate(endDate);
            try {
                SubscriptionRepository.subscriptionScheduler.syncSchedule(oldScheduleReference, oldSched);
            } catch (SubscriptionSchedulerException ex) {
                throw new SubscriptionRepositoryException(
                        Messages.getString("PRO_SUBSCRIPTREP.CANNOT_EDIT_SCHEDULE", id), ex); //$NON-NLS-1$
            }
            return (oldSched);
        }
        return (null);
    }

    public ISchedule editRepeatSchedule(final String id, final String title, final String scheduleRef,
            final String description, final Integer repeatCount, final Integer repeatInterval, final String group,
            Date startDate, Date endDate) throws SubscriptionRepositoryCheckedException {

        ISchedule oldSched = getSchedule(id);
        if (oldSched != null) {
            String oldScheduleReference = oldSched.getScheduleReference();

            // Any null values keep previous values
            if (scheduleRef != null) {
                if ((!oldScheduleReference.equals(scheduleRef))
                        && (getScheduleByScheduleReference(scheduleRef) != null)) {
                    throw new SubscriptionRepositoryException(
                            Messages.getString("PRO_SUBSCRIPTREP.SCHEDULE_REF_NOT_UNIQUE_EDIT", scheduleRef)); //$NON-NLS-1$
                }
                oldSched.setScheduleReference(scheduleRef);
            }

            if (title != null) {
                oldSched.setTitle(title);
            }
            if (description != null) {
                oldSched.setDescription(description);
            }
            oldSched.setRepeatCount(repeatCount);
            if (repeatInterval != null) {
                oldSched.setRepeatInterval(repeatInterval);
            }
            if (group != null) {
                oldSched.setGroup(group);
            }
            oldSched.setStartDate(startDate);
            oldSched.setEndDate(endDate);
            try {
                SubscriptionRepository.subscriptionScheduler.syncSchedule(oldScheduleReference, oldSched);
            } catch (SubscriptionSchedulerException ex) {
                throw new SubscriptionRepositoryException(
                        Messages.getString("PRO_SUBSCRIPTREP.CANNOT_EDIT_SCHEDULE", id), ex); //$NON-NLS-1$
            }
            return (oldSched);
        }
        return (null);
    }

    public ISchedule getSchedule(final String scheduleId) {
        // return (Schedule) scheduleMap.get( scheduleId );
        Session session = HibernateUtil.getSession();
        try {
            return (Schedule) session.get(Schedule.class, scheduleId);
        } catch (HibernateException ex) {
            throw new SubscriptionRepositoryException(
                    Messages.getErrorString("PRO_SUBSCRIPTREP.ERROR_0002_GETTING_SCHEDULE", scheduleId), ex); //$NON-NLS-1$
        }
    }

    public List getSubscriptionArchives(final String subscriptionName, final IPentahoSession session) {

        IContentItem contentItem = getContentItem(subscriptionName, session);
        if (contentItem == null) {
            // we have no archived versions
            return null;
        }
        return contentItem.getFileVersions();

    }

    public IContentItem getContentItem(final String subscriptionName, final IPentahoSession session) {
        ISubscriptionRepository subscriptionRepository = PentahoSystem.get(ISubscriptionRepository.class, session);
        ISubscription subscription = subscriptionRepository.getSubscription(subscriptionName, session);
        if (subscription == null) {
            // TODO surface an error
            return null;
        }
        ISubscribeContent content = subscription.getContent();
        Map subscriptionParameters = subscription.getParameters();
        ActionInfo contentInfo = ActionInfo.parseActionString(content.getActionReference());
        //        String solutionName = contentInfo[0];
        //        String actionPath = contentInfo[1];
        String actionName = (String) subscriptionParameters.get("action"); //$NON-NLS-1$
        if (actionName == null) {
            actionName = contentInfo.getActionName();
        }

        IContentItem contentItem = getContentItem(actionName, subscriptionName, null, null, session,
                contentInfo.getSolutionName(), contentInfo.getPath(), false);
        if (contentItem == null) {
            return null;
        }
        return contentItem;
    }

    public IContentItem getContentItem(final String contentName, final String subscriptionName,
            final String mimeType, final String extension, final IPentahoSession session, final String solutionName,
            final String solutionPath, final boolean allowCreate) {

        // get an output stream to hand to the caller
        IContentRepository contentRepository = PentahoSystem.get(IContentRepository.class, session);
        if (contentRepository == null) {
            // error(
            // Messages.getErrorString("RuntimeContext.ERROR_0024_NO_CONTENT_REPOSITORY")
            // ); //$NON-NLS-1$
            return null;
        }
        String contentPath = SubscriptionHelper.getSubscriptionOutputLocation(solutionName, solutionPath,
                contentName);
        // Find the location if it's already there.
        IContentLocation contentLocation = null;
        try {
            contentLocation = contentRepository.getContentLocationByPath(contentPath);
        } catch (Exception ex) {
            // ignored
        }
        if ((contentLocation == null) && allowCreate) {
            contentLocation = contentRepository.newContentLocation(contentPath, subscriptionName, subscriptionName,
                    solutionName, true);
        }
        if (contentLocation == null) {
            // error(
            // Messages.getErrorString("RuntimeContext.ERROR_0025_INVALID_CONTENT_LOCATION")
            // ); //$NON-NLS-1$
            return null;
        }

        // Get the content item from the location - if it's there.
        IContentItem contentItem = null;
        try {
            contentItem = contentLocation.getContentItemByName(subscriptionName);
        } catch (Exception ex) {
            // Ignored
        }
        if ((contentItem == null) && allowCreate) {
            contentItem = contentLocation.newContentItem(subscriptionName, contentName, extension, mimeType, null,
                    IContentItem.WRITEMODE_KEEPVERSIONS);
        }

        return contentItem;

    }

}