cn.org.once.cstack.controller.ApplicationController.java Source code

Java tutorial

Introduction

Here is the source code for cn.org.once.cstack.controller.ApplicationController.java

Source

/*
 * LICENCE : CloudUnit is available under the GNU Affero General Public License : https://gnu.org/licenses/agpl.html
 * but CloudUnit is licensed too under a standard commercial license.
 * Please contact our sales team if you would like to discuss the specifics of our Enterprise license.
 * If you are not sure whether the AGPL is right for you,
 * you can always test our software under the AGPL and inspect the source code before you contact us
 * about purchasing a commercial license.
 *
 * LEGAL TERMS : "CloudUnit" is a registered trademark of Treeptik and can't be used to endorse
 * or promote products derived from this project without prior written permission from Treeptik.
 * Products or services derived from this software may not be called "CloudUnit"
 * nor may "Treeptik" or similar confusing terms appear in their names without prior written permission.
 * For any questions, contact us : contact@treeptik.fr
 */

package cn.org.once.cstack.controller;

import java.io.IOException;
import java.io.Serializable;
import java.util.List;
import java.util.Locale;

import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.org.once.cstack.aspects.CloudUnitSecurable;
import cn.org.once.cstack.dto.*;
import cn.org.once.cstack.enums.RemoteExecAction;
import cn.org.once.cstack.model.User;
import cn.org.once.cstack.utils.AuthentificationUtils;
import cn.org.once.cstack.utils.CheckUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import cn.org.once.cstack.config.events.ApplicationFailEvent;
import cn.org.once.cstack.config.events.ApplicationPendingEvent;
import cn.org.once.cstack.config.events.ApplicationStartEvent;
import cn.org.once.cstack.config.events.ApplicationStopEvent;
import cn.org.once.cstack.exception.CheckException;
import cn.org.once.cstack.exception.FatalDockerJSONException;
import cn.org.once.cstack.exception.ServiceException;
import cn.org.once.cstack.factory.EnvUnitFactory;
import cn.org.once.cstack.model.Application;
import cn.org.once.cstack.model.Status;
import cn.org.once.cstack.service.ApplicationService;
import cn.org.once.cstack.service.DockerService;

/**
 * Controller about Application lifecycle Application is the main concept for
 * CloudUnit : it composed by Server, Module and Metadata
 */
@Controller
@RequestMapping("/application")
public class ApplicationController implements Serializable {

    private static final long serialVersionUID = 1L;

    private final Logger logger = LoggerFactory.getLogger(ApplicationController.class);

    @Inject
    private ApplicationService applicationService;

    @Inject
    private AuthentificationUtils authentificationUtils;

    @Inject
    private DockerService dockerService;

    @Inject
    private ApplicationEventPublisher applicationEventPublisher;

    /**
     * To verify if an application exists or not.
     *
     * @param applicationName
     * @param serverName
     * @return
     * @throws ServiceException
     * @throws CheckException
     */
    @ResponseBody
    @RequestMapping(value = "/verify/{applicationName}/{serverName}", method = RequestMethod.GET)
    public JsonResponse isValid(@PathVariable String applicationName, @PathVariable String serverName)
            throws ServiceException, CheckException {

        User user = authentificationUtils.getAuthentificatedUser();
        if (logger.isInfoEnabled()) {
            logger.info("applicationName:" + applicationName);
            logger.info("serverName:" + serverName);
        }

        CheckUtils.validateInput(applicationName, "check.app.name");
        CheckUtils.validateInput(serverName, "check.server.name");

        applicationService.checkCreate(user, applicationName);

        return new HttpOk();
    }

    /**
     * CREATE AN APPLICATION
     *
     * @param input
     * @return
     * @throws ServiceException
     * @throws CheckException
     * @throws InterruptedException
     */
    @ResponseBody
    @Transactional
    @RequestMapping(method = RequestMethod.POST)
    public JsonResponse createApplication(@RequestBody JsonInput input)
            throws ServiceException, CheckException, InterruptedException {

        // validate the input
        input.validateCreateApp();

        // We must be sure there is no running action before starting new one
        User user = authentificationUtils.getAuthentificatedUser();
        authentificationUtils.canStartNewAction(user, null, Locale.ENGLISH);

        // CREATE AN APP
        applicationService.create(input.getApplicationName(), input.getServerName());

        return new HttpOk();
    }

