com.sfs.captor.controller.AlternativeFlowAction.java Source code

Java tutorial

Introduction

Here is the source code for com.sfs.captor.controller.AlternativeFlowAction.java

Source

/*
 * South Face Software
 * Copyright 2012, South Face Software, Inc. and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package com.sfs.captor.controller;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import javax.ejb.Stateful;
import javax.enterprise.context.ConversationScoped;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.primefaces.context.RequestContext;
import org.primefaces.event.SelectEvent;
import org.slf4j.Logger;

import com.sfs.captor.data.Literal;
import com.sfs.captor.exception.UCMException;
import com.sfs.captor.model.Actor;
import com.sfs.captor.model.AuthUser;
import com.sfs.captor.model.Flow;
import com.sfs.captor.model.FlowStep;
import com.sfs.captor.model.FlowStepRule;
import com.sfs.captor.model.Project;
import com.sfs.captor.model.TestCase;
import com.sfs.captor.model.UseCase;
import com.sfs.captor.security.AccessManager;
import com.sfs.captor.service.ProjectService;
import com.sfs.captor.util.Authenticated;
import com.sfs.captor.util.ProjectActorInit;
import com.sfs.captor.util.Service;
import com.sfs.captor.view.FacesContextMessage;

/**
 * AlternativeFlow Actions
 * 
 * @author lbbishop
 */
@Stateful
@ConversationScoped
@Named("alternativeFlowAction")
public class AlternativeFlowAction extends ActionBase implements Serializable {

    private static final long serialVersionUID = 1L;

    static final Comparator<FlowStep> FLOWSTEP_ORDER = new Comparator<FlowStep>() {
        public int compare(FlowStep f1, FlowStep f2) {
            return f1.getStepNumber().compareTo(f2.getStepNumber());
        }
    };

    @Inject
    private FacesContextMessage facesContextMessage;

    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager em;

    @Inject
    private Logger logger;

    @Inject
    @Authenticated
    private AuthUser authUser;

    @Inject
    private AccessManager accessManager;

    private boolean editable;

    @Inject
    @Service
    private ProjectService projectService;

    @Inject
    @ProjectActorInit
    private Event<Project> projectActorSrc;

    private UseCase useCase;

    private Flow alternativeFlow;

    private FlowStepRule flowStepRule;

    private Project project;

    private boolean selected;

    private Long flowId;

    private FlowStep alternativeFlowStep;

    private boolean alternativeStepSelected;

    /**
     * Controller resource loader
     */
    @Inject
    public void init() {

        this.alternativeFlow = new Flow();
        this.flowStepRule = new FlowStepRule();
        this.selected = false;
        this.alternativeStepSelected = false;

        begin();
    }

    /**
     * Controller resource loader
     * 
     * @throws UCMException
     */
    public void load() throws UCMException {
        try {
            loadUseCase();

            editable = this.accessManager.hasPermission("projectMember", "Edit", this.project);

            // update project actor producer
            this.projectActorSrc.fire(this.useCase.getProject());
        } catch (Exception e) {
            throw new UCMException(e);
        }
    }

    /**
     * Load flow using flowId as request parameter
     * 
     * @throws UCMException
     */
    public void loadFlow() throws UCMException {
        try {
            logger.debug("loadFlow flowId = {}", this.flowId);
            this.alternativeFlow = em.find(Flow.class, this.flowId);

            // resort steps
            Collections.sort(this.alternativeFlow.getFlowSteps(), FLOWSTEP_ORDER);
        } catch (Exception e) {
            throw new UCMException(e);
        }
    }

    /**
     * Save action
     * 
     * @throws UCMException
     */
    public void save() throws UCMException {
        try {
            em.persist(this.alternativeFlow);
            logger.info("Saved Alternative Flow {}", this.alternativeFlow.getName());
            this.facesContextMessage.infoMessage("{0} saved successfully", this.alternativeFlow.getName());
        } catch (Exception e) {
            throw new UCMException(e);
        }
    }

    /**
     * Remove alternative flow
     * 
     * @throws UCMException
     */
    public void remove() throws UCMException {
        try {
            // remove any parent test classes
            List<TestCase> testCases = findTestCases(this.alternativeFlow);
            Iterator<TestCase> testCaseIter = testCases.iterator();
            while (testCaseIter.hasNext()) {
                em.remove(testCaseIter.next());
            }

            this.useCase.removeAlternativeFlow(this.alternativeFlow);
            em.remove(this.alternativeFlow);

            logger.info("Deleted Alternative Flow {}", this.alternativeFlow.getName());
            this.facesContextMessage.infoMessage("{0} deleted successfully", this.alternativeFlow.getName());
        } catch (Exception e) {
            throw new UCMException(e);
        }
    }

    /**
     * Close action
     * <p>
     * End work unit and navigate home
     * 
     * @return outcome
     */
    public String close() {
        String outcome = Literal.NAV_HOME.toString();
        end();
        return outcome;
    }

    /**
     * Add business rule action
     */
    public void addBusinessRule() {
        Long cnt = getFlowStepRuleCount();

        this.flowStepRule = new FlowStepRule(cnt.intValue() + 1);

        // product release is inherited
        this.flowStepRule.setProductRelease(this.useCase.getProductRelease());
    }

