com.appeligo.alerts.PendingAlertThread.java Source code

Java tutorial

Introduction

Here is the source code for com.appeligo.alerts.PendingAlertThread.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 com.appeligo.alerts;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Transaction;

import com.appeligo.search.entity.Message;
import com.appeligo.search.entity.MessageContextException;
import com.appeligo.search.entity.Permissions;
import com.appeligo.search.entity.User;
import com.knowbout.epg.service.Program;
import com.knowbout.epg.service.ScheduledProgram;
import com.knowbout.hibernate.HibernateUtil;

class PendingAlertThread extends Thread {

    private static final Log log = LogFactory.getLog(PendingAlertThread.class);
    private AlertManager alertManager;
    private boolean isActive;
    private int maxConsecutiveExceptions;
    private String url;

    public PendingAlertThread(Configuration config) {
        super("PendingAlertThread");
        isActive = true;
        alertManager = AlertManager.getInstance();
        maxConsecutiveExceptions = config.getInt("maxConsecutiveExceptions", 10);
        url = config.getString("url", "http://localhost:8080");
    }

    public void run() {
        try {
            Permissions.setCurrentUser(Permissions.SUPERUSER);

            while (isActive()) {

                PendingAlert next = null;

                HibernateUtil.openSession();
                try {
                    next = PendingAlert.getNextAlert();
                } finally {
                    HibernateUtil.closeSession();
                }

                long delay = 0;
                if (next != null) {
                    delay = next.getAlertTime().getTime() - System.currentTimeMillis();
                    log.debug("current time=" + System.currentTimeMillis() + ", next alert time="
                            + next.getAlertTime().getTime());
                }

                while (((delay > 0) || (next == null)) && isActive()) {
                    log.debug("Waiting for next pending alert. next=" + (next == null ? null : next.getId())
                            + ", time before next alert=" + delay);
                    try {
                        synchronized (this) {
                            wait(delay); // value can only be zero (as initialized) or
                                         // a positive value (as checked in while condition).
                                         // wait(0) == wait forever
                        }
                    } catch (InterruptedException e) {
                    }
                    //need to see if there is a newer alert
                    //(in which case, notifyAll was called), or the
                    //alert we were waiting for was deleted
                    delay = 0;
                    HibernateUtil.openSession();
                    try {
                        next = PendingAlert.getNextAlert();
                    } finally {
                        HibernateUtil.closeSession();
                    }
                    if (next != null) {
                        delay = next.getAlertTime().getTime() - System.currentTimeMillis();
                        log.debug("current time=" + System.currentTimeMillis() + ", next alert time="
                                + next.getAlertTime().getTime());
                    }
                }

                if (isActive())
                    log.debug("Ready to fire off at least one pending alert. next=" + next.getId() + ", deleted="
                            + next.isDeleted());

                HibernateUtil.openSession();
                List<PendingAlert> pendingAlerts = PendingAlert.getExpiredAlerts();
                try {
                    if (isActive())
                        log.debug("checking next");
                    for (PendingAlert pendingAlert : pendingAlerts) {
                        if (!isActive()) {
                            break;
                        }
                        log.debug("next");
                        User user = null;
                        int consecutiveExceptions = 0;
                        Transaction transaction = HibernateUtil.currentSession().beginTransaction();
                        try {
                            if (pendingAlert.isDeleted()) {
                                log.debug("deleted");
                                continue;
                            }
                            ProgramAlert programAlert = pendingAlert.getProgramAlert();
                            if (programAlert == null) { // then this should be a manual pending alert
                                pendingAlert.setDeleted(true);
                                pendingAlert.save();
                                if (!pendingAlert.isManual()) {
                                    log.debug("no program alert");
                                    continue;
                                }
                            }
                            user = pendingAlert.getUser();
                            String programId = pendingAlert.getProgramId();
                            if (user == null || programId == null) {
                                log.debug("user (" + user + ") can't be null and programId (" + programId
                                        + ") can't be null");
                                if (programAlert != null) {
                                    programAlert.setDeleted(true);
                                    programAlert.save();
                                }
                                continue;
                            }
                            ScheduledProgram scheduledProgram = alertManager.getEpg()
                                    .getScheduledProgramByNetworkCallSign(pendingAlert.getUser().getLineupId(),
                                            pendingAlert.getCallSign(), pendingAlert.getProgramStartTime());
                            String targetId;
                            if (programAlert == null) {
                                targetId = scheduledProgram.getProgramId();
                            } else {
                                targetId = programAlert.getProgramId();
                                // not a manual alert, so this is the id for the reminder itself
                            }
                            Program targetProgram = alertManager.getEpg().getProgram(targetId);

                            boolean invalidProgramAlert = false;

                            if (scheduledProgram == null) {
                                if (log.isDebugEnabled())
                                    log.debug("no scheduled program");
                            } else {
                                if (!scheduledProgram.getProgramId().equals(programId)) {
                                    invalidProgramAlert = true;
                                    if (log.isDebugEnabled())
                                        log.debug("Schedule must have changed...no matching programId: "
                                                + scheduledProgram.getProgramId() + " != " + programId);
                                } else if (programAlert != null) { // Not a manual (quick) alert
                                    if (programAlert.isDisabled()) {
                                        invalidProgramAlert = true;
                                        if (log.isDebugEnabled())
                                            log.debug("program alert disabled");
                                    } else if (programAlert.isDeleted()) {
                                        invalidProgramAlert = true;
                                        if (log.isDebugEnabled())
                                            log.debug("program alert was deleted");
                                    }
                                }
                            }

                            if ((scheduledProgram != null) && (!invalidProgramAlert)) {

                                boolean scheduledAlert = false;
                                boolean episodeAlert = false;
                                if (programAlert == null) {
                                    scheduledAlert = true;
                                } else {
                                    episodeAlert = true;
                                }

                                log.debug("firing pending alert=" + pendingAlert.getId());

                                Date startTime = scheduledProgram.getStartTime();
                                Date endTime = scheduledProgram.getEndTime();

                                long durationMinutes = (endTime.getTime() - startTime.getTime()) / (60 * 1000);

                                Map<String, String> context = new HashMap<String, String>();

                                DateFormat format = null;
                                DateFormat shortFormat = null;
                                if ((startTime.getTime() - System.currentTimeMillis()) < 12 * 60 * 60 * 1000) {
                                    format = DateFormat.getTimeInstance(DateFormat.SHORT);
                                    shortFormat = DateFormat.getTimeInstance(DateFormat.SHORT);
                                    context.put("timePreposition", "at");
                                } else {
                                    shortFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT,
                                            DateFormat.SHORT);
                                    format = new SimpleDateFormat("EEEE, MMMM d 'at' h:mm a");
                                    context.put("timePreposition", "on");
                                }
                                format.setTimeZone(user.getTimeZone());
                                shortFormat.setTimeZone(user.getTimeZone());
                                context.put("startTime", format.format(startTime));
                                context.put("shortStartTime", shortFormat.format(startTime));

                                context.put("durationMinutes", Long.toString(durationMinutes));
                                context.put("programId", scheduledProgram.getProgramId()); // don't use ID from programAlert
                                // which may be a show, but this may be an episode, or may be a team, but this a game
                                String webPath = scheduledProgram.getWebPath();
                                if (webPath.charAt(0) == '/') {
                                    webPath = webPath.substring(1);
                                }
                                context.put("webPath", webPath);
                                context.put("targetId", targetId);
                                context.put("programLabel", scheduledProgram.getLabel());
                                if (targetId.startsWith("TE")) {
                                    context.put("whatfor", "any game featuring the " + targetProgram.getTeamName());
                                    context.put("reducedTitle40", targetProgram.getReducedTitle40());
                                } else {
                                    context.put("whatfor", "the following program");
                                    context.put("reducedTitle40", scheduledProgram.getReducedTitle40());
                                }
                                if (scheduledProgram.getDescription().trim().length() > 0) {
                                    context.put("description",
                                            "Description: " + scheduledProgram.getDescription() + "<br/>");
                                } else {
                                    context.put("description", "");
                                }
                                context.put("stationName", scheduledProgram.getNetwork().getStationName());
                                String greeting = user.getUsername();
                                context.put("username", greeting);
                                String firstName = user.getFirstName();
                                if (firstName != null && firstName.trim().length() > 0) {
                                    greeting = firstName;
                                }
                                context.put("greeting", greeting);
                                String targetWebPath = targetProgram.getWebPath();
                                if (targetWebPath.charAt(0) == '/') {
                                    targetWebPath = targetWebPath.substring(1);
                                }
                                context.put("showDetailsLink", "<a href=\"" + url + targetWebPath + "#reminders\">"
                                        + url + targetWebPath + "#reminders</a>");
                                if (episodeAlert) {
                                    context.put("deleteRemindersSentence",
                                            "Did you already see this program? If you're done with this reminder, "
                                                    + "<a href=\"" + url
                                                    + "reminders/deleteProgramReminders?programId=" + targetId
                                                    + "\">click here to delete the reminders for this program</a>.");
                                    /*
                                    LATER, REPLACE THE LAST PARAGRAPH ABOVE WITH...
                                    <p>
                                    Did you already see this program?  <a href="${url}reminders/deleteProgramReminders?programId=@programId@">Click
                                    here to delete the reminders for this program</a>\, and if you don't mind\, tell us what you think.
                                    </p>
                                    AND PUT A SIMILAR MESSAGE WITHOUT THE DELETE BUT WITH A LINK IN IF NOT EPISODEREMINDER, in "ELSE" BELOW
                                        */
                                } else {
                                    context.put("deleteRemindersSentence", "");
                                }
                                if ((programAlert != null && programAlert.isUsingPrimaryEmail())
                                        || user.isUsingPrimaryEmailDefault()) {
                                    Message message = new Message("program_reminder_email", context);
                                    if ((startTime.getTime() - System.currentTimeMillis()) > 4 * 60 * 60 * 1000) {
                                        message.setPriority(2);
                                    }
                                    message.setUser(user);
                                    message.setTo(user.getPrimaryEmail());
                                    message.insert();
                                }
                                if ((programAlert != null && programAlert.isUsingSMS()
                                        && user.getSmsEmail().trim().length() > 0) || user.isUsingSMSDefault()) {
                                    Message message = new Message("program_reminder_sms", context);
                                    if ((startTime.getTime() - System.currentTimeMillis()) > 4 * 60 * 60 * 1000) {
                                        message.setPriority(2);
                                    }
                                    message.setUser(user);
                                    message.setTo(user.getSmsEmail());
                                    message.setSms(true);
                                    message.insert();
                                }
                            }
                            consecutiveExceptions = 0;
                        } catch (MessageContextException e) {
                            log.error(
                                    "Software bug resulted in exception with email message context or configuration",
                                    e);
                        } catch (Throwable t) {
                            log.error("Could not complete pending alert execution", t);
                            transaction.rollback();
                            log.error("Caught throwable on pendingAlert " + pendingAlert.getId() + ", user "
                                    + ((user == null) ? null : user.getUsername()), t);
                            consecutiveExceptions++;
                            if (consecutiveExceptions >= maxConsecutiveExceptions) {
                                log.fatal(
                                        "Reached max consecutive exceptions for PendingAlertThread. Exiting thread immediately.");
                                return;
                            }
                        } finally {
                            if (transaction.wasRolledBack()) {
                                transaction = HibernateUtil.currentSession().beginTransaction();
                            }
                            try {
                                log.debug("marking pending alert=" + pendingAlert.getId()
                                        + " as fired. Should see commit message next.");
                                pendingAlert.setFired(true);
                                pendingAlert.save();
                                log.debug("committing after marking pending alert");
                            } catch (Throwable t) {
                                log.error("Coult not mark pending alert", t);
                            } finally {
                                transaction.commit();
                            }
                        }
                    }

                    // Now that we aren't looping on PendingAlerts, I should be able to safely
                    // delete all of the PendingAlerts flagged as deleted without screwing up
                    // paging (if we decide to implement paging up above)
                    Transaction transaction = HibernateUtil.currentSession().beginTransaction();
                    try {
                        log.debug("deleting marked-deleted pending alerts");
                        PendingAlert.deleteAllMarkedDeleted();
                        log.debug("deleted marked-deleted pending alerts");
                        log.debug("deleting marked-fired pending alerts if program has started");
                        PendingAlert.deleteOldFired();
                        log.debug("deleted marked-deleted pending alerts");
                    } finally {
                        transaction.commit();
                    }
                } finally {
                    HibernateUtil.closeSession();
                }
            }
        } catch (Throwable t) {
            log.fatal("Caught unexpected exception, causing abort of thread!", t);
        }
    }

    public boolean isActive() {
        return isActive;
    }

    public void setActive(boolean isActive) {
        this.isActive = isActive;
    }
}