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.ksb.messaging.exceptionhandling;
017
018import javax.xml.namespace.QName;
019
020import org.apache.commons.lang.StringUtils;
021import org.apache.log4j.Logger;
022import org.kuali.rice.core.api.exception.RiceRuntimeException;
023import org.kuali.rice.core.api.reflect.ObjectDefinition;
024import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
025import org.kuali.rice.ksb.api.KsbApiServiceLocator;
026import org.kuali.rice.ksb.api.bus.Endpoint;
027import org.kuali.rice.ksb.api.bus.ServiceBus;
028import org.kuali.rice.ksb.api.messaging.AsynchronousCall;
029import org.kuali.rice.ksb.messaging.PersistedMessageBO;
030import org.kuali.rice.ksb.messaging.quartz.MessageServiceExecutorJob;
031import org.kuali.rice.ksb.messaging.quartz.MessageServiceExecutorJobListener;
032import org.kuali.rice.ksb.service.KSBServiceLocator;
033import org.quartz.JobDataMap;
034import org.quartz.JobDetail;
035import org.quartz.Scheduler;
036import org.quartz.SimpleTrigger;
037import org.quartz.Trigger;
038import org.quartz.impl.JobDetailImpl;
039import org.quartz.impl.triggers.SimpleTriggerImpl;
040
041/**
042 * Default implementation of {@link ExceptionRoutingService}.  Just saves 
043 * the message in the queue as is, which should be marked Exception by the 
044 * {@link MessageExceptionHandler}.
045 * 
046 * @author Kuali Rice Team (rice.collab@kuali.org)
047 *
048 */
049public class DefaultExceptionServiceImpl implements ExceptionRoutingService {
050        
051        private static final Logger LOG = Logger.getLogger(DefaultExceptionServiceImpl.class);
052
053        public void placeInExceptionRouting(Throwable throwable, PersistedMessageBO message, Object service) throws Exception {
054                LOG.error("Exception caught processing message " + message.getRouteQueueId() + " " + message.getServiceName() + ": " + throwable);
055                
056                
057                AsynchronousCall methodCall = null;
058                if (message.getMethodCall() != null) {
059                        methodCall = message.getMethodCall();
060                } else {
061                        methodCall = message.getPayload().getMethodCall();
062                }
063                message.setMethodCall(methodCall);
064                MessageExceptionHandler exceptionHandler = getMessageExceptionHandler(methodCall.getServiceConfiguration().getServiceName());
065                exceptionHandler.handleException(throwable, message, service);
066        }
067        
068        public void placeInExceptionRoutingLastDitchEffort(Throwable throwable, PersistedMessageBO message, Object service) throws Exception {
069                LOG.error("Exception caught processing message " + message.getRouteQueueId() + " " + message.getServiceName() + ": " + throwable);
070                
071                AsynchronousCall methodCall = null;
072                if (message.getMethodCall() != null) {
073                        methodCall = message.getMethodCall();
074                } else {
075                        methodCall = message.getPayload().getMethodCall();
076                }
077                message.setMethodCall(methodCall);
078                MessageExceptionHandler exceptionHandler = getMessageExceptionHandler(methodCall.getServiceConfiguration().getServiceName());
079                exceptionHandler.handleExceptionLastDitchEffort(throwable, message, service);
080        }
081        
082        protected MessageExceptionHandler getMessageExceptionHandler(QName serviceName) {
083                ServiceBus serviceBus = KsbApiServiceLocator.getServiceBus();
084                Endpoint endpoint = serviceBus.getEndpoint(serviceName);
085                if (endpoint == null) {
086                        throw new RiceRuntimeException("No services found for name " + serviceName);
087                }
088                String messageExceptionHandlerName = endpoint.getServiceConfiguration().getMessageExceptionHandler();
089                if (messageExceptionHandlerName == null) {
090                        messageExceptionHandlerName = DefaultMessageExceptionHandler.class.getName();
091                }
092                return (MessageExceptionHandler) GlobalResourceLoader.getObject(new ObjectDefinition(messageExceptionHandlerName));
093        }
094        
095        
096
097        public void scheduleExecution(Throwable throwable, PersistedMessageBO message, String description) throws Exception {
098                KSBServiceLocator.getMessageQueueService().delete(message);
099        PersistedMessageBO messageCopy = message.copy();
100                Scheduler scheduler = KSBServiceLocator.getScheduler();
101                JobDataMap jobData = new JobDataMap();
102                jobData.put(MessageServiceExecutorJob.MESSAGE_KEY, messageCopy);
103                JobDetailImpl jobDetail = new JobDetailImpl("Exception_Message_Job " + Math.random(), "Exception Messaging",
104                        MessageServiceExecutorJob.class);
105                jobDetail.setJobDataMap(jobData);
106
107        if (!StringUtils.isBlank(description)) {
108                    jobDetail.setDescription(description);
109                }
110
111        scheduler.getListenerManager().addJobListener( new MessageServiceExecutorJobListener());
112
113        SimpleTriggerImpl trigger = new SimpleTriggerImpl("Exception_Message_Trigger " + Math.random(), "Exception Messaging", messageCopy
114                        .getQueueDate());
115                trigger.setJobDataMap(jobData);// 1.6 bug required or derby will choke
116
117        scheduler.scheduleJob(jobDetail, trigger);
118        }
119                
120}