    /**
     * START AN APPLICATION
     *
     * @param input
     *            {applicatioName:myApp-johndoe-admin}
     * @return
     * @throws ServiceException
     * @throws CheckException
     * @throws InterruptedException
     */
    @CloudUnitSecurable
    @ResponseBody
    @RequestMapping(value = "/restart", method = RequestMethod.POST)
    public JsonResponse restartApplication(@RequestBody JsonInput input)
            throws ServiceException, CheckException, InterruptedException {

        // validate the input
        input.validateStartApp();

        String applicationName = input.getApplicationName();
        User user = authentificationUtils.getAuthentificatedUser();
        Application application = applicationService.findByNameAndUser(user, applicationName);

        if (application != null && application.getStatus().equals(Status.PENDING)) {
            // If application is pending do nothing
            return new HttpErrorServer("application is pending. No action allowed.");
        }

        // We must be sure there is no running action before starting new one
        authentificationUtils.canStartNewAction(user, application, Locale.ENGLISH);

        if (application.getStatus().equals(Status.START)) {
            applicationService.stop(application);
            applicationService.start(application);
        } else if (application.getStatus().equals(Status.STOP)) {
            applicationService.start(application);
        }

        return new HttpOk();
    }

    /**
     * START AN APPLICATION
     *
     * @param input
     *            {applicatioName:myApp-johndoe-admin}
     * @return
     * @throws ServiceException
     * @throws CheckException
     * @throws InterruptedException
     */
    @CloudUnitSecurable
    @ResponseBody
    @RequestMapping(value = "/start", method = RequestMethod.POST)
    public JsonResponse startApplication(@RequestBody JsonInput input)
            throws ServiceException, CheckException, InterruptedException {

        // validate the input
        input.validateStartApp();

        String applicationName = input.getApplicationName();
        User user = authentificationUtils.getAuthentificatedUser();
        Application application = applicationService.findByNameAndUser(user, applicationName);

        if (application != null && application.getStatus().equals(Status.START)) {
            // If appliction is already start, we return the status
            return new HttpErrorServer("application already started");
        }

        // We must be sure there is no running action before starting new one
        authentificationUtils.canStartNewAction(user, application, Locale.ENGLISH);

        // set the application in pending mode
        applicationEventPublisher.publishEvent(new ApplicationPendingEvent(application));

        applicationService.start(application);

        // wait for modules and servers starting
        applicationEventPublisher.publishEvent(new ApplicationStartEvent(application));

        return new HttpOk();
    }

    /**
     * STOP a running application
     *
     * @param input
     * @return
     * @throws ServiceException
     * @throws CheckException
     */
    @CloudUnitSecurable
    @ResponseBody
    @RequestMapping(value = "/stop", method = RequestMethod.POST)
    public JsonResponse stopApplication(@RequestBody JsonInput input) throws ServiceException, CheckException {

        if (logger.isDebugEnabled()) {
            logger.debug(input.toString());
        }

        String name = input.getApplicationName();
        User user = authentificationUtils.getAuthentificatedUser();
        Application application = applicationService.findByNameAndUser(user, name);

        // We must be sure there is no running action before starting new one
        authentificationUtils.canStartNewAction(user, application, Locale.ENGLISH);

        // set the application in pending mode
        applicationEventPublisher.publishEvent(new ApplicationPendingEvent(application));

        // stop the application
        applicationService.stop(application);

        applicationEventPublisher.publishEvent(new ApplicationStopEvent(application));

        return new HttpOk();
    }

    /**
     * DELETE AN APPLICATION
     *
     * @param jsonInput
     * @return
     * @throws ServiceException
     * @throws CheckException
     */
    @CloudUnitSecurable
    @ResponseBody
    @RequestMapping(value = "/{applicationName}", method = RequestMethod.DELETE)
    public JsonResponse deleteApplication(JsonInput jsonInput) throws ServiceException, CheckException {

        jsonInput.validateRemoveApp();

        String applicationName = jsonInput.getApplicationName();
        User user = this.authentificationUtils.getAuthentificatedUser();
        Application application = applicationService.findByNameAndUser(user, applicationName);

        // We must be sure there is no running action before starting new one
        authentificationUtils.canStartDeleteApplicationAction(user, application, Locale.ENGLISH);

        try {
            // Application busy
            // set the application in pending mode
            applicationEventPublisher.publishEvent(new ApplicationPendingEvent(application));

            logger.info("delete application :" + applicationName);
            applicationService.remove(application, user);

        } catch (ServiceException e) {
            // set the application in pending mode
            applicationEventPublisher.publishEvent(new ApplicationFailEvent(application));
        }

        logger.info("Application " + applicationName + " is deleted.");

        return new HttpOk();
    }

