ro.nextreports.server.schedule.RunReportJob.java Source code

Java tutorial

Introduction

Here is the source code for ro.nextreports.server.schedule.RunReportJob.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ro.nextreports.server.schedule;

import java.io.File;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.MessageFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.UUID;
import java.util.ArrayList;

import javax.jcr.RepositoryException;

import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.joda.time.DateTime;
import org.joda.time.Seconds;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mail.javamail.JavaMailSenderImpl;

import ro.nextreports.server.StorageConstants;
import ro.nextreports.server.audit.AuditEvent;
import ro.nextreports.server.audit.Auditor;
import ro.nextreports.server.distribution.Destination;
import ro.nextreports.server.distribution.DestinationType;
import ro.nextreports.server.distribution.DistributionContext;
import ro.nextreports.server.distribution.DistributionException;
import ro.nextreports.server.distribution.Distributor;
import ro.nextreports.server.distribution.DistributorFactory;
import ro.nextreports.server.domain.AclEntry;
import ro.nextreports.server.domain.NextContent;
import ro.nextreports.server.domain.Report;
import ro.nextreports.server.domain.ReportResultEvent;
import ro.nextreports.server.domain.ReportRuntimeTemplate;
import ro.nextreports.server.domain.RunReportHistory;
import ro.nextreports.server.domain.SchedulerBatchDefinition;
import ro.nextreports.server.domain.SchedulerJob;
import ro.nextreports.server.domain.Settings;
import ro.nextreports.server.domain.ShortcutType;
import ro.nextreports.server.domain.SmtpAlertDestination;
import ro.nextreports.server.exception.FormatNotSupportedException;
import ro.nextreports.server.exception.ReportEngineException;
import ro.nextreports.server.report.ReportConstants;
import ro.nextreports.server.report.next.NextUtil;
import ro.nextreports.server.report.util.ReportUtil;
import ro.nextreports.server.service.DataSourceService;
import ro.nextreports.server.service.ReportService;
import ro.nextreports.server.service.SecurityService;
import ro.nextreports.server.service.StorageService;
import ro.nextreports.server.util.ConnectionUtil;
import ro.nextreports.server.util.PermissionUtil;
import ro.nextreports.server.util.StorageUtil;
import ro.nextreports.server.web.language.LanguageManager;
import ro.nextreports.engine.ReportRunner;
import ro.nextreports.engine.ReportRunnerException;
import ro.nextreports.engine.condition.ConditionalExpression;
import ro.nextreports.engine.condition.exception.ConditionalException;
import ro.nextreports.engine.exporter.Alert;
import ro.nextreports.engine.exporter.exception.NoDataFoundException;
import ro.nextreports.engine.queryexec.IdName;
import ro.nextreports.engine.queryexec.QueryParameter;

/**
 * @author Decebal Suiu
 * @author Mihai Dinca-Panaitescu
 */
public class RunReportJob implements Job {

    private static final Logger LOG = LoggerFactory.getLogger(RunReportJob.class);

    public static final String SCHEDULER_JOB = "SCHEDULER_JOB";
    public static final String MAIL_SENDER = "MAIL_SENDER";
    public static final String REPORT_SERVICE = "REPORT_SERVICE";
    public static final String STORAGE_SERVICE = "STORAGE_SERVICE";
    public static final String SECURITY_SERVICE = "SECURITY_SERVICE";
    public static final String DATASOURCE_SERVICE = "DATASOURCE_SERVICE";
    public static final String RUNNER_ID = "RUNNER_ID";
    public static final String RUNNER_TYPE = "RUNNER_TYPE";
    public static final String RUNNER_KEY = "RUNNER_KEY";
    public static final String REPORT_TYPE = "REPORT_TYPE";
    public static final String AUDIT_EVENT = " AUDIT_EVENT";
    public static final String AUDITOR = "AUDITOR";

