org.sofun.core.sport.SportsGraphLifeCycleManager.java Source code

Java tutorial

Introduction

Here is the source code for org.sofun.core.sport.SportsGraphLifeCycleManager.java

Source

/*
 * Copyright (c)  Sofun Gaming SAS.
 * Copyright (c)  Julien Anguenot <julien@anguenot.org>
 * Copyright (c)  Julien De Preaumont <juliendepreaumont@gmail.com>
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Julien Anguenot <julien@anguenot.org> - initial API and implementation
*/

package org.sofun.core.sport;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.ejb.ConcurrencyManagement;
import javax.ejb.ConcurrencyManagementType;
import javax.ejb.EJB;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Singleton;
import javax.ejb.Startup;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sofun.core.CoreConstants;
import org.sofun.core.api.local.SportServiceLocal;
import org.sofun.core.api.sport.SportService;
import org.sofun.core.api.sport.tournament.TournamentGame;
import org.sofun.core.api.sport.tournament.TournamentGameStatus;
import org.sofun.core.api.sport.tournament.TournamentRound;
import org.sofun.core.api.sport.tournament.TournamentRoundStatus;
import org.sofun.core.api.sport.tournament.TournamentSeason;
import org.sofun.core.api.sport.tournament.TournamentSeasonStatus;
import org.sofun.core.api.sport.tournament.TournamentStage;
import org.sofun.core.api.sport.tournament.TournamentStageStatus;

/**
 * Sports Graph Life Cycle Manager.
 * 
 * <p>
 * 
 * Singleton handling graph elements (Season, Stage, Round and Game) life cycle.
 * Responsibility is to transition these elements when required.
 * 
 * <p>
 * 
 * Note, the current implementation does not support live betting.
 * 
 * @author <a href="mailto:julien@anguenot.org">Julien Anguenot</a>
 * 
 */
