<commit_before>/*******************************************************************************
 * Copyright (c) 2011 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 <NAME>
 * @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 )){
                        widgetInstance.setServicePublicIp( servicePublicIp );
                        widgetInstance.save(  );
                    }
                }

                logger.debug("detected finished installation");
                result.setInstanceIsAvailable(Boolean.TRUE);
                result.setConsoleLink(widgetInstance.getLink());
            }
        }<commit_msg>adding "installation completed successfully" if already installed.<commit_after>/*******************************************************************************
 * Copyright (c) 2011 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 <NAME>
 * @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 )){
                        widgetInstance.setServicePublicIp( servicePublicIp );
                        widgetInstance.save(  );
                    }
                }

                logger.debug("detected finished installation");
                output.add( "Installation completed successfully" );
                result.setInstanceIsAvailable(Boolean.TRUE);
                result.setConsoleLink(widgetInstance.getLink());
            }
        }
{'fraction_non_alphanumeric': 0.11454018227009113, 'fraction_numerical': 0.002623584645125656, 'mean_word_length': 2.5502450980392157, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3806315', 'n_tokens_mistral': 3658, 'n_tokens_neox': 3497, 'n_words': 986}