    private Map<Serializable, String> batchMailMap;

    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap dataMap = context.getMergedJobDataMap();
        SchedulerJob schedulerJob = (SchedulerJob) dataMap.get(SCHEDULER_JOB);

        Report report = schedulerJob.getReport();

        DataSourceService dataSourceService = (DataSourceService) dataMap.get(DATASOURCE_SERVICE);
        StorageService storageService = (StorageService) dataMap.get(STORAGE_SERVICE);
        final JavaMailSenderImpl mailSender = (JavaMailSenderImpl) dataMap.get(MAIL_SENDER);

        if (storageService.getSettings().getMailServer().getUsername() != null) {
            mailSender.setUsername(storageService.getSettings().getMailServer().getUsername());
            mailSender.setPassword(storageService.getSettings().getMailServer().getPassword());
            mailSender.getJavaMailProperties().put("mail.smtp.auth", true);
        } else if (mailSender.getUsername() == null) {
            // username password are not set inside configuration xml file
            mailSender.getJavaMailProperties().put("mail.smtp.auth", false);
        }
        if (storageService.getSettings().getMailServer().getEnableTls() != null) {
            mailSender.getJavaMailProperties().put("mail.smtp.starttls.enable",
                    storageService.getSettings().getMailServer().getEnableTls());
        }

        Locale locale = LanguageManager.getInstance().getLocale(storageService.getSettings().getLanguage());
        ResourceBundle bundle = ResourceBundle.getBundle("ro.nextreports.server.web.NextServerApplication", locale);

