001/**
002 * Copyright 2005-2014 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.criteria.QueryByCriteria;
019import org.kuali.rice.ken.bo.NotificationBo;
020import org.kuali.rice.ken.bo.NotificationMessageDelivery;
021import org.kuali.rice.ken.dao.NotificationMessegeDeliveryDao;
022import org.kuali.rice.ken.service.NotificationMessageDeliveryService;
023import org.kuali.rice.ken.util.NotificationConstants;
024import org.kuali.rice.krad.data.DataObjectService;
025
026import java.sql.Timestamp;
027import java.util.ArrayList;
028import java.util.Collection;
029import java.util.List;
030
031import static org.kuali.rice.core.api.criteria.PredicateFactory.*;
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 DataObjectService dataObjectService;
043    private NotificationMessegeDeliveryDao ntdDao;
044    
045    /**
046     * Constructs a NotificationServiceImpl class instance.
047     * @param dataObjectService
048     * @param ntdDao
049     */
050    public NotificationMessageDeliveryServiceImpl(DataObjectService dataObjectService, NotificationMessegeDeliveryDao ntdDao) {
051        this.dataObjectService = dataObjectService;
052        this.ntdDao = ntdDao;
053    }
054
055    /**
056     * This is the default implementation that uses the businessObjectDao.
057     * @param id
058     * @return NotificationMessageDelivery
059     */
060    public NotificationMessageDelivery getNotificationMessageDelivery(Long id) {
061
062        return dataObjectService.find(NotificationMessageDelivery.class, id);
063    }
064
065    /**
066     * @see org.kuali.rice.ken.service.NotificationMessageDeliveryService#getNotificationMessageDeliveryByDelivererId(java.lang.String)
067     */
068    //switch to JPA criteria
069    @Override
070    public NotificationMessageDelivery getNotificationMessageDeliveryByDelivererId(String id) {
071        QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create();
072        criteria.setPredicates(equal(NotificationConstants.BO_PROPERTY_NAMES.DELIVERY_SYSTEM_ID, id));
073        Collection<NotificationMessageDelivery> results = dataObjectService.findMatching(NotificationMessageDelivery.class, criteria.build()).getResults();
074
075        if (results.isEmpty()) {
076            return null;
077        }
078        if (results.size() > 1) {
079            throw new RuntimeException("More than one message delivery found with the following delivery system id: " + id);
080        }
081
082        return results.iterator().next();
083    }
084
085    /**
086     * @see org.kuali.rice.ken.service.NotificationMessageDeliveryService#getNotificationMessageDeliveries()
087     */
088    public Collection<NotificationMessageDelivery> getNotificationMessageDeliveries() {
089        return dataObjectService.findMatching(NotificationMessageDelivery.class, QueryByCriteria.Builder.create().build()).getResults();
090    }
091    
092    /**
093     * @see org.kuali.rice.ken.service.NotificationMessageDeliveryService#getNotificationMessageDeliveries(java.lang.Long, java.lang.String)
094     */
095    //switch to JPA criteria
096    @Override
097    public Collection<NotificationMessageDelivery> getNotificationMessageDeliveries(NotificationBo notification, String userRecipientId) {
098
099        QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create();
100        criteria.setPredicates(equal(NotificationConstants.BO_PROPERTY_NAMES.NOTIFICATION + ".id", notification.getId()),
101                equal(NotificationConstants.BO_PROPERTY_NAMES.USER_RECIPIENT_ID, userRecipientId));
102
103        return dataObjectService.findMatching(NotificationMessageDelivery.class, criteria.build()).getResults();
104    }
105
106    /**
107     * This method is responsible for atomically finding all untaken, undelivered messagedeliveries, marking them as taken
108     * and returning them to the caller for processing.
109     * NOTE: it is important that this method execute in a SEPARATE dedicated transaction; either the caller should
110     * NOT be wrapped by Spring declarative transaction and this service should be wrapped (which is the case), or
111     * the caller should arrange to invoke this from within a newly created transaction).
112
113     * @return a list of available message deliveries that have been marked as taken by the caller
114     */
115    //switch to JPA criteria
116    @Override
117    public Collection<NotificationMessageDelivery> takeMessageDeliveriesForDispatch() {
118        // DO WITHIN TRANSACTION: get all untaken messagedeliveries, and mark as "taken" so no other thread/job takes them
119        // need to think about durability of work list
120
121        // get all undelivered message deliveries
122        Collection<NotificationMessageDelivery> messageDeliveries =  ntdDao.getUndeliveredMessageDelivers(dataObjectService);
123        List<NotificationMessageDelivery> savedMsgDel = new ArrayList<NotificationMessageDelivery>();
124        
125        LOG.debug("Retrieved " + messageDeliveries.size() + " available message deliveries: " + System.currentTimeMillis());
126
127        // mark messageDeliveries as taken
128        for (NotificationMessageDelivery delivery: messageDeliveries) {
129            delivery.setLockedDateValue(new Timestamp(System.currentTimeMillis()));
130            savedMsgDel.add(dataObjectService.save(delivery));
131        }
132        return savedMsgDel;
133    }
134    
135    /**
136     * This method is responsible for atomically finding all untaken message deliveries that are ready to be autoremoved,
137     * marking them as taken and returning them to the caller for processing.
138     * NOTE: it is important that this method execute in a SEPARATE dedicated transaction; either the caller should
139     * NOT be wrapped by Spring declarative transaction and this service should be wrapped (which is the case), or
140     * the caller should arrange to invoke this from within a newly created transaction).
141     * @return a list of notifications to be autoremoved that have been marked as taken by the caller
142     */
143    @Override
144    public Collection<NotificationMessageDelivery> takeMessageDeliveriesForAutoRemoval() {
145        // get all UNDELIVERED/DELIVERED notification notification message delivery records with associated notifications that have and autoRemovalDateTime <= current
146        Collection<NotificationMessageDelivery> messageDeliveries = ntdDao.getMessageDeliveriesForAutoRemoval(new Timestamp(System.currentTimeMillis()), dataObjectService);
147        List<NotificationMessageDelivery> savedMsgDel = new ArrayList<NotificationMessageDelivery>();
148        for (NotificationMessageDelivery d: messageDeliveries) {
149            d.setLockedDateValue(new Timestamp(System.currentTimeMillis()));
150            savedMsgDel.add(dataObjectService.save(d));
151        }
152        
153        return savedMsgDel;
154    
155    }
156
157    /**
158     * Unlocks the specified messageDelivery object
159     * @param messageDelivery the message delivery to unlock
160     */
161    @Override
162    public void unlockMessageDelivery(NotificationMessageDelivery messageDelivery) {
163
164        NotificationMessageDelivery d = dataObjectService.find(NotificationMessageDelivery.class, messageDelivery.getId());
165
166        if (d == null) {
167            throw new RuntimeException("NotificationMessageDelivery #" + messageDelivery.getId() + " not found to unlock");
168        }
169
170        d.setLockedDateValue(null);
171        dataObjectService.save(d);
172    }
173}