    /**
     * save business rule action
     * 
     * @throws UCMException
     */
    public void saveBusinessRule() throws UCMException {
        try {
            if (validateBusinessRule()) {
                this.flowStepRule.setModifiedBy(this.authUser.getUsername());
                if (this.flowStepRule.getId() == null) {
                    this.alternativeFlowStep.addFlowStepRule(this.flowStepRule);
                }

                em.persist(this.alternativeFlow);

                // force testcase update
                Timestamp now = new Timestamp(System.currentTimeMillis());
                this.useCase.setModifiedDate(now);

                em.persist(this.useCase);
                logger.info("Saved Business Rule {}", this.flowStepRule.getArtifact());
                this.facesContextMessage.infoMessage("Business Rule {0} saved successfully",
                        this.flowStepRule.getArtifact());
            }
        } catch (Exception e) {
            throw new UCMException(e);
        }
    }

    /**
     * save alternative flow action
     * 
     * @throws UCMException
     */
    public void saveAlternativeFlow() throws UCMException {
        try {
            if (validate()) {

                if (this.alternativeFlowStep.getId() == null) {
                    this.alternativeFlowStep.setModifiedBy(authUser.getUsername());
                    this.alternativeFlow.addFlowStep(this.alternativeFlowStep);
                }

                em.persist(this.alternativeFlow);
                logger.info("Saved {}", this.alternativeFlow.getName());
                this.facesContextMessage.infoMessage("{0} saved successfully", this.alternativeFlow.getName());

                // resort steps
                Collections.sort(this.alternativeFlow.getFlowSteps(), FLOWSTEP_ORDER);
            }
        } catch (Exception e) {
            throw new UCMException(e);
        }
    }

    /**
     * Add alternative flow step
     * 
     * @throws UCMException
     */
    public void addFlowStep() throws UCMException {
        try {
            Integer stepNumber = this.alternativeFlow.getFlowSteps().size() + 1;

            this.alternativeFlowStep = new FlowStep(stepNumber.shortValue());

            if (stepNumber.shortValue() % 2 == 0) {
                // test for previous actor
            } else {
                // system is actor for odd numbered steps
                Actor system = this.projectService.findSystemActor(this.project);
                this.alternativeFlowStep.setActor(system);
            }
        } catch (Exception e) {
            throw new UCMException(e);
        }
    }

    /**
     * Insert an alternative flow step
     * 
     * @throws UCMException
     */
    public void insertFlowStep() throws UCMException {
        try {
            logger.debug("inserting flow step before: {}", this.alternativeFlowStep.getStepNumber());
            this.alternativeFlowStep = new FlowStep(this.alternativeFlowStep.getStepNumber());

            // renumber steps
            short startStep = this.alternativeFlowStep.getStepNumber();

            // increment start step
            startStep++;

            // renumber from this starting step
            renumberFlowSteps(startStep);

            // resort steps
            Collections.sort(this.alternativeFlow.getFlowSteps(), FLOWSTEP_ORDER);
        } catch (Exception e) {
            throw new UCMException(e);
        }
    }

    /**
     * Action: remove alternative flow step
     * 
     * @throws UCMException
     */
    public void removeFlowStep() throws UCMException {
        try {
            this.alternativeFlow.removeFlowStep(this.alternativeFlowStep);
            em.remove(this.alternativeFlowStep);
            logger.info("Deleted Step {}", this.alternativeFlowStep.getStepNumber());
            this.facesContextMessage.infoMessage("{0} step deleted successfully",
                    this.alternativeFlowStep.getStepNumber());

            // renumber steps
            renumberAllFlowSteps();

            // persist renumbering changes
            em.persist(this.useCase);

            this.alternativeStepSelected = false;
        } catch (Exception e) {
            throw new UCMException(e);
        }
    }

    /**
     * @return the alternativeStepSelected
     */
    public boolean isAlternativeStepSelected() {
        return alternativeStepSelected;
    }

    /**
     * @param alternativeStepSelected
     *            the alternativeStepSelected to set
     */
    public void setAlternativeStepSelected(boolean alternativeStepSelected) {
        this.alternativeStepSelected = alternativeStepSelected;
    }

    /**
     * Row selection event
     * 
     * @param event
     */
    public void onRowSelect(SelectEvent event) {
        this.selected = true;
    }

    /**
     * Flow Step Row selection event
     * 
     * @param event
     */
    public void onFlowStepRowSelect(SelectEvent event) {
        this.alternativeStepSelected = true;
    }

    /**
     * @return the alternativeFlowStep
     */
    public FlowStep getAlternativeFlowStep() {
        return alternativeFlowStep;
    }

    /**
     * @param alternativeFlowStep
     *            the alternativeFlowStep to set
     */
    public void setAlternativeFlowStep(FlowStep alternativeFlowStep) {
        this.alternativeFlowStep = alternativeFlowStep;
    }

    /**
     * get UseCase
     * 
     * @return useCase
     */
    public UseCase getUseCase() {
        return useCase;
    }

