hsa.awp.scire.controller.ScireController.java Source code

Java tutorial

Introduction

Here is the source code for hsa.awp.scire.controller.ScireController.java

Source

/*
 * Copyright (c) 2010-2012 Matthias Klass, Johannes Leimer,
 *               Rico Lieback, Sebastian Gabriel, Lothar Gesslein,
 *               Alexander Rampp, Kai Weidner
 *
 * This file is part of the Physalix Enrollment System
 *
 * Foobar is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Foobar is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
 */

package hsa.awp.scire.controller;

import hsa.awp.campaign.facade.CampaignFacade;
import hsa.awp.campaign.facade.ICampaignFacade;
import hsa.awp.campaign.model.Campaign;
import hsa.awp.campaign.model.DrawProcedure;
import hsa.awp.campaign.model.FifoProcedure;
import hsa.awp.campaign.model.Procedure;
import hsa.awp.common.exception.DataAccessException;
import hsa.awp.common.exception.NoMatchingElementException;
import hsa.awp.common.util.GenericUtil;
import hsa.awp.common.util.ITimerTaskFactory;
import hsa.awp.scire.procedureLogic.DrawProcedureLogic;
import hsa.awp.scire.procedureLogic.FifoProcedureLogic;
import hsa.awp.scire.procedureLogic.IProcedureLogic;
import hsa.awp.scire.procedureLogic.IProcedureLogicFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;

import javax.persistence.EntityManager;
import java.util.*;

/**
 * Controller class managing currently active {@link Procedure}s, looking for new and finalizing expired ones.
 *
 * @author klassm
 * @author johannes
 */
public class ScireController implements IScireController {
    /**
     * {@link CampaignFacade}.
     */
    private ICampaignFacade campaignFacade;

    /**
     * time interval the {@link ScireController} checks for newly active {@link Procedure}s.
     */
    private int checkInterval = 500;

    /**
     * Calendar object symbolizing the time when the Controller has last checked the state of its {@link Procedure}s.
     */
    private Calendar lastCheck;

    /**
     * Default logger.
     */
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * {@link IProcedureLogicFactory}.
     */
    private IProcedureLogicFactory procedureLogicFactory;

    /**
     * ProcedureLogic types.
     */
    private Set<Class<? extends IProcedureLogic<?>>> procedureTypes = new HashSet<Class<? extends IProcedureLogic<?>>>();

    /**
     * Currently active {@link Procedure}s.
     */
    private Set<IProcedureLogic<? extends Procedure>> runningProcedures;

    /**
     * Timer object calling the check method in a periodical time period.
     */
    private Timer timer;

    /**
     * The TimerTaskFactory which wraps a {@link TimerTask} into an open {@link EntityManager}.
     */
    private ITimerTaskFactory timerTaskFactory;

    /**
     * Boolean variable being true if the timer checking for updated states of the {@link Procedure}s is running.
     */
    private boolean timerIsRunning = false;

    /**
     * Default constructor.
     */
    public ScireController() {

        logger.info("creating Scire controller");

        this.runningProcedures = new HashSet<IProcedureLogic<? extends Procedure>>();

        procedureTypes.add(FifoProcedureLogic.class);
        procedureTypes.add(DrawProcedureLogic.class);
    }

    @Override
    public synchronized Collection<Campaign> findActiveCampaigns() {

        if (!isCheckingForProcedureStates()) {
            throw new IllegalStateException("ScireController is not checking for new Procedures");
        }

        Collection<Campaign> active = campaignFacade.findActiveCampaigns();

        if (active.size() != runningProcedures.size()) {
            check();
        }

        return active;
    }

    @Override
    public synchronized IProcedureLogic<? extends Procedure> findActiveLogicByCampaign(Campaign campaign) {

        if (campaign == null) {
            throw new IllegalArgumentException("no campaign given");
        }

        logger.trace("searching for campaign {}", campaign.getName());

        for (IProcedureLogic<? extends Procedure> logic : runningProcedures) {
            Procedure proc = logic.getProcedure();
            logger.trace("campaign of {} logic is {}", proc.getName(), proc.getCampaign().getName());
            if (proc.getCampaign().equals(campaign)) {
                return logic;
            }
        }
        throw new NoMatchingElementException("No matching campaign found");
    }

