001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.ken.service.impl;
017
018import org.kuali.rice.core.api.util.RiceConstants;
019import org.kuali.rice.core.framework.persistence.dao.GenericDao;
020import org.kuali.rice.ken.bo.NotificationBo;
021import org.kuali.rice.ken.bo.NotificationMessageDelivery;
022import org.kuali.rice.ken.dao.NotificationMessegeDeliveryDao;
023import org.kuali.rice.ken.service.NotificationMessageDeliveryService;
024import org.kuali.rice.ken.util.NotificationConstants;
025
026import java.sql.Timestamp;
027import java.util.Collection;
028import java.util.HashMap;
029import java.util.Map;
030
031//import org.kuali.rice.core.jpa.criteria.Criteria;
032
033/**
034 * NotificationService implementation - this is the default out-of-the-box implementation of the service that uses the 
035 * businessObjectDao to get at the data via our OOTB DBMS.
036 * @author Kuali Rice Team (rice.collab@kuali.org)
037 */
038public class NotificationMessageDeliveryServiceImpl implements NotificationMessageDeliveryService {
039    private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
040        .getLogger(NotificationMessageDeliveryServiceImpl.class);
041    
042    private GenericDao businessObjectDao;
043    private NotificationMessegeDeliveryDao ntdDao;
044    
045    /**
046     * Constructs a NotificationServiceImpl class instance.
047     * @param businessObjectDao
048     */
049    public NotificationMessageDeliveryServiceImpl(GenericDao businessObjectDao, NotificationMessegeDeliveryDao ntdDao) {
050        this.businessObjectDao = businessObjectDao;
051        this.ntdDao = ntdDao;
052    }
053
054    /**
055     * This is the default implementation that uses the businessObjectDao.
056     * @param id
057     * @return NotificationMessageDelivery
058     */
059    public NotificationMessageDelivery getNotificationMessageDelivery(Long id) {
060        HashMap<String, Long> primaryKeys = new HashMap<String, Long>();
061        primaryKeys.put(NotificationConstants.BO_PROPERTY_NAMES.ID, id);
062        
063        return (NotificationMessageDelivery) businessObjectDao.findByPrimaryKey(NotificationMessageDelivery.class, primaryKeys);
064    }
065
066    /**
067     * @see org.kuali.rice.ken.service.NotificationMessageDeliveryService#getNotificationMessageDeliveryByDelivererId(java.lang.String)
068     */
069    //switch to JPA criteria
070    public NotificationMessageDelivery getNotificationMessageDeliveryByDelivererId(String id) {
071        Map<String, Object> c = new HashMap<String, Object>();
072        c.put(NotificationConstants.BO_PROPERTY_NAMES.DELIVERY_SYSTEM_ID, id);  
073        Collection<NotificationMessageDelivery> results = businessObjectDao.findMatching(NotificationMessageDelivery.class, c);
074        
075        if (results == null || results.size() == 0) return null;
076        if (results.size() > 1) {
077            throw new RuntimeException("More than one message delivery found with the following delivery system id: " + id);
078        }
079        return results.iterator().next();
080    }
081
082    /**
083     * @see org.kuali.rice.ken.service.NotificationMessageDeliveryService#getNotificationMessageDeliveries()
084     */
085    public Collection<NotificationMessageDelivery> getNotificationMessageDeliveries() {
086        return businessObjectDao.findAll(NotificationMessageDelivery.class);
087    }
088    
089    /**
090     * @see org.kuali.rice.ken.service.NotificationMessageDeliveryService#getNotificationMessageDeliveries(java.lang.Long, java.lang.String)
091     */
092    //switch to JPA criteria
093    public Collection<NotificationMessageDelivery> getNotificationMessageDeliveries(NotificationBo notification, String userRecipientId) {
094
095        Map<String, Object> c = new HashMap<String, Object>();
096        c.put(NotificationConstants.BO_PROPERTY_NAMES.NOTIFICATION, notification.getId());
097        c.put(NotificationConstants.BO_PROPERTY_NAMES.USER_RECIPIENT_ID, userRecipientId);
098        
099        return businessObjectDao.findMatching(NotificationMessageDelivery.class, c);
100    }
101
102    /**
103     * This method is responsible for atomically finding all untaken, undelivered messagedeliveries, marking them as taken
104     * and returning them to the caller for processing.
105     * NOTE: it is important that this method execute in a SEPARATE dedicated transaction; either the caller should
106     * NOT be wrapped by Spring declarative transaction and this service should be wrapped (which is the case), or
107     * the caller should arrange to invoke this from within a newly created transaction).
108
109     * @return a list of available message deliveries that have been marked as taken by the caller
110     */
111    //switch to JPA criteria
112    public Collection<NotificationMessageDelivery> takeMessageDeliveriesForDispatch() {
113        // DO WITHIN TRANSACTION: get all untaken messagedeliveries, and mark as "taken" so no other thread/job takes them
114        // need to think about durability of work list
115
116        // get all undelivered message deliveries
117        Collection<NotificationMessageDelivery> messageDeliveries = ntdDao.getUndeliveredMessageDelivers(businessObjectDao);
118
119        
120        LOG.debug("Retrieved " + messageDeliveries.size() + " available message deliveries: " + System.currentTimeMillis());
121
122        // mark messageDeliveries as taken
123        for (NotificationMessageDelivery delivery: messageDeliveries) {
124            delivery.setLockedDateValue(new Timestamp(System.currentTimeMillis()));
125            businessObjectDao.save(delivery);
126        }
127        return messageDeliveries;
128    }
129    
130    /**
131     * This method is responsible for atomically finding all untaken message deliveries that are ready to be autoremoved,
132     * marking them as taken and returning them to the caller for processing.
133     * NOTE: it is important that this method execute in a SEPARATE dedicated transaction; either the caller should
134     * NOT be wrapped by Spring declarative transaction and this service should be wrapped (which is the case), or
135     * the caller should arrange to invoke this from within a newly created transaction).
136     * @return a list of notifications to be autoremoved that have been marked as taken by the caller
137     */
138    public Collection<NotificationMessageDelivery> takeMessageDeliveriesForAutoRemoval() {
139        // get all UNDELIVERED/DELIVERED notification notification message delivery records with associated notifications that have and autoRemovalDateTime <= current
140        Collection<NotificationMessageDelivery> messageDeliveries = ntdDao.getMessageDeliveriesForAutoRemoval(new Timestamp(System.currentTimeMillis()), businessObjectDao);
141        
142        for (NotificationMessageDelivery d: messageDeliveries) {
143            d.setLockedDateValue(new Timestamp(System.currentTimeMillis()));
144            businessObjectDao.save(d);
145        }
146        
147        return messageDeliveries;
148    
149    }
150
151    /**
152     * Unlocks the specified messageDelivery object
153     * @param messageDelivery the message delivery to unlock
154     */
155    public void unlockMessageDelivery(NotificationMessageDelivery messageDelivery) {
156        Map<String, Long> c = new HashMap<String, Long>();
157        c.put(NotificationConstants.BO_PROPERTY_NAMES.DELIVERY_SYSTEM_ID, messageDelivery.getId());     
158
159        Collection<NotificationMessageDelivery> deliveries = businessObjectDao.findMatching(NotificationMessageDelivery.class, c, true, RiceConstants.NO_WAIT);
160        if (deliveries == null || deliveries.size() == 0) {
161            throw new RuntimeException("NotificationMessageDelivery #" + messageDelivery.getId() + " not found to unlock");
162        }
163
164        NotificationMessageDelivery d = deliveries.iterator().next();
165        d.setLockedDateValue(null);
166
167        businessObjectDao.save(d);
168    }
169}