beans.WidgetServerImpl.java Source code

Java tutorial

Introduction

Here is the source code for beans.WidgetServerImpl.java

Source

/*
 * Copyright (c) 2013 GigaSpaces Technologies Ltd. All rights reserved
 *
 * Licensed 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 beans;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import beans.config.Conf;
import controllers.WidgetAdmin;

import models.ServerNodeEvent;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import play.cache.Cache;
import play.i18n.Messages;

import models.ServerNode;
import models.Widget;
import models.Widget.Status;
import models.WidgetInstance;
import server.*;
import utils.CollectionUtils;
import utils.Utils;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

/**
 * This class provides ability to deploy/undeploy new widget by apiKey.
 * Before that the user must create an account by WidgetAdmin and register a new widget.
 * 
 * @author Igor Goldenberg
 * @see ServerPoolImpl
 * @see WidgetAdmin
 */
public class WidgetServerImpl implements WidgetServer {
    private static Logger logger = LoggerFactory.getLogger(WidgetServerImpl.class);
    @Inject
    private ServerPool serverPool;

    @Inject
    private MailSender mailSender;

    @Inject
    private Conf conf;

    @Inject
    private DeployManager deployManager;

    private static Map<Recipe.Type, Pattern> installationFinishedRegexMap = null;

    static {
        installationFinishedRegexMap = new HashMap<Recipe.Type, Pattern>();
        for (Recipe.Type type : Recipe.Type.values()) {
            String pattern = type + " .* (installed|successfully) (installed|successfully)";
            installationFinishedRegexMap.put(type, Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
        }
    }

    private List<String> filterOutputLines = new LinkedList<String>();
    private List<String> filterOutputStrings = new LinkedList<String>();

    @PostConstruct
    public void init() {
        Utils.addAllTrimmed(filterOutputLines, StringUtils.split(conf.cloudify.removeOutputLines, "|"));
        Utils.addAllTrimmed(filterOutputStrings, StringUtils.split(conf.cloudify.removeOutputString, "|"));
    }

    @Override
    public void uninstall(ServerNode server) {
        logger.info("uninstalling [{}], [{}]", server, server.getWidgetInstance());
        if (server.isRemote()) {
            deployManager.uninstall(server);
        } else {
            undeploy(server);
        }

    }

    public WidgetInstance deploy(Widget widget, ServerNode server, String remoteAddress) {
        // keep the user for 30 seconds by IP, to avoid immediate widget start after stop
        Cache.set(remoteAddress, System.currentTimeMillis() + conf.settings.stopTimeout,
                (int) (conf.settings.stopTimeout / 1000));
        widget.countLaunch();
        return deployManager.fork(server, widget);
    }

    public void undeploy(ServerNode serverNode) {
        serverPool.destroy(serverNode);
    }

    private static boolean isFinished(Recipe.Type recipeType, String line) {
        logger.debug("checking to see if [{}] has finished using [{}]", recipeType, line);
        Pattern pattern = installationFinishedRegexMap.get(recipeType);
        return pattern != null && !StringUtils.isEmpty(line) && pattern.matcher(line).matches();
    }

    @Override
    public Status getWidgetStatus(ServerNode server) {
        Status result = new Status();
        List<String> output = new LinkedList<String>();
        result.setOutput(output);

        if (server == null) {
            result.setState(Status.State.STOPPED);
            output.add(Messages.get("test.drive.successfully.complete"));
            return result;
        }

        String cachedOutput = Utils.getCachedOutput(server);// need to sort out the cache before we decide if the installation finished.

        result.setRawOutput(Utils.split(cachedOutput, "\n"));

        result.setRemote(server.isRemote()).setHasPemFile(!StringUtils.isEmpty(server.getPrivateKey())); // let UI know this is a remote bootstrap.

        boolean doneFromEvent = false;

        if (!CollectionUtils.isEmpty(server.events)) {
            for (ServerNodeEvent event : server.events) {
                switch (event.getEventType()) {

                case DONE:
                    logger.info("detected that widget instance installation done by event");
                    doneFromEvent = true;
                    break;
                case ERROR: {
                    result.setState(Status.State.STOPPED);
                    result.setMessage(event.getMsg());
                    return result;
                }
                case INFO: {
                    output.add(event.getMsg());
                }
                    break;
                default: {
                    logger.error("unknown event type while formatting : [{}]", event.getEventType());
                }
                }
            }
        }

        output.addAll(Utils.formatOutput(cachedOutput, server.getPrivateIP() + "]", filterOutputLines,
                filterOutputStrings));

        WidgetInstance widgetInstance = WidgetInstance.findByServerNode(server);
        logger.debug("checking if installation finished for {} on the following output {}", widgetInstance, output);
        if (widgetInstance != null) {
            if (doneFromEvent
                    || isFinished(widgetInstance.getRecipeType(), (String) CollectionUtils.last(output))) {

                // need to figure out the remote service IP for the link
                if (server.isRemote() && StringUtils.isEmpty(widgetInstance.getServicePublicIp())
                        && !StringUtils.isEmpty(widgetInstance.getWidget().getConsoleUrlService())) {
                    // find out the service's public IP.
                    String servicePublicIp = deployManager.getServicePublicIp(widgetInstance);
                    if (!StringUtils.isEmpty(servicePublicIp)) {
                        logger.info("found ip at : [{}]", servicePublicIp);
                        widgetInstance.setServicePublicIp(servicePublicIp);
                        widgetInstance.save();
                    }
                }

                logger.debug("detected finished installation");
                output.add("Installation completed successfully");
                result.setInstanceIsAvailable(Boolean.TRUE);
                result.setConsoleLink(widgetInstance.getLink());
            }
        }

        result.setState(Status.State.RUNNING);
        if (!StringUtils.isEmpty(server.getPublicIP())) {
            result.setPublicIp(server.getPublicIP());
            result.setCloudifyUiIsAvailable(Boolean.TRUE);
        }

        // server is remote we don't count time
        if (!server.isRemote() && server.getExpirationTime() != null) {
            long elapsedTime = server.getExpirationTime() - System.currentTimeMillis();
            result.setTimeleft((int) TimeUnit.MILLISECONDS.toMinutes(elapsedTime));
        }
        return result;
    }

    public void setServerPool(ServerPool serverPool) {
        this.serverPool = serverPool;
    }

    public void setDeployManager(DeployManager deployManager) {
        this.deployManager = deployManager;
    }

    public void setConf(Conf conf) {
        this.conf = conf;
    }
}