    @Override
    public synchronized IProcedureLogic<? extends Procedure> findActiveLogicByProcedure(Long id) {

        if (id == null) {
            throw new IllegalArgumentException("no id given");
        }

        for (IProcedureLogic<? extends Procedure> logic : runningProcedures) {
            if (logic.getProcedure().getId().equals(id)) {
                return logic;
            }
        }
        return null;
    }

    @Override
    public synchronized IProcedureLogic<? extends Procedure> findActiveLogicByProcedure(Procedure proc) {

        if (proc == null) {
            throw new IllegalArgumentException("no Procedure given");
        }
        return findActiveLogicByProcedure(proc.getId());
    }

    @Override
    public Set<IProcedureLogic<? extends Procedure>> getRunningProcedures() {
        checkForDeletedCampaignsOrProcedures();

        return new HashSet<IProcedureLogic<? extends Procedure>>(runningProcedures);
    }

    @Override
    public int getTimerInterval() {

        return checkInterval;
    }

    @Override
    public boolean isCheckingForProcedureStates() {

        return timerIsRunning;
    }

    @Override
    public void setProcedureLogicTypeList(Set<Class<? extends IProcedureLogic<?>>> types) {

        if (types == null) {
            throw new IllegalArgumentException("no set given");
        }
        this.procedureTypes = types;
    }

    @Override
    public synchronized void setTimerInterval(int interval) {

        if (interval < 0) {
            throw new IllegalArgumentException("argument must be at least 1 minute (60.000 millisecods)");
        }

        logger.debug("setting refresh interval to {}. Old value was {}", interval, this.checkInterval);
        this.checkInterval = interval;

        if (timerIsRunning) {
            stopTimer();
            startTimer();
        }
    }

    /**
     * Starts the timer if it is currently running.
     */
    @Override
    public synchronized void startTimer() {

        if (timerIsRunning) {
            throw new IllegalStateException("timer is already running.");
        }
        logger.debug("starting timer");

        lastCheck = Calendar.getInstance();
        lastCheck.add(Calendar.YEAR, -30);

        timer = new Timer();
        timer.scheduleAtFixedRate(timerTaskFactory.getTask(new Runnable() {
            @Override
            public void run() {
                // TODO remove that one!!!
                SecurityContextHolder.getContext()
                        .setAuthentication(new UsernamePasswordAuthenticationToken("admin", "password"));
                try {
                    check();
                } catch (Throwable e) {
                    logger.error(e.toString(), e);
                }
            }
        }), 0, checkInterval);
        timerIsRunning = true;
    }

    @Override
    public synchronized void stopTimer() {

        if (!timerIsRunning) {
            throw new IllegalStateException("cannot stop timer - it is not running at the moment");
        }
        logger.debug("stopping timer");

        timer.cancel();
        timerIsRunning = false;
    }

    /**
     * Adds a new procedure logic type.
     *
     * @param type procedure logic type.
     */
    public synchronized void addProcedureLogicType(Class<? extends IProcedureLogic<?>> type) {

        procedureTypes.add(type);
    }

