001: /*
002: * Copyright 2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.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/ecl1.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.kfs.batch;
017:
018: import java.io.File;
019: import java.io.IOException;
020: import java.util.Calendar;
021:
022: import org.apache.commons.lang.StringUtils;
023: import org.apache.log4j.FileAppender;
024: import org.apache.log4j.Logger;
025: import org.apache.log4j.NDC;
026: import org.kuali.core.mail.InvalidAddressException;
027: import org.kuali.core.mail.MailMessage;
028: import org.kuali.core.service.DateTimeService;
029: import org.kuali.core.service.KualiConfigurationService;
030: import org.kuali.core.service.MailService;
031: import org.kuali.kfs.KFSConstants;
032: import org.kuali.kfs.context.NDCFilter;
033: import org.kuali.kfs.service.SchedulerService;
034: import org.quartz.JobExecutionContext;
035: import org.quartz.JobExecutionException;
036:
037: public class JobListener implements org.quartz.JobListener {
038: private static final Logger LOG = Logger
039: .getLogger(JobListener.class);
040: private static final String NAME = "jobListener";
041: public static final String REQUESTOR_EMAIL_ADDRESS_KEY = "requestorEmailAdress";
042: private SchedulerService schedulerService;
043: private KualiConfigurationService configurationService;
044: private MailService mailService;
045: private DateTimeService dateTimeService;
046:
047: /**
048: * @see org.quartz.JobListener#jobWasExecuted(org.quartz.JobExecutionContext, org.quartz.JobExecutionException)
049: */
050: public void jobWasExecuted(JobExecutionContext jobExecutionContext,
051: JobExecutionException jobExecutionException) {
052: if (jobExecutionContext.getJobInstance() instanceof Job) {
053: if (!((Job) jobExecutionContext.getJobInstance())
054: .isNotRunnable()) {
055: notify(jobExecutionContext, schedulerService
056: .getStatus(jobExecutionContext.getJobDetail()));
057: }
058: completeLogging(jobExecutionContext);
059: }
060: }
061:
062: /**
063: * @see org.quartz.JobListener#jobToBeExecuted(org.quartz.JobExecutionContext)
064: */
065: public void jobToBeExecuted(JobExecutionContext jobExecutionContext) {
066: if (jobExecutionContext.getJobInstance() instanceof Job) {
067: schedulerService.initializeJob(jobExecutionContext
068: .getJobDetail().getName(),
069: (Job) jobExecutionContext.getJobInstance());
070: initializeLogging(jobExecutionContext);
071: if (schedulerService.shouldNotRun(jobExecutionContext
072: .getJobDetail())) {
073: ((Job) jobExecutionContext.getJobInstance())
074: .setNotRunnable(true);
075: }
076: }
077: }
078:
079: /**
080: * @see org.quartz.JobListener#jobExecutionVetoed(org.quartz.JobExecutionContext)
081: */
082: public void jobExecutionVetoed(
083: JobExecutionContext jobExecutionContext) {
084: if (jobExecutionContext.getJobInstance() instanceof Job) {
085: throw new UnsupportedOperationException(
086: "JobListener does not implement jobExecutionVetoed(JobExecutionContext jobExecutionContext)");
087: }
088: }
089:
090: private void initializeLogging(
091: JobExecutionContext jobExecutionContext) {
092: try {
093: Calendar startTimeCalendar = dateTimeService
094: .getCurrentCalendar();
095: StringBuffer nestedDiagnosticContext = new StringBuffer(
096: jobExecutionContext.getJobDetail().getName())
097: .append("-").append(
098: dateTimeService.toString(startTimeCalendar
099: .getTime(), "yyyyMMdd-HH-mm-ss-S"));
100: ((Job) jobExecutionContext.getJobInstance())
101: .setNdcAppender(new FileAppender(Logger
102: .getRootLogger().getAppender("LogFile")
103: .getLayout(),
104: getLogFileName(nestedDiagnosticContext
105: .toString())));
106: ((Job) jobExecutionContext.getJobInstance())
107: .getNdcAppender().addFilter(
108: new NDCFilter(nestedDiagnosticContext
109: .toString()));
110: Logger.getRootLogger().addAppender(
111: ((Job) jobExecutionContext.getJobInstance())
112: .getNdcAppender());
113: NDC.push(nestedDiagnosticContext.toString());
114: } catch (IOException e) {
115: LOG.warn(
116: "Could not initialize special custom logging for job: "
117: + jobExecutionContext.getJobDetail()
118: .getName(), e);
119: }
120: }
121:
122: private void completeLogging(JobExecutionContext jobExecutionContext) {
123: ((Job) jobExecutionContext.getJobInstance()).getNdcAppender()
124: .close();
125: Logger.getRootLogger().removeAppender(
126: ((Job) jobExecutionContext.getJobInstance())
127: .getNdcAppender());
128: NDC.pop();
129: }
130:
131: private String getLogFileName(String nestedDiagnosticContext) {
132: return new StringBuffer(configurationService
133: .getPropertyString(KFSConstants.LOGS_DIRECTORY_KEY))
134: .append(File.separator).append(
135: nestedDiagnosticContext.toString()).append(
136: ".log").toString();
137: }
138:
139: private String getLogFileUrl(String nestedDiagnosticContext) {
140: return new StringBuffer(configurationService
141: .getPropertyString(KFSConstants.HTDOCS_LOGS_URL_KEY))
142: .append(nestedDiagnosticContext.toString()).append(
143: ".log").toString();
144: }
145:
146: private void notify(JobExecutionContext jobExecutionContext,
147: String jobStatus) {
148: try {
149: StringBuffer mailMessageSubject = new StringBuffer(
150: configurationService
151: .getPropertyString(KFSConstants.ENVIRONMENT_KEY))
152: .append(": ").append(
153: jobExecutionContext.getJobDetail()
154: .getGroup()).append(": ").append(
155: jobExecutionContext.getJobDetail()
156: .getName());
157: MailMessage mailMessage = new MailMessage();
158: mailMessage.setFromAddress(mailService
159: .getBatchMailingList());
160: if (jobExecutionContext.getMergedJobDataMap().containsKey(
161: REQUESTOR_EMAIL_ADDRESS_KEY)
162: && !StringUtils.isBlank(jobExecutionContext
163: .getMergedJobDataMap().getString(
164: REQUESTOR_EMAIL_ADDRESS_KEY))) {
165: mailMessage.addToAddress(jobExecutionContext
166: .getMergedJobDataMap().getString(
167: REQUESTOR_EMAIL_ADDRESS_KEY));
168: }
169: if (SchedulerService.FAILED_JOB_STATUS_CODE
170: .equals(jobStatus)
171: || SchedulerService.CANCELLED_JOB_STATUS_CODE
172: .equals(jobStatus)) {
173: mailMessage.addToAddress(mailService
174: .getBatchMailingList());
175: }
176: mailMessageSubject.append(": ").append(jobStatus);
177: mailMessage.setMessage(new StringBuffer("See ").append(
178: getLogFileName(NDC.peek())).append(" or ").append(
179: getLogFileUrl(NDC.peek())).append(" for details")
180: .toString());
181: if (mailMessage.getToAddresses().size() > 0) {
182: mailMessage.setSubject(mailMessageSubject.toString());
183: mailService.sendMessage(mailMessage);
184: }
185: } catch (InvalidAddressException iae) {
186: LOG.error(
187: "Caught exception while trying to send job completion notification e-mail for "
188: + jobExecutionContext.getJobDetail()
189: .getName(), iae);
190: }
191: }
192:
193: /**
194: * @see org.quartz.JobListener#getName()
195: */
196: public String getName() {
197: return NAME;
198: }
199:
200: /**
201: * Sets the schedulerService attribute value.
202: *
203: * @param schedulerService The schedulerService to set.
204: */
205: public void setSchedulerService(SchedulerService schedulerService) {
206: this .schedulerService = schedulerService;
207: }
208:
209: /**
210: * Sets the configurationService attribute value.
211: *
212: * @param configurationService The configurationService to set.
213: */
214: public void setConfigurationService(
215: KualiConfigurationService configurationService) {
216: this .configurationService = configurationService;
217: }
218:
219: /**
220: * Sets the mailService attribute value.
221: *
222: * @param mailService The mailService to set.
223: */
224: public void setMailService(MailService mailService) {
225: this .mailService = mailService;
226: }
227:
228: /**
229: * Sets the dateTimeService attribute value.
230: *
231: * @param dateTimeService The dateTimeService to set.
232: */
233: public void setDateTimeService(DateTimeService dateTimeService) {
234: this.dateTimeService = dateTimeService;
235: }
236: }
|