@Startup
@Singleton
@Lock(LockType.READ)
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class SportsGraphLifeCycleManager {

    private static final Log log = LogFactory.getLog(SportsGraphLifeCycleManager.class);

    @EJB(beanName = "SportServiceImpl", beanInterface = SportServiceLocal.class)
    private SportService sports;

    /** Processing lock */
    private boolean available = true;

    /**
     * Returns the reference time for end of predictions.
     * 
     * @return: a {@link Calendar} instance.
     */
    private Calendar getReferenceTime() {
        final Calendar ref = Calendar.getInstance();
        ref.add(Calendar.SECOND, CoreConstants.TIME_TO_BET_BEFORE_EVENT_STARTS);
        return ref;
    }

    /**
     * Checks sports graph elements (Season, Stage, Round and Game) and
     * transitioning their status when needed.
     * 
     * @throws Exception
     */
    // XXX DISABLED
    // @Schedule(minute = "*/5", hour = "*", persistent = false)
    public void check() throws Exception {

        if (!available) {
            return;
        } else {
            available = false;
        }

        try {
            final Calendar ref = getReferenceTime();
            log.debug("Reference time for end of predictions " + ref.getTime().toString());

            // Check scheduled games: This is important for this manager to
            // handle the `scheduled` to `on_going` transition (versus feed
            // provider component). This status conditions the ability for a
            // player to place a bet.
            for (TournamentGame game : sports.getTournamentGamesByStatus(TournamentGameStatus.SCHEDULED)) {
                final Date startDate = game.getStartDate();
                if (startDate != null) {
                    final Calendar calStartDate = Calendar.getInstance();
                    calStartDate.setTime(startDate);
                    if (ref.compareTo(calStartDate) >= 0) {
                        log.info("End of predictions for game with uuid=" + game.getUUID() + " starting @ "
                                + calStartDate.getTime().toString());
                        game.setGameStatus(TournamentGameStatus.ON_GOING);
                    }
                }
            }
            // Check for games that do not have any status. Let's not assume the
            // third party provider never does mistakes.
            for (TournamentGame game : sports.getTournamentGamesByStatus(null)) {
                final Date startDate = game.getStartDate();
                if (startDate != null) {
                    final Calendar calStartDate = Calendar.getInstance();
                    calStartDate.setTime(startDate);
                    if (ref.compareTo(calStartDate) < 0) {
                        log.info("Marking game with uuid=" + game.getUUID()
                                + " as scheduled. Former status was unknown.");
                        game.setGameStatus(TournamentGameStatus.SCHEDULED);
                    } else {
                        log.info("Marking game with uuid=" + game.getUUID()
                                + " as terminated. Former status was unknown.");
                        game.setGameStatus(TournamentGameStatus.TERMINATED);
                    }
                }
            }
            // Subsequent transitions (closed, cancelled, postponed, etc.) will
            // he handled by the component implementing the third party
            // external feed provider (see sofun-platform-opta for instance)

            // Check rounds: `scheduled` -> `on going` -> `terminated`
            for (TournamentRound round : sports.getTournamentRoundsByStatus(TournamentRoundStatus.SCHEDULED)) {
                boolean terminated = true;
                boolean onGoing = false;
                if (round.getGames().size() > 0) {
                    for (TournamentGame game : round.getGames()) {
                        final String gameStatus = game.getGameStatus();
                        if (!(TournamentGameStatus.TERMINATED.equals(gameStatus)
                                || TournamentGameStatus.CANCELLED.equals(gameStatus))) {
                            // One game is still scheduled. Nothing to do.
                            terminated = false;
                            break;
                        }
                        if (TournamentGameStatus.ON_GOING.equals(gameStatus)) {
                            // One game is ongoing and the game is marked as
                            // scheduled. Let's transition round
                            onGoing = true;
                            break;
                        }
                    }
                    if (terminated) {
                        // All games for this round are terminated. Marking
                        // round as terminated.
                        log.info("All games for round w/ UUID=" + String.valueOf(round.getUUID())
                                + " are marked as terminated. Marking round terminated");
                        round.setStatus(TournamentRoundStatus.TERMINATED);
                    }
                    if (onGoing) {
                        log.info("At least one game in round w/ UUID=" + String.valueOf(round.getUUID())
                                + " is marked as ON_GOING. Marking round as ON_GOING");
                        round.setStatus(TournamentRoundStatus.ON_GOING);
                    }
                } else {
                    // Handle case of a rounds with no games. (CY, F1, etc.)
                    final Calendar startDate = Calendar.getInstance();
                    startDate.setTime(round.getStartDate());
                    if (ref.compareTo(startDate) >= 0
                            && TournamentRoundStatus.SCHEDULED.equals(round.getStatus())) {
                        log.info("Round w/ UUID=" + String.valueOf(round.getUUID()) + " is marked as ON_GOING.");
                        round.setStatus(TournamentRoundStatus.ON_GOING);
                    }
                }
            }
            // Check rounds: unknown status
            for (TournamentRound round : sports.getTournamentRoundsByStatus(null)) {
                boolean onGoing = false;
                boolean scheduled = false;
                for (TournamentGame game : round.getGames()) {
                    final String gameStatus = game.getGameStatus();
                    if (TournamentGameStatus.ON_GOING.equals(gameStatus)) {
                        onGoing = true;
                        break;
                    } else if (TournamentGameStatus.SCHEDULED.equals(gameStatus)
                            || TournamentGameStatus.POSTPONED.equals(gameStatus)) {
                        scheduled = true;
                    }
                }
                if (onGoing) {
                    if (!TournamentRoundStatus.ON_GOING.equals(round.getStatus())) {
                        log.info("At least one game in round w/ UUID=" + String.valueOf(round.getUUID())
                                + " is marked as ON_GOING. Marking round as "
                                + "ON_GOING. Former status was unknown");
                        round.setStatus(TournamentRoundStatus.ON_GOING);
                    }
                } else if (scheduled) {
                    if (!TournamentRoundStatus.SCHEDULED.equals(round.getStatus())) {
                        log.info("At least one game in round w/ UUID=" + String.valueOf(round.getUUID())
                                + " is marked as SCHEDULED. Marking round as "
                                + "SCHEDULED. Former status was unknown");
                        round.setStatus(TournamentRoundStatus.SCHEDULED);
                    }
                } else {
                    if (!TournamentRoundStatus.TERMINATED.equals(round.getStatus())) {
                        log.info("No game in round w/ UUID=" + String.valueOf(round.getUUID())
                                + " is marked as SCHEDULED, ON_GOING or " + "POSPONED Marking round as "
                                + "TERMINATED. Former status was unknown");
                        round.setStatus(TournamentRoundStatus.TERMINATED);
                    }
                }

            }

            // Check stages: `scheduled` -> `on going` -> `terminated`
            List<TournamentStage> stages = sports.getTournamentStagesByStatus(TournamentStageStatus.SCHEDULED);
            stages.addAll(sports.getTournamentStagesByStatus(TournamentStageStatus.ON_GOING));
            for (TournamentStage stage : stages) {
                boolean terminated = true;
                boolean onGoing = false;
                for (TournamentRound round : stage.getRounds()) {
                    final String roundStatus = round.getStatus();
                    if (TournamentRoundStatus.ON_GOING.equals(roundStatus)) {
                        // One round is ongoing and the stage is marked as
                        // scheduled. Let's transition stage
                        terminated = false;
                        onGoing = true;
                        break;
                    }
                    if (!(TournamentRoundStatus.TERMINATED.equals(roundStatus)
                            || TournamentRoundStatus.CANCELLED.equals(roundStatus))) {
                        // One round is still scheduled. Nothing to do.
                        terminated = false;
                        break;
                    }
                }
                if (terminated) {
                    // All rounds for this stage are terminated. Marking stage
                    // as terminated.
                    if (!TournamentStageStatus.TERMINATED.equals(stage.getStatus())) {
                        log.info("All rounds for stage w/ UUID=" + String.valueOf(stage.getUUID())
                                + " are marked as terminated. Marking stage terminated");
                        stage.setStatus(TournamentStageStatus.TERMINATED);
                    }
                }
                if (onGoing) {
                    if (!TournamentStageStatus.ON_GOING.equals(stage.getStatus())) {
                        log.info("At least one round in stage w/ UUID=" + String.valueOf(stage.getUUID())
                                + " is marked as ON_GOING. Marking stage as ON_GOING");
                        stage.setStatus(TournamentStageStatus.ON_GOING);
                    }
                }
            }
            // Check stages: unknown status
            for (TournamentStage stage : sports.getTournamentStagesByStatus(null)) {
                boolean onGoing = false;
                boolean scheduled = false;
                for (TournamentRound round : stage.getRounds()) {
                    final String roundStatus = round.getStatus();
                    if (TournamentRoundStatus.ON_GOING.equals(roundStatus)) {
                        onGoing = true;
                        break;
                    } else if (TournamentRoundStatus.SCHEDULED.equals(roundStatus)
                            || TournamentRoundStatus.POSTPONED.equals(roundStatus)) {
                        scheduled = true;
                    }
                }
                if (onGoing) {
                    log.info("At least one round in stage w/ UUID=" + String.valueOf(stage.getUUID())
                            + " is marked as ON_GOING. Marking stage as " + "ON_GOING. Former status was unknown");
                    stage.setStatus(TournamentStageStatus.ON_GOING);
                } else if (scheduled) {
                    log.info("At least one round in stage w/ UUID=" + String.valueOf(stage.getUUID())
                            + " is marked as SCHEDULED. Marking stage as "
                            + "SCHEDULED. Former status was unknown");
                    stage.setStatus(TournamentStageStatus.SCHEDULED);
                } else {
                    log.info("No round in stage w/ UUID=" + String.valueOf(stage.getUUID())
                            + " is marked as SCHEDULED, ON_GOING or " + "POSPONED Marking stage as "
                            + "TERMINATED. Former status was unknown");
                    stage.setStatus(TournamentStageStatus.TERMINATED);
                }

            }

            // Check seasons: `scheduled` -> `on going` -> `terminated`
            for (TournamentSeason season : sports.getTournamentSeasonsByStatus(TournamentSeasonStatus.SCHEDULED)) {
                boolean terminated = true;
                boolean onGoing = false;
                for (TournamentStage stage : season.getStages()) {
                    final String stageStatus = stage.getStatus();
                    if (TournamentStageStatus.ON_GOING.equals(stageStatus)) {
                        // One stage is ongoing and the season is marked as
                        // scheduled. Let's transition stage
                        onGoing = true;
                        terminated = false;
                        break;
                    }
                    if (!(TournamentStageStatus.TERMINATED.equals(stageStatus)
                            || TournamentStageStatus.CANCELLED.equals(stageStatus))) {
                        // One stage is still scheduled. Nothing to do.
                        terminated = false;
                        break;
                    }
                }
                if (terminated) {
                    // All stages for this stage are terminated. Marking season
                    // as terminated.
                    log.info("All stages for season w/ UUID=" + String.valueOf(season.getUUID())
                            + " are marked as terminated. Marking season terminated");
                    season.setStatus(TournamentSeasonStatus.TERMINATED);
                }
                if (onGoing) {
                    log.info("At least one stage in season w/ UUID=" + String.valueOf(season.getUUID())
                            + " is marked as ON_GOING. Marking season as ON_GOING");
                    season.setStatus(TournamentSeasonStatus.ON_GOING);
                }
            }
            // Check seasons: unknown status
            for (TournamentSeason season : sports.getTournamentSeasonsByStatus(null)) {
                boolean onGoing = false;
                boolean scheduled = false;
                for (TournamentStage stage : season.getStages()) {
                    final String stageStatus = stage.getStatus();
                    if (TournamentStageStatus.ON_GOING.equals(stageStatus)) {
                        onGoing = true;
                        break;
                    } else if (TournamentStageStatus.SCHEDULED.equals(stageStatus)
                            || TournamentStageStatus.POSTPONED.equals(stageStatus)) {
                        scheduled = true;
                    }
                }
                if (onGoing) {
                    log.info("At least one stage in season w/ UUID=" + String.valueOf(season.getUUID())
                            + " is marked as ON_GOING. Marking season as " + "ON_GOING. Former status was unknown");
                    season.setStatus(TournamentSeasonStatus.ON_GOING);
                } else if (scheduled) {
                    log.info("At least one stage in season w/ UUID=" + String.valueOf(season.getUUID())
                            + " is marked as SCHEDULED. Marking season as "
                            + "SCHEDULED. Former status was unknown");
                    season.setStatus(TournamentSeasonStatus.SCHEDULED);
                } else {
                    log.info("No stage in season w/ UUID=" + String.valueOf(season.getUUID())
                            + " is marked as SCHEDULED, ON_GOING or " + "POSPONED Marking season as "
                            + "TERMINATED. Former status was unknown");
                    season.setStatus(TournamentSeasonStatus.TERMINATED);
                }

            }
        } finally {
            available = true;
        }

    }
}