    /**
     * Return detail information about application
     *
     * @return
     * @throws ServiceException
     */
    @CloudUnitSecurable
    @ResponseBody
    @RequestMapping(value = "/{applicationName}", method = RequestMethod.GET)
    public Application detail(JsonInput jsonInput) throws ServiceException, CheckException {

        jsonInput.validateDetail();

        User user = authentificationUtils.getAuthentificatedUser();
        Application application = applicationService.findByNameAndUser(user, jsonInput.getApplicationName());
        return application;
    }

    /**
     * Return the list of applications for an User
     *
     * @return
     * @throws ServiceException
     */
    @ResponseBody
    @RequestMapping(method = RequestMethod.GET)
    public List<Application> findAllByUser() throws ServiceException {
        User user = this.authentificationUtils.getAuthentificatedUser();
        List<Application> applications = applicationService.findAllByUser(user);

        logger.debug("Number of applications " + applications.size());
        return applications;
    }

    /**
     * Deploy a web application
     *
     * @return
     * @throws IOException
     * @throws ServiceException
     * @throws CheckException
     */
    @ResponseBody
    @RequestMapping(value = "/{applicationName}/deploy", method = RequestMethod.POST, consumes = {
            "multipart/form-data" })
    public JsonResponse deploy(@RequestPart("file") MultipartFile fileUpload, @PathVariable String applicationName,
            HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServiceException, CheckException {

        logger.info("applicationName = " + applicationName + "file = " + fileUpload.getOriginalFilename());

        User user = authentificationUtils.getAuthentificatedUser();
        Application application = applicationService.findByNameAndUser(user, applicationName);

        // We must be sure there is no running action before starting new one
        authentificationUtils.canStartNewAction(user, application, Locale.ENGLISH);

        application = applicationService.deploy(fileUpload, application);

        String needRestart = dockerService.getEnv(application.getServer().getContainerID(),
                "CU_SERVER_RESTART_POST_DEPLOYMENT");
        if ("true".equalsIgnoreCase(needRestart)) {
            // set the application in pending mode
            applicationEventPublisher.publishEvent(new ApplicationPendingEvent(application));
            applicationService.stop(application);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            applicationService.start(application);
            // wait for modules and servers starting
            applicationEventPublisher.publishEvent(new ApplicationStartEvent(application));
        }

        logger.info("--DEPLOY APPLICATION WAR ENDED--");
        return new HttpOk();
    }

    /**
     * Return the list of containers for an application (module, server or
     * tools)
     *
     * @param applicationName
     * @return
     * @throws ServiceException
     * @throws CheckException
     */
    @ResponseBody
    @RequestMapping(value = "/{applicationName}/containers", method = RequestMethod.GET)
    public List<ContainerUnit> listContainer(@PathVariable String applicationName)
            throws ServiceException, CheckException {
        logger.debug("applicationName:" + applicationName);
        return applicationService.listContainers(applicationName);
    }

    /**
     * Display env variables for a container
     *
     * @param applicationName
     * @return
     * @throws ServiceException
     * @throws CheckException
     */
    @CloudUnitSecurable
    @ResponseBody
    @RequestMapping(value = "/{applicationName}/container/{containerName}/env", method = RequestMethod.GET)
    public List<EnvUnit> displayEnv(@PathVariable String applicationName, @PathVariable String containerName)
            throws ServiceException, CheckException {
        List<EnvUnit> envUnits = null;
        try {
            User user = this.authentificationUtils.getAuthentificatedUser();
            String content = dockerService.execCommand(containerName,
                    RemoteExecAction.GATHER_CU_ENV.getCommand() + " " + user.getLogin());
            logger.debug(content);
            envUnits = EnvUnitFactory.fromOutput(content);
        } catch (FatalDockerJSONException e) {
            throw new ServiceException(applicationName + ", " + containerName, e);
        }
        return envUnits;
    }
}