    /**
     * set UseCase
     * 
     * @param useCase
     */
    public void setUseCase(UseCase useCase) {
        this.useCase = useCase;
    }

    /**
     * @return the alternativeFlow
     */
    public Flow getAlternativeFlow() {
        return alternativeFlow;
    }

    /**
     * @param alternativeFlow
     *            the alternativeFlow to set
     */
    public void setAlternativeFlow(Flow alternativeFlow) {
        this.alternativeFlow = alternativeFlow;
    }

    /**
     * @return the editable
     */
    public boolean isEditable() {
        return editable;
    }

    /**
     * @return the selected
     */
    public boolean isSelected() {
        return selected;
    }

    /**
     * @param selected
     *            the selected to set
     */
    public void setSelected(boolean selected) {
        this.selected = selected;
    }

    /**
     * @return the project
     */
    public Project getProject() {
        return project;
    }

    /**
     * @return the flowStepRule
     */
    public FlowStepRule getFlowStepRule() {
        return flowStepRule;
    }

    /**
     * @param flowStepRule the flowStepRule to set
     */
    public void setFlowStepRule(FlowStepRule flowStepRule) {
        this.flowStepRule = flowStepRule;
    }

    /**
     * @return the flowId
     */
    public Long getFlowId() {
        return flowId;
    }

    /**
     * @param flowId
     *            the flowId to set
     */
    public void setFlowId(Long flowId) {
        this.flowId = flowId;
    }

    /**
     * Validate alternative flow
     * <ul>
     * <li></li>
     * </ul>
     * 
     * @return flag true if validation is successful
     */
    private boolean validate() {
        boolean isvalid = true;

        return isvalid;
    }

    /**
     * load resources
     */
    private void loadUseCase() {
        this.useCase = em.find(UseCase.class, this.id);
        this.project = this.useCase.getProject();
    }

    /**
     * helper method renumbers alternative flow steps
     * 
     * @param starting
     *            step
     */
    private void renumberFlowSteps(final short startStep) {
        logger.debug("startStep = {}", startStep);
        short stepNumber = startStep;
        for (int i = stepNumber - 2; i < this.alternativeFlow.getFlowSteps().size(); i++) {
            FlowStep flowStep = this.alternativeFlow.getFlowSteps().get(i);
            flowStep.setStepNumber(stepNumber);
            logger.debug("renumbered {}", flowStep);
            stepNumber++;
        }
    }

    /**
     * Helper method to renumber all alternative flow steps
     */
    private void renumberAllFlowSteps() {
        for (int i = 0; i < this.alternativeFlow.getFlowSteps().size(); i++) {
            FlowStep flowStep = this.alternativeFlow.getFlowSteps().get(i);
            flowStep.setStepNumber((short) (i + 1));
            logger.debug("renumbered {}", flowStep);
        }
    }

    /**
     * Find testcases associated with this alternative flow
     * <p>
     * Return all testcases where flow name is contained in the testcase name.
     * 
     * @param alternativeFlow
     * @return List of TestCase
     */
    private List<TestCase> findTestCases(Flow alternativeFlow) {
        List<TestCase> testCases = new ArrayList<TestCase>();

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<TestCase> c = cb.createQuery(TestCase.class);
        Root<TestCase> obj = c.from(TestCase.class);
        c.select(obj);
        List<TestCase> list = em.createQuery(c).getResultList();

        for (TestCase testCase : list) {

            if (testCase.getName().indexOf(alternativeFlow.getName()) != -1) {
                testCases.add(testCase);
            }
        }

        return testCases;
    }

    /**
     * Get count of flowstep rules
     * 
     * @return count
     */
    private Long getFlowStepRuleCount() {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Long> c = cb.createQuery(Long.class);
        c.select(cb.count(c.from(FlowStepRule.class)));
        return em.createQuery(c).getSingleResult();
    }

    /**
     * Validate business rule
     * <ul>
     * <li>Check for duplicate business rule</li>
     * </ul>
     * 
     * @return flag true if validation is successful
     */
    private boolean validateBusinessRule() {
        boolean isvalid = true;

        if (this.flowStepRule.getId() == null) {
            if (checkForDuplicateBusinessRule(this.flowStepRule.getName())) {
                this.facesContextMessage.errorMessage("{0} already exists",
                        StringUtils.abbreviate(this.flowStepRule.getName(), 25));
                logger.error("{} already exists", this.flowStepRule.getName());
                isvalid = false;
                RequestContext requestContext = RequestContext.getCurrentInstance();
                requestContext.addCallbackParam("validationFailed", !isvalid);
            }
        }
        return isvalid;
    }

    /**
     * check for duplicate alternative flow
     */
    private boolean checkForDuplicateBusinessRule(String name) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<FlowStepRule> c = cb.createQuery(FlowStepRule.class);
        Root<FlowStepRule> obj = c.from(FlowStepRule.class);
        c.select(obj).where(cb.equal(obj.get("name"), name));
        List<FlowStepRule> list = em.createQuery(c).getResultList();
        return (list.size() > 0);
    }
}