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