001/*
002 * Copyright 2007 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.ole.gl.batch.service.impl;
017
018import java.io.File;
019import java.io.InputStream;
020import java.util.Collection;
021import java.util.HashSet;
022import java.util.List;
023import java.util.Set;
024
025import org.apache.commons.lang.StringUtils;
026import org.kuali.ole.gl.batch.EnterpriseFeedStep;
027import org.kuali.ole.gl.batch.service.EnterpriseFeederNotificationService;
028import org.kuali.ole.sys.OLEConstants;
029import org.kuali.ole.sys.OLEKeyConstants;
030import org.kuali.ole.sys.Message;
031import org.kuali.ole.sys.service.impl.OleParameterConstants;
032import org.kuali.rice.core.api.config.property.ConfigurationService;
033import org.kuali.rice.core.api.mail.MailMessage;
034import org.kuali.rice.coreservice.framework.parameter.ParameterService;
035import org.kuali.rice.krad.service.MailService;
036
037/**
038 * The base implementation of EnterpriseFeederNotificationService; performs email-based notifications
039 */
040public class EnterpriseFeederNotificationServiceImpl implements EnterpriseFeederNotificationService {
041    private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(EnterpriseFeederNotificationServiceImpl.class);
042
043    private ParameterService parameterService;
044    private ConfigurationService configurationService;
045    private MailService mailService;
046
047    /**
048     * Performs notification about the status of the upload (i.e. feeding) of a single file set (i.e. done file, data file, and
049     * recon file).
050     * 
051     * @param feederProcessName The name of the feeder process; this may correspond to the name of the Spring definition of the
052     *        feeder step, but each implementation may define how to use the value of this parameter and/or restrictions on its
053     *        value.
054     * @param event The event/status of the upload of the file set
055     * @param doneFile The done file
056     * @param dataFile The data file
057     * @param reconFile The recon file
058     * @param errorMessages Any error messages for which to provide notification
059     * @see org.kuali.ole.gl.batch.service.EnterpriseFeederNotificationService#notifyFileFeedStatus(java.lang.String,
060     *      org.kuali.module.gl.util.EnterpriseFeederEvent, java.io.File, java.io.File, java.io.File, java.util.List)
061     */
062    @Override
063    public void notifyFileFeedStatus(String feederProcessName, EnterpriseFeederStatus status, File doneFile, File dataFile, File reconFile, List<Message> errorMessages) {
064        String doneFileDescription = doneFile == null ? "Done file missing" : doneFile.getAbsolutePath();
065        String dataFileDescription = dataFile == null ? "Data file missing" : dataFile.getAbsolutePath();
066        String reconFileDescription = reconFile == null ? "Recon file missing" : reconFile.getAbsolutePath();
067
068        // this implementation does not use the contents of the file, so we don't bother opening up the files
069        notifyFileFeedStatus(feederProcessName, status, doneFileDescription, null, dataFileDescription, null, reconFileDescription, null, errorMessages);
070    }
071
072    /**
073     * Performs notifications
074     * 
075     * @param feederProcessName The name of the feeder process; this may correspond to the name of the Spring definition of the
076     *        feeder step, but each implementation may define how to use the value of this parameter and/or restrictions on its
077     *        value.
078     * @param status The event/status of the upload of the file set
079     * @param doneFileDescription The file name
080     * @param doneFileContents Not used; can be set to null
081     * @param dataFileDescription The file name
082     * @param dataFileContents Not used; can be set to null
083     * @param reconFileDescription The file name
084     * @param reconFileContents Not used; can be set to null
085     * @param errorMessages Any error messages for which to provide notification
086     * @see org.kuali.ole.gl.batch.service.EnterpriseFeederNotificationService#notifyFileFeedStatus(java.lang.String,
087     *      org.kuali.module.gl.util.EnterpriseFeederEvent, java.lang.String, java.io.InputStream, java.lang.String,
088     *      java.io.InputStream, java.lang.String, java.io.InputStream, java.util.List)
089     */
090    @Override
091    public void notifyFileFeedStatus(String feederProcessName, EnterpriseFeederStatus status, String doneFileDescription, InputStream doneFileContents, String dataFileDescription, InputStream dataFileContents, String reconFileDescription, InputStream reconFileContents, List<Message> errorMessages) {
092        try {
093            if (isStatusNotifiable(feederProcessName, status, doneFileDescription, dataFileDescription, reconFileDescription, errorMessages)) {
094                Set<String> toEmailAddresses = generateToEmailAddresses(feederProcessName, status, doneFileDescription, dataFileDescription, reconFileDescription, errorMessages);
095
096                MailMessage mailMessage = new MailMessage();
097                String returnAddress = parameterService.getParameterValueAsString(OleParameterConstants.GENERAL_LEDGER_BATCH.class, OLEConstants.FROM_EMAIL_ADDRESS_PARM_NM);
098                if(StringUtils.isEmpty(returnAddress)) {
099                    returnAddress = mailService.getBatchMailingList();
100                }
101                mailMessage.setFromAddress(returnAddress);
102                mailMessage.setToAddresses(toEmailAddresses);
103                mailMessage.setSubject(getSubjectLine(doneFileDescription, dataFileDescription, reconFileDescription, errorMessages, feederProcessName, status));
104                mailMessage.setMessage(buildFileFeedStatusMessage(doneFileDescription, dataFileDescription, reconFileDescription, errorMessages, feederProcessName, status));
105
106                mailService.sendMessage(mailMessage);
107            }
108        }
109        catch (Exception e) {
110            // Have to try to prevent notification exceptions from breaking control flow in the caller
111            // log and swallow the exception
112            LOG.error("Error occured trying to send notifications.", e);
113        }
114    }
115
116    /**
117     * Generates the destination address(s) for the email notifications, possibly depending on the parameter values
118     * 
119     * @param feederProcessName The name of the feeder process; this may correspond to the name of the Spring definition of the
120     *        feeder step, but each implementation may define how to use the value of this parameter and/or restrictions on its
121     *        value.
122     * @param status The event/status of the upload of the file set
123     * @param doneFileDescription The file name
124     * @param dataFileDescription The file name
125     * @param reconFileDescription The file name
126     * @param errorMessages Any error messages for which to provide notification
127     * @return the destination addresses
128     */
129    protected Set<String> generateToEmailAddresses(String feederProcessName, EnterpriseFeederStatus status, String doneFileDescription, String dataFileDescription, String reconFileDescription, List<Message> errorMessages) {
130        Set<String> addresses = new HashSet<String>();
131        Collection<String> addressesArray = parameterService.getParameterValuesAsString(EnterpriseFeedStep.class, OLEConstants.EnterpriseFeederApplicationParameterKeys.TO_ADDRESS);
132        for (String address : addressesArray) {
133            addresses.add(address);
134        }
135        return addresses;
136    }
137
138    /**
139     * Generates the "From:" address for the email
140     * 
141     * @param feederProcessName The name of the feeder process; this may correspond to the name of the Spring definition of the
142     *        feeder step, but each implementation may define how to use the value of this parameter and/or restrictions on its
143     *        value.
144     * @param status The event/status of the upload of the file set
145     * @param doneFileDescription The file name
146     * @param dataFileDescription The file name
147     * @param reconFileDescription The file name
148     * @param errorMessages Any error messages for which to provide notification
149     * @return the source address
150     */
151    protected String generateFromEmailAddress(String feederProcessName, EnterpriseFeederStatus status, String doneFileDescription, String dataFileDescription, String reconFileDescription, List<Message> errorMessages) {
152        return mailService.getBatchMailingList();
153    }
154
155    /**
156     * Generates the status message that would be generated by a call to notifyFileFeedStatus with the same parameters.
157     * 
158     * @param feederProcessName The name of the feeder process; this may correspond to the name of the Spring definition of the
159     *        feeder step, but each implementation may define how to use the value of this parameter and/or restrictions on its
160     *        value.
161     * @param event The event/status of the upload of the file set
162     * @param doneFile The done file
163     * @param dataFile The data file
164     * @param reconFile The recon file
165     * @param errorMessages Any error messages for which to provide notification
166     * @see org.kuali.ole.gl.batch.service.EnterpriseFeederNotificationService#getFileFeedStatusMessage(java.lang.String,
167     *      org.kuali.module.gl.util.EnterpriseFeederEvent, java.io.File, java.io.File, java.io.File, java.util.List)
168     */
169    @Override
170    public String getFileFeedStatusMessage(String feederProcessName, EnterpriseFeederStatus status, File doneFile, File dataFile, File reconFile, List<Message> errorMessages) {
171        String doneFileDescription = doneFile.getAbsolutePath();
172        String dataFileDescription = dataFile.getAbsolutePath();
173        String reconFileDescription = reconFile.getAbsolutePath();
174
175        return buildFileFeedStatusMessage(doneFileDescription, dataFileDescription, reconFileDescription, errorMessages, feederProcessName, status);
176    }
177
178    /**
179     * @see org.kuali.ole.gl.batch.service.EnterpriseFeederNotificationService#getFileFeedStatusMessage(java.lang.String,
180     *      org.kuali.module.gl.util.EnterpriseFeederEvent, java.lang.String, java.io.InputStream, java.lang.String,
181     *      java.io.InputStream, java.lang.String, java.io.InputStream, java.util.List)
182     */
183    @Override
184    public String getFileFeedStatusMessage(String feederProcessName, EnterpriseFeederStatus status, String doneFileDescription, InputStream doneFileContents, String dataFileDescription, InputStream dataFileContents, String reconFileDescription, InputStream reconFileContents, List<Message> errorMessages) {
185        return buildFileFeedStatusMessage(doneFileDescription, dataFileDescription, reconFileDescription, errorMessages, feederProcessName, status);
186    }
187
188    /**
189     * Builds the status message for the status of a feed.
190     * 
191     * @param doneFileDescription the name of the done file
192     * @param dataFileDescription the name of the file to read data from
193     * @param reconFileDescription the name of the reconciliation file
194     * @param errorMessages a List of error messages
195     * @param feederProcessName the name of the feeder process
196     * @return the String of the subject line
197     */
198    protected String getSubjectLine(String doneFileDescription, String dataFileDescription, String reconFileDescription, List<Message> errorMessages, String feederProcessName, EnterpriseFeederStatus status) {
199        String subject = configurationService.getPropertyValueAsString(OLEKeyConstants.ERROR_ENTERPRISE_FEEDER_RECONCILIATION_OR_LOADING_ERROR);
200        if (subject == null) {
201            return "ERROR in reconciling or loading GL origin entries from file.";
202        }
203        String productionEnvironmentCode = configurationService.getPropertyValueAsString(OLEConstants.PROD_ENVIRONMENT_CODE_KEY);
204        String environmentCode = configurationService.getPropertyValueAsString(OLEConstants.ENVIRONMENT_KEY);
205        if (!StringUtils.equals(productionEnvironmentCode, environmentCode)) {
206            subject = environmentCode + ": " + subject;
207        }
208        return subject;
209    }
210
211    /**
212     * Builds the status message for the status of a feed.
213     * 
214     * @param doneFileName the name of the done file
215     * @param dataFileName the name of the file to get data from
216     * @param reconFileName the reconciliation file
217     * @param errorMessages a List of error messages generated during the process
218     * @param feederProcessName the name of the feeder process
219     * @return a String with the status message
220     */
221    protected String buildFileFeedStatusMessage(String doneFileName, String dataFileName, String reconFileName, List<Message> errorMessages, String feederProcessName, EnterpriseFeederStatus status) {
222        StringBuilder buf = new StringBuilder();
223
224        buf.append("Data file: ").append(dataFileName).append("\n");
225        buf.append("Reconciliation File: ").append(reconFileName).append("\n");
226        buf.append("Done file: ").append(doneFileName).append("\n\n\n");
227
228        buf.append("Status: ").append(status.getStatusDescription()).append("\n\n\n");
229
230        if (status.isErrorEvent()) {
231            buf.append("The done file has been removed and ");
232            if (StringUtils.isNotBlank(feederProcessName)) {
233                buf.append(feederProcessName);
234            }
235            else {
236                buf.append("<process name unavailable>");
237            }
238            buf.append(" will continue without processing this set of files (see below).");
239
240            buf.append("  Please correct and resend the files for the next day's batch.");
241        }
242
243        buf.append("\n\n");
244
245        if (!errorMessages.isEmpty()) {
246            buf.append("Error/warning messages:\n");
247            for (Message message : errorMessages) {
248                if (message.getType() == Message.TYPE_FATAL) {
249                    buf.append("ERROR: ");
250                }
251                if (message.getType() == Message.TYPE_WARNING) {
252                    buf.append("WARNING: ");
253                }
254                buf.append(message.getMessage()).append("\n");
255            }
256        }
257
258        return buf.toString();
259    }
260
261    /**
262     * Returns whether a notification is necessary given the values of the parameters
263     * 
264     * @param feederProcessName the name of the process that invoked the feeder
265     * @param status the status of the feed
266     * @param doneFileDescription the done file description
267     * @param dataFileDescription the data file description
268     * @param reconFileDescription the recon file description
269     * @param errorMessages a list of error messages
270     * @return whether to notify
271     */
272    protected boolean isStatusNotifiable(String feederProcessName, EnterpriseFeederStatus status, String doneFileDescription, String dataFileDescription, String reconFileDescription, List<Message> errorMessages) {
273        if (status instanceof FileReconOkLoadOkStatus) {
274            return false;
275        }
276        return true;
277    }
278
279
280    /**
281     * Sets the mailService attribute value.
282     * 
283     * @param mailService The mailService to set.
284     */
285    public void setMailService(MailService mailService) {
286        this.mailService = mailService;
287    }
288
289    public void setConfigurationService(ConfigurationService configurationService) {
290        this.configurationService = configurationService;
291    }
292
293    public void setParameterService(ParameterService parameterService) {
294        this.parameterService = parameterService;
295    }
296}