001/** 002 * Copyright 2005-2017 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.kcb.service.impl; 017 018import org.apache.log4j.Logger; 019import org.kuali.rice.core.api.criteria.Predicate; 020import org.kuali.rice.core.api.criteria.QueryByCriteria; 021import org.kuali.rice.kcb.bo.Message; 022import org.kuali.rice.kcb.bo.MessageDelivery; 023import org.kuali.rice.kcb.bo.MessageDeliveryStatus; 024import org.kuali.rice.kcb.service.MessageDeliveryService; 025import org.kuali.rice.krad.data.DataObjectService; 026 027import java.sql.Timestamp; 028import java.util.ArrayList; 029import java.util.Collection; 030import java.util.List; 031 032import static org.kuali.rice.core.api.criteria.PredicateFactory.*; 033 034/** 035 * MessageDeliveryService implementation 036 * 037 * @author Kuali Rice Team (rice.collab@kuali.org) 038 */ 039public class MessageDeliveryServiceImpl implements MessageDeliveryService { 040 private static final Logger LOG = Logger.getLogger(MessageDeliveryServiceImpl.class); 041 042 private DataObjectService dataObjectService; 043 044 /** 045 * Number of processing attempts to make. {@link MessageDelivery}s with this number or more of attempts 046 * will not be selected for further processing. 047 */ 048 private int maxProcessAttempts; 049 050 /** 051 * Sets the max processing attempts 052 * @param maxProcessAttempts the max delivery attempts 053 */ 054 public void setMaxProcessAttempts(int maxProcessAttempts) { 055 this.maxProcessAttempts = maxProcessAttempts; 056 } 057 058 /** 059 * @see org.kuali.rice.kcb.service.MessageDeliveryService#saveMessageDelivery(org.kuali.rice.kcb.bo.MessageDelivery) 060 */ 061 public MessageDelivery saveMessageDelivery(MessageDelivery delivery) { 062 return dataObjectService.save(delivery); 063 } 064 065 /** 066 * @see org.kuali.rice.kcb.service.MessageDeliveryService#deleteMessageDelivery(MessageDelivery) 067 */ 068 public void deleteMessageDelivery(MessageDelivery messageDelivery) { 069 dataObjectService.delete(messageDelivery); 070 } 071 072 /** 073 * @see org.kuali.rice.kcb.service.MessageDeliveryService#getAllMessageDeliveries() 074 */ 075 public Collection<MessageDelivery> getAllMessageDeliveries() { 076 return dataObjectService.findMatching(MessageDelivery.class, QueryByCriteria.Builder.create().build()).getResults(); 077 } 078 079 /** 080 * @see org.kuali.rice.kcb.service.MessageDeliveryService#getMessageDelivery(java.lang.Long) 081 */ 082 public MessageDelivery getMessageDelivery(Long id) { 083 return dataObjectService.find(MessageDelivery.class, id); 084 } 085 086 /** 087 * @see org.kuali.rice.kcb.service.MessageDeliveryService#getMessageDeliveryByDelivererSystemId(java.lang.Long) 088 */ 089 public MessageDelivery getMessageDeliveryByDelivererSystemId(Long id) { 090 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create(); 091 092 criteria.setPredicates(equal(MessageDelivery.SYSTEMID_FIELD, id)); 093 List<MessageDelivery> results = dataObjectService.findMatching(MessageDelivery.class, criteria.build()).getResults(); 094 095 if (results.isEmpty()) { 096 return null; 097 } 098 if (results.size() > 1) { 099 throw new RuntimeException("More than one message delivery found with the following delivery system id: " + id); 100 } 101 return results.get(0); 102 } 103 104 /** 105 * @see org.kuali.rice.kcb.service.MessageDeliveryService#getMessageDeliveries(org.kuali.rice.kcb.bo.Message) 106 */ 107 public Collection<MessageDelivery> getMessageDeliveries(Message message) { 108 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create(); 109 criteria.setPredicates(equal(MessageDelivery.MESSAGEID_FIELD, message.getId())); 110 111 return dataObjectService.findMatching(MessageDelivery.class, criteria.build()).getResults(); 112 } 113 114 /* This method is responsible for atomically finding messagedeliveries, marking them as taken 115 * and returning them to the caller for processing. 116 * NOTE: it is important that this method execute in a SEPARATE dedicated transaction; either the caller should 117 * NOT be wrapped by Spring declarative transaction and this service should be wrapped (which is the case), or 118 * the caller should arrange to invoke this from within a newly created transaction). 119 */ 120 public Collection<MessageDelivery> lockAndTakeMessageDeliveries(MessageDeliveryStatus[] statuses) { 121 return lockAndTakeMessageDeliveries(null, statuses); 122 } 123 public Collection<MessageDelivery> lockAndTakeMessageDeliveries(Long messageId, MessageDeliveryStatus[] statuses) { 124 LOG.debug("========>> ENTERING LockAndTakeMessageDeliveries: " + Thread.currentThread()); 125 // DO WITHIN TRANSACTION: get all untaken messagedeliveries, and mark as "taken" so no other thread/job takes them 126 // need to think about durability of work list 127 128 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create(); 129 List<Predicate> predicates = new ArrayList<Predicate>(); 130 131 predicates.add(isNull(MessageDelivery.LOCKED_DATE)); 132 if (messageId != null) { 133 predicates.add(equal(MessageDelivery.MESSAGEID_FIELD + ".id", messageId)); 134 } 135 predicates.add(lessThan(MessageDelivery.PROCESS_COUNT, maxProcessAttempts)); 136 137 Collection<String> statusCollection = new ArrayList<String>(statuses.length); 138 for (MessageDeliveryStatus status: statuses) { 139 statusCollection.add(status.name()); 140 } 141 predicates.add(in(MessageDelivery.DELIVERY_STATUS, statusCollection)); 142 criteria.setPredicates(predicates.toArray(new Predicate[predicates.size()])); 143 List<MessageDelivery> messageDeliveries = dataObjectService.findMatching(MessageDelivery.class, criteria.build()).getResults(); 144 List<MessageDelivery> lockedMsgDels = new ArrayList<MessageDelivery>(); 145 146 // mark messageDeliveries as taken 147 for (MessageDelivery delivery: messageDeliveries) { 148 LOG.debug("Took: " + delivery); 149 delivery.setLockedDate(new Timestamp(System.currentTimeMillis())); 150 delivery = dataObjectService.save(delivery); 151 lockedMsgDels.add(delivery); 152 } 153 154 LOG.debug("<<======= LEAVING LockAndTakeMessageDeliveries: " + Thread.currentThread()); 155 return lockedMsgDels; 156 } 157 158 /** 159 * Sets the data object service. 160 * @param dataObjectService service to persist data to the datasource 161 */ 162 public void setDataObjectService(DataObjectService dataObjectService) { 163 this.dataObjectService = dataObjectService; 164 } 165}