        SchedulerBatchDefinition batchDef = schedulerJob.getBatchDefinition();
        List<IdName> batchValues = new ArrayList<IdName>();
        QueryParameter reportParameter = ReportUtil.getBatchQueryParameter(schedulerJob,
                storageService.getSettings());
        if (reportParameter != null) {
            try {
                batchValues = dataSourceService.getParameterValues(report.getDataSource(), reportParameter);
            } catch (Exception e) {
                LOG.error(e.getMessage(), e);
                e.printStackTrace();
            }
        }
        if (batchValues.isEmpty()) {
            executeOneReport(context, bundle, null);
        } else {
            if ((batchDef != null) && (batchDef.getDataQuery() != null)) {
                try {
                    batchMailMap = ReportUtil.getBatchMailMap(batchDef.getDataQuery(), storageService,
                            report.getDataSource());
                } catch (Exception e) {
                    LOG.error(e.getMessage(), e);
                }
            }
            for (IdName batchValue : batchValues) {
                schedulerJob.getReportRuntime().updateParameterValue(reportParameter.getName(), batchValue);
                executeOneReport(context, bundle, batchValue);
            }
        }
    }

    private void executeOneReport(JobExecutionContext context, ResourceBundle bundle, IdName batchValue) {

        JobDataMap dataMap = context.getMergedJobDataMap();
        SchedulerJob schedulerJob = (SchedulerJob) dataMap.get(SCHEDULER_JOB);
        Report report = schedulerJob.getReport();

        ReportService reportService = (ReportService) dataMap.get(REPORT_SERVICE);
        DataSourceService dataSourceService = (DataSourceService) dataMap.get(DATASOURCE_SERVICE);
        StorageService storageService = (StorageService) dataMap.get(STORAGE_SERVICE);
        final SecurityService securityService = (SecurityService) dataMap.get(SECURITY_SERVICE);

        List<Destination> destinations = schedulerJob.getDestinations();
        final JavaMailSenderImpl mailSender = (JavaMailSenderImpl) dataMap.get(MAIL_SENDER);
        final String mailFrom = storageService.getSettings().getMailServer().getFrom();
        String reportsPath = new File(storageService.getSettings().getReportsHome()).getAbsolutePath();

        Auditor auditor = (Auditor) dataMap.get(AUDITOR);
        AuditEvent auditEvent = (AuditEvent) dataMap.get(AUDIT_EVENT);
        String runnerType = dataMap.getString(RUNNER_TYPE);
        String runnerId = dataMap.getString(RUNNER_ID);
        String creator = "";
        AclEntry[] granted = securityService.getGrantedById(report.getId());
        if (RunReportHistory.SCHEDULER.equals(runnerType)) {
            creator = schedulerJob.getCreatedBy();
        } else if (RunReportHistory.USER.equals(runnerType)) {
            try {
                creator = storageService.getEntityById(runnerId).getName();
            } catch (Exception e) {
                e.printStackTrace();
                LOG.error(e.getMessage(), e);
            }
        }
        String key = dataMap.getString(RUNNER_KEY);

        boolean error = false;
        String message = "Ok";
        String url = "";
        String fileName = null;
        Connection connection = null;
        try {
            /*
               try {
               Thread.sleep(2 * 60 * 1000);
               } catch (InterruptedException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
               }
               */

            // for Scheduled reports
            // take care for INTERVAL template values
            // and set start_date and end_date accordingly           
            if (!schedulerJob.isRunNow()) {
                ReportRuntimeTemplate template = schedulerJob.getTemplate();
                if (template != null) {
                    ShortcutType type = template.getShortcutType();
                    if ((type != null) && !ShortcutType.NONE.equals(type)) {
                        Date[] dates = type.getTimeShortcutType().getDates();
                        Map<String, Object> map = schedulerJob.getReportRuntime().getParametersValues();
                        if (map.containsKey(QueryParameter.INTERVAL_START_DATE_NAME)) {
                            Object start = map.get(QueryParameter.INTERVAL_START_DATE_NAME);
                            Object value = null;
                            if (start instanceof Date) {
                                value = dates[0];
                            } else if (start instanceof Timestamp) {
                                value = new Timestamp(dates[0].getTime());
                            } else if (start instanceof Time) {
                                value = new Time(dates[0].getTime());
                            }
                            if (value != null) {
                                schedulerJob.getReportRuntime().updateParameterValue(
                                        QueryParameter.INTERVAL_START_DATE_NAME, (Serializable) value);
                            }
                        }
                        if (map.containsKey(QueryParameter.INTERVAL_END_DATE_NAME)) {
                            Object start = map.get(QueryParameter.INTERVAL_END_DATE_NAME);
                            Object value = null;
                            if (start instanceof Date) {
                                value = dates[1];
                            } else if (start instanceof Timestamp) {
                                value = new Timestamp(dates[1].getTime());
                            } else if (start instanceof Time) {
                                value = new Time(dates[1].getTime());
                            }
                            if (value != null) {
                                schedulerJob.getReportRuntime().updateParameterValue(
                                        QueryParameter.INTERVAL_END_DATE_NAME, (Serializable) value);
                            }
                        }
                    }
                }
            }

            if (LOG.isDebugEnabled()) {
                LOG.debug("Run report '" + report.getPath() + "'");
                // debug runtime parameters
                Map<String, Object> parametersValues = schedulerJob.getReportRuntime().getParametersValues();
                StringBuilder sb = new StringBuilder("\r\nRuntime parameters for '");
                sb.append(report.getPath());
                sb.append("'\r\n");
                sb.append(ReportUtil.getDebugParameters(parametersValues));
                LOG.debug(sb.toString());
            }

            String[] result = new String[2];
            if (report.isAlarmType() || report.isIndicatorType() || report.isDisplayType()) {
                // for alarm alert there is no url
                ro.nextreports.engine.Report nextReport = NextUtil.getNextReport(storageService.getSettings(),
                        (NextContent) report.getContent());
                final ReportRunner reportRunner = new ReportRunner();
                reportRunner.setParameterValues(schedulerJob.getReportRuntime().getParametersValues());
                reportRunner.setReport(nextReport);
                if (report.isAlarmType()) {
                    reportRunner.setFormat(ReportRunner.ALARM_FORMAT);
                } else if (report.isDisplayType()) {
                    reportRunner.setFormat(ReportRunner.DISPLAY_FORMAT);
                } else {
                    reportRunner.setFormat(ReportRunner.INDICATOR_FORMAT);
                }
                try {
                    connection = ConnectionUtil.createConnection(storageService, report.getDataSource());
                } catch (RepositoryException e) {
                    throw new ReportRunnerException("Cannot connect to database", e);
                }
                reportRunner.setConnection(connection);

                List<SmtpAlertDestination> alertDestinations = getAlertDestinations(destinations);
                if (alertDestinations.size() == 0) {
                    LOG.error("Alarm '" + report.getPath() + "' has no alert destination.");
                    ConnectionUtil.closeConnection(connection);
                    return;
                }

                List<Alert> alerts = new ArrayList<Alert>();
                for (final SmtpAlertDestination alertDestination : alertDestinations) {

                    alerts.add(new Alert() {
                        protected boolean isActive(Object value) {
                            ConditionalExpression ce = new ConditionalExpression(alertDestination.getOperator());
                            ce.setRightOperand(ce.getOperand(alertDestination.getRightOperand()));
                            ce.setRightOperand2(ce.getOperand(alertDestination.getRightOperand2()));
                            ce.setLeftOperand((Serializable) value);
                            try {
                                boolean result = ce.evaluate();
                                return result;
                            } catch (ConditionalException e) {
                                e.printStackTrace();
                            }
                            return false;
                        }

                        protected void run(Object value, String message) {
                            Distributor alertDistributor = DistributorFactory
                                    .getDistributor(DestinationType.ALERT.toString());
                            try {
                                DistributionContext distributionContext = new DistributionContext();
                                distributionContext.setSecurityService(securityService);
                                distributionContext.setMailFrom(mailFrom);
                                distributionContext.setMailSender(mailSender);
                                String sValue = (value == null) ? "" : value.toString();
                                String mailMessage = alertDestination.getMailBody().replaceAll("\\$\\{val\\}",
                                        sValue);
                                distributionContext.setMessage(mailMessage);
                                alertDestination.setMailBody(mailMessage);
                                distributionContext.setAlertMessage(message);
                                alertDistributor.distribute(null, alertDestination, distributionContext);
                            } catch (DistributionException e) {
                                String failedMessage = "Distribution " + alertDestination.getName();
                                message += "\r\n" + failedMessage + " : " + e.getMessage();
                                LOG.error(message, e);
                                e.printStackTrace();
                            }
                        }
                    });
                }
                reportRunner.setAlerts(alerts);
                reportRunner.run();
            } else {
                // not null when run
                String author = schedulerJob.getCreator();
                if (author == null) {
                    // when schedule
                    author = schedulerJob.getCreatedBy();
                }
                result = reportService.reportToURL(report, schedulerJob.getReportRuntime(), author, key);
                if (result == null) {
                    fileName = "";
                    url = ReportConstants.ETL_FORMAT;
                } else {
                    fileName = result[0];
                    url = result[1];
                }
            }
        } catch (ReportEngineException e) {
            error = true;
            message = e.getMessage();
            LOG.error(message, e);
            e.printStackTrace();
        } catch (FormatNotSupportedException e) {
            error = true;
            message = e.getMessage();
            LOG.error(message, e);
            e.printStackTrace();
        } catch (NoDataFoundException e) {
            error = false;
            message = bundle.getString("ActionContributor.Run.nodata");
        } catch (InterruptedException e) {
            error = true;
            message = bundle.getString("ActionContributor.Run.interrupted");
        } catch (Throwable t) {
            error = true;
            if (t instanceof OutOfMemoryError) {
                message = bundle.getString("ActionContributor.Run.toomany");
            } else {
                message = t.getMessage();
            }
            LOG.error(message, t);
            t.printStackTrace();
        } finally {
            ConnectionUtil.closeConnection(connection);
            if (RunReportHistory.USER.equals(runnerType)) {
                String eventMessage = error ? bundle.getString("ActionContributor.Run.error") : message;
                String dynamicUrl = "";
                if (!error) {
                    String fName = url.substring(url.lastIndexOf("/") + 1);
                    dynamicUrl = reportService.getReportURL(fName);
                }
                ReportResultEvent event = new ReportResultEvent(creator, report.getName(), dynamicUrl,
                        eventMessage);
                reportService.notifyReportListener(event);
                integrationPost(storageService.getSettings(), event);
            }
        }

        List<Distributor> distributors = new ArrayList<Distributor>();
        DistributionContext distributionContext = new DistributionContext();
        distributionContext.setSecurityService(securityService);
        distributionContext.setStorageService(storageService);
        distributionContext.setDataSource(report.getDataSource());
        distributionContext.setError(error);
        distributionContext.setMailFrom(mailFrom);
        distributionContext.setMailSender(mailSender);
        distributionContext.setMessage(message);
        distributionContext.setReportsPath(reportsPath);
        distributionContext.setUrl(url);
        distributionContext.setReportName(report.getName());
        distributionContext.setParameterValues(schedulerJob.getReportRuntime().getHistoryParametersValues()); // contains also the dynamic values
        if (batchMailMap != null) {
            distributionContext.setBatchMailMap(batchMailMap);
        }
        if (batchValue != null) {
            distributionContext.setBatchValue(batchValue.getId());
        }

        if (fileName != null) {
            int errors = 0;
            File exportedFile = new File(reportsPath, fileName);
            for (Destination destination : destinations) {
                Distributor distributor = DistributorFactory.getDistributor(destination.getType());
                distributors.add(distributor);
                try {
                    distributor.distribute(exportedFile, destination, distributionContext);
                } catch (DistributionException e) {
                    LOG.error(e.getMessage(), e);
                    String s = bundle.getString("ActionContributor.Run.distributionFailed");
                    String failedMessage = MessageFormat.format(s, destination.getName());
                    error = true;
                    if (errors == 0) {
                        message = failedMessage + " : " + e.getMessage();
                    } else {
                        message += "\r\n" + failedMessage + "  : " + e.getMessage();
                    }
                    errors++;
                }
            }
        } else {
            if (!report.isAlarmType() && !report.isIndicatorType() && !report.isDisplayType()) {
                // if 'No data' the email is not sent
                // send error through mail
                if (error) {
                    for (Destination destination : destinations) {
                        if (DestinationType.SMTP.toString().equals(destination.getType())) {
                            Distributor distributor = DistributorFactory.getDistributor(destination.getType());
                            distributors.add(distributor);
                            try {
                                distributor.distribute(null, destination, distributionContext);
                            } catch (DistributionException e) {
                                String s = bundle.getString("ActionContributor.Run.distributionFailed");
                                String failedMessage = MessageFormat.format(s, destination.getName());
                                error = true;
                                message += "\r\n" + failedMessage + " : " + e.getMessage();
                            }
                        }
                    }
                }
            }
        }

        // save history       
        RunReportHistory runHistory = new RunReportHistory();
        String name = UUID.randomUUID().toString();
        runHistory.setName(name);

        String path = null;
        try {
            if (!StorageUtil.isVersion(report)) {
                path = storageService.getEntityById(report.getId()).getPath();
            } else {
                String versionId = StorageUtil.getVersionableId(report);
                path = storageService.getEntityById(versionId).getPath();
            }
        } catch (Exception e) {
            e.printStackTrace();
            LOG.error(e.getMessage(), e);
        }
        path += StorageConstants.PATH_SEPARATOR + "runHistory" + StorageConstants.PATH_SEPARATOR + name;
        runHistory.setPath(path);

        if (LOG.isDebugEnabled()) {
            LOG.debug("Create run history '" + runHistory.getPath() + "'");
        }

        runHistory.setRunnerId(runnerId);
        runHistory.setRunnerType(runnerType);
        runHistory.setStartDate(context.getScheduledFireTime());
        runHistory.setEndDate(new Date());
        runHistory.setDuration(Seconds
                .secondsBetween(new DateTime(runHistory.getStartDate()), new DateTime(runHistory.getEndDate()))
                .getSeconds());
        runHistory.setError(error);
        runHistory.setMessage(message);
        runHistory.setUrl(url);
        runHistory.setParametersValues(schedulerJob.getReportRuntime().getHistoryParametersValues(),
                schedulerJob.getReportRuntime().getHistoryParametersDisplayNames());

        // audit report runs
        auditEvent.setDate(runHistory.getStartDate());
        auditEvent.getContext().put("DURATION", runHistory.getDuration());
        if (error) {
            auditEvent.setErrorMessage(message);
        }
        auditor.logEvent(auditEvent);

        if (!report.isAlarmType() && !report.isIndicatorType() && !report.isIndicatorType()) {
            try {
                storageService.addEntity(runHistory);
            } catch (Exception e) {
                e.printStackTrace();
                LOG.error(e.getMessage(), e);
            }

            // after distribute
            // for send mail distributor : update acl for run report history
            for (Distributor distributor : distributors) {
                distributor.afterDistribute(runHistory, distributionContext);
            }

            // create full permissions for the creator
            if (creator != null) {
                try {
                    securityService.grantUser(path, creator, PermissionUtil.getFullPermissions(), false);
                } catch (Exception e) {
                    e.printStackTrace();
                    LOG.error(e.getMessage(), e);
                }
            }
        }

        // security breach? (reports with data filtered by user)
        // create permissions for those who have permission on report
        //        if (granted != null) {           
        //           for (AclEntry aclEntry :  granted) {               
        //              try {
        //                 if (aclEntry.getType() == AclEntry.USER_TYPE) {
        //                    securityService.grantUser(path, aclEntry.getName(), aclEntry.getPermissions(), false);
        //                 } else if (aclEntry.getType() == AclEntry.GROUP_TYPE) {
        //                    securityService.grantGroup(path, aclEntry.getName(), aclEntry.getPermissions(), false);
        //                 } 
        //                } catch (Exception e) {
        //                    e.printStackTrace();
        //                    LOG.error(e.getMessage(), e);
        //                }
        //           }
        //        }
    }

    private List<SmtpAlertDestination> getAlertDestinations(List<Destination> destinations) {
        List<SmtpAlertDestination> alertDestinations = new ArrayList<SmtpAlertDestination>();
        for (Destination destination : destinations) {
            if (DestinationType.ALERT.toString().equals(destination.getType())) {
                alertDestinations.add((SmtpAlertDestination) destination);
            }
        }
        return alertDestinations;
    }

    private void integrationPost(Settings settings, ReportResultEvent event) {
        String notifyUrl = settings.getIntegration().getNotifyUrl();
        if ((notifyUrl == null) || notifyUrl.equals("")) {
            return;
        }

        DefaultHttpClient httpclient = new DefaultHttpClient();
        try {
            HttpPost httpPost = new HttpPost(notifyUrl);

            List<NameValuePair> nvps = new ArrayList<NameValuePair>();
            nvps.add(new BasicNameValuePair("report", event.getReportName()));
            nvps.add(new BasicNameValuePair("message", event.getResultMessage()));
            nvps.add(new BasicNameValuePair("url", event.getReportUrl()));
            httpPost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));

            //           JSONObject jsonObj = new JSONObject();
            //           jsonObj.put("report", event.getReportName());
            //           jsonObj.put("message", event.getResultMessage());
            //           jsonObj.put("url", event.getReportUrl());           
            //           StringEntity entity = new StringEntity(jsonObj.toString(), HTTP.UTF_8);
            //           entity.setContentType("application/json");           

            httpclient.execute(httpPost);

        } catch (Exception e) {
            e.printStackTrace();
            LOG.error(e.getMessage(), e);
        } finally {
            httpclient.getConnectionManager().shutdown();
        }
    }

}