    /**
     * Checks the {@link Procedure}s whether their states have changed.
     */
    private synchronized void check() {

        logger.debug("starting check for procedure states");

        logger.debug("looking for deleted campaigns/procedures");

        checkForDeletedCampaignsOrProcedures();

        Set<IProcedureLogic<? extends Procedure>> procedures = new HashSet<IProcedureLogic<? extends Procedure>>(
                runningProcedures);
        Calendar now = Calendar.getInstance();

        logger.debug("looking for no longer active procedures");
        for (IProcedureLogic<? extends Procedure> logic : procedures) {
            Procedure proc = logic.getProcedure();

            logger.trace("checking {}", proc.getName());

            // is over?
            if (proc.getEndDate().compareTo(now) <= 0) {
                logger.debug("finish {}", logic);
                logic.afterActive();
                runningProcedures.remove(logic);
            } else {
                // notify running
                logic.whileActive();
            }
        }

        logger.debug("looking for newly active procedures");

        List<Campaign> activeCampaigns = campaignFacade.findActiveCampaigns();
        logger.debug("active campaigns: {}", activeCampaigns);

        for (Campaign campaign : activeCampaigns) {
            Procedure activeProcedure = campaign.findCurrentProcedure();
            if (activeProcedure != null && !isProcedureKnown(activeProcedure)) {
                logger.debug("found new Procedure: {}", activeProcedure.getName());

                for (Class<? extends IProcedureLogic<? extends Procedure>> logicClass : procedureTypes) {
                    Class<? extends Procedure> typeClass = GenericUtil.searchForTypeArgument(logicClass,
                            activeProcedure.getClass());
                    if (typeClass != null) {
                        IProcedureLogic<?> logic = procedureLogicFactory.getInstance(logicClass);
                        logic.setProcedure(activeProcedure);

                        logic.beforeActive();

                        runningProcedures.add(logic);

                        logger.debug("added procedure as active: {} : {}", activeProcedure.getName(),
                                logic.getClass());
                    }
                }
            }
        }
    }

    private void checkForDeletedCampaignsOrProcedures() {

        Set<IProcedureLogic<? extends Procedure>> procedureLogicsForDeletion = new HashSet<IProcedureLogic<? extends Procedure>>();

        for (IProcedureLogic<? extends Procedure> procedureLogic : runningProcedures) {
            Procedure procedure = procedureLogic.getProcedure();

            if (procedure instanceof DrawProcedure) {
                try {
                    procedure = campaignFacade.getDrawProcedureById(procedure.getId());
                } catch (DataAccessException ex) {
                    procedureLogicsForDeletion.add(procedureLogic);
                }
            } else if (procedure instanceof FifoProcedure) {
                try {
                    procedure = campaignFacade.getFifoProcedureById(procedure.getId());
                } catch (DataAccessException ex) {
                    procedureLogicsForDeletion.add(procedureLogic);
                }
            }

            try {
                Campaign campaign = procedure.getCampaign();
                if (campaign != null) {
                    campaignFacade.getCampaignById(campaign.getId());
                } else {
                    procedureLogicsForDeletion.add(procedureLogic);
                }
            } catch (DataAccessException ex) {
                procedureLogicsForDeletion.add(procedureLogic);
            }
        }

        for (IProcedureLogic<? extends Procedure> procedureLogic : procedureLogicsForDeletion) {
            logger.debug(
                    "removing procedure '" + procedureLogic.getProcedure().getName() + "' from running procedures");
            runningProcedures.remove(procedureLogic);
        }

    }

    /**
     * This method will return true if the given {@link Procedure} is already known as running {@link Procedure}.
     *
     * @param procedure {@link Procedure} to check.
     * @return true if the {@link Procedure} is given.
     */
    private boolean isProcedureKnown(Procedure procedure) {

        if (procedure == null) {
            throw new IllegalArgumentException("no Procedure given");
        }

        for (IProcedureLogic<? extends Procedure> logic : runningProcedures) {
            if (logic.getProcedure().equals(procedure)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Setter for campaignFacade.
     *
     * @param campaignFacade the campaignFacade to set
     */
    public void setCampaignFacade(ICampaignFacade campaignFacade) {

        if (campaignFacade == null) {
            throw new IllegalArgumentException("null given, ICampaignFacade expected");
        }

        this.campaignFacade = campaignFacade;
    }

    /**
     * Setter for procedureLogicFactory.
     *
     * @param procedureLogicFactory the procedureLogicFactory to set
     */
    public void setProcedureLogicFactory(IProcedureLogicFactory procedureLogicFactory) {

        this.procedureLogicFactory = procedureLogicFactory;
    }

    public void setTimerTaskFactory(ITimerTaskFactory factory) {

        timerTaskFactory = factory;
    }
}