All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.bogieclj.molecule.mods.ishell.JLineInteractiveShell Maven / Gradle / Ivy

There is a newer version: 0.1.2
Show newest version
/*
 * Copyright 2019 Vijayakumar Mohan
 *
 * 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 com.github.bogieclj.molecule.mods.ishell;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.base.Splitter;
import lombok.extern.slf4j.Slf4j;
import org.fusesource.jansi.AnsiConsole;
import org.jline.reader.*;
import org.jline.reader.impl.completer.ArgumentCompleter;
import com.github.bogieclj.molecule.commons.Constants;
import com.github.bogieclj.molecule.ishell.annotations.DomainStack;
import com.github.bogieclj.molecule.system.*;
import com.github.bogieclj.molecule.system.services.DomainService;
import com.github.bogieclj.molecule.system.services.FnBus;
import org.mvel2.MVEL;

import javax.inject.Inject;
import java.io.PrintWriter;
import java.net.URI;
import java.util.*;
import java.util.regex.Pattern;

import static com.github.bogieclj.molecule.util.JSONUtils.OBJECT_MAPPER;

@Slf4j
class JLineInteractiveShell implements Shell{


    static final String ROOT_DOMAIN = "";

    private String[] commandsList;

    private DomainService domainService;
    static String defaultPrompt = "> ";
    private Completer domainOpCompleter;
    //private String currentDomain = "";


    private Stack domainStack;
    //private EvictingQueue commandHistory = EvictingQueue.create(50);

    private Pattern pattern = Pattern.compile(" (?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
    //private Pattern pattern = Pattern.compile(" (?=(?:[^\"]*\\[(.\\s\\d)*\\])*[^\"]*$)");
    //private Pattern pattern = Pattern.compile(" (?=(?:[^\"]*\\[[^\"]*\\])*[^\"]*$)");
    //private Pattern pattern = Pattern.compile(" ");
    private Splitter splitter = Splitter.on(pattern).trimResults().omitEmptyStrings();
    private FnBus fnBus;

    @Inject
    JLineInteractiveShell(DomainService domainService, FnBus fnBus,@DomainStack Stack domainStack){
        commandsList = new String[]{"help","domains","ops","cd","pwd","exec","exit"};
        this.domainService = domainService;
        this.fnBus = fnBus;
        this.domainStack = domainStack;
        this.domainStack.push(ROOT_DOMAIN);
        this.domainOpCompleter = new DomainOperationsCompleter(domainService,domainStack);
    }

    @Override
    public void start(String[] args) {
        AnsiConsole.systemInstall(); // needed to support ansi on Windows cmd
        //printWelcomeMessage();
        LineReaderBuilder readerBuilder = LineReaderBuilder.builder();
        List completors = new LinkedList();

        //completors.add(new StringsCompleter(commandsList));
        completors.add(domainOpCompleter);
        readerBuilder.completer(new ArgumentCompleter(completors));

        LineReader reader = readerBuilder.build();

        String line;
        PrintWriter out = new PrintWriter(System.out);

        boolean active = true;

        while (active && (line = readLine(reader, defaultPrompt)) != null) {

            List input = splitter.splitToList(line);
            if(input != null && !input.isEmpty()) {
                String command = input.get(0);
                List commandArguments = new ArrayList();
                if(input.size() > 1){
                    commandArguments = input.subList(1,input.size());
                }
                active = executeCommandOnFnBus(command,commandArguments);
            }
            /*if ("help".equals(line)) {
                printHelp();
            } else if ("domains".equals(line)) {
                AttributedStringBuilder a = new AttributedStringBuilder()
                        .append("You have selected ")
                        .append("domains", AttributedStyle.BOLD.foreground(AttributedStyle.RED))
                        .append("!");

                System.out.println(a.toAnsi());
            } else if ("action2".equals(line)) {
                AttributedStringBuilder a = new AttributedStringBuilder()
                        .append("You have selected ")
                        .append("ops", AttributedStyle.BOLD.foreground(AttributedStyle.RED))
                        .append("!");

                System.out.println(a.toAnsi());
            } else if ("exit".equals(line)) {
                System.out.println("Exiting application");
                return;
            } else {
                System.out
                        .println("Invalid command, For assistance press TAB or type \"help\" then hit ENTER.");
            }*/
        }


    }

    private boolean executeCommandOnFnBus(String command,List args) {
        boolean shouldContinue = true;
        try {
            shouldContinue = executeCommandOnRootDomain(command, args);
        }catch(InvalidOperationException e){
            try {
                executeCommandOnCurrentDomain(command, args);
            }catch(InvalidOperationException ex){
                System.out
                        .println("Invalid command, For assistance press TAB or type \"help\" then hit ENTER.");
            }
        }
        return shouldContinue;
    }

    private void executeCommandOnCurrentDomain(String command, List args) throws InvalidOperationException {
        String fullyQualifiedCurrentDomain = getFullyQualifiedDomain(domainStack);
        List rootOperationList = domainService.getOperationsAt(fullyQualifiedCurrentDomain);
        if(rootOperationList.contains(command)){
            String commandPath = fullyQualifiedCurrentDomain.isEmpty() == false ? fullyQualifiedCurrentDomain + "." +command : command;
            Operation operation = domainService.getOperation(commandPath);
            //log.info("Operation {}",operation);
            Param inParam = new InOutParam();
            inParam = inParam.plus(Constants.FUNCTION_TO_INVOKE, operation.getFunctionURI());
            //log.info("In Params {}",inParam);
            Param outParam = fnBus.apply(inParam);
            if(outParam.hasOutParams()){
                prettyPrintOutput(outParam);
            }
        }else{
            throw new InvalidOperationException(String.format("Operation %s is invalid for domain %s",command,fullyQualifiedCurrentDomain));
        }
    }

    private boolean executeCommandOnRootDomain(String command,List args) throws InvalidOperationException {
        boolean retVal = true;
        List rootOperationList = domainService.getOperationsAt("");
        if(rootOperationList.contains(command)){
            Operation operation = domainService.getOperation(command);
            Param inParam = new InOutParam();
            inParam = inParam.plus(Constants.FUNCTION_TO_INVOKE, operation.getFunctionURI());
            inParam = inParam.plus(Constants.IN_PARAMS,args);
            Param outParam = fnBus.apply(inParam);
            if(outParam.containsKey(IShellConstants.EXIT_SYSTEM)){
                retVal = (Boolean)outParam.get(IShellConstants.EXIT_SYSTEM);
            }

            if(outParam.hasOutParams()){
                prettyPrintOutput(outParam);
            }
            //log.info("Received Out {}",outParam);
        }else{
            throw new InvalidOperationException(String.format("Operation %s is invalid for domain %s",command,"/"));
        }
        return retVal;
    }

    private void prettyPrintOutput(Param outParam) {
        Map outParamMap = outParam.outParams();
        try {
            String outputString = OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(outParamMap);
            System.out.println(outputString);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

    /*private void printHelp() {
        int helpFormattingWidth = 15;
        System.out.println(getFormattedHelpMessage(helpFormattingWidth,"help","Show help"));

        System.out.println(getFormattedHelpMessage(helpFormattingWidth,"domains","List all valid accessible domains within the current active domain"));
        System.out.println(getFormattedHelpMessage(helpFormattingWidth,"ops","List all valid accessible operations within the current active domain"));
        System.out.println(getFormattedHelpMessage(helpFormattingWidth,"cd","Change to the specified domain"));
        System.out.println(getFormattedHelpMessage(helpFormattingWidth,"pwd","Prints the present working domain"));
        System.out.println(getFormattedHelpMessage(helpFormattingWidth,"exec","Executes the specified operation withing the current active domain"));
        System.out.println(getFormattedHelpMessage(helpFormattingWidth,"exit","Exits the system"));
        System.out.println(getFormattedHelpMessage(helpFormattingWidth,"shutdown","Shutdown the system"));
        System.out.println(getFormattedHelpMessage(helpFormattingWidth,"quit","Exits the system"));

    }*/


    @Override
    public void stop() {
        AnsiConsole.systemUninstall();

    }
    private String getPrompt_working(Stack domainStack, String currentDomain,String postFix) {
        StringBuffer pathPrompt = new StringBuffer();
        for(int i=0;i domainStack,String postFix) {
        StringBuffer pathPrompt = new StringBuffer();
        for(int i=0;i input = splitter.splitToList(commandLine);
        if(input != null && !input.isEmpty()) {
            String commandName = input.get(0);
            List args = input.subList(1, input.size());

            if (commandName.equalsIgnoreCase("domains")) {
                listDomains(args);
            } else if (commandName.equalsIgnoreCase("ops")) {
                listOps(args);
            } else if (commandName.equalsIgnoreCase("cd")) {
                changeDomain(args);
            } else if (commandName.equalsIgnoreCase("pwd")) {
                printCurrentDomain(args);
            } else if (commandName.equalsIgnoreCase("exec")) {
                executeOperation(args);
            } else if (hasToExit(commandName)) {
                exit(args);
                retVal = false; //on exit get out of the command prompt looping
            } else if (commandName.equalsIgnoreCase("help")) {
                printHelp();
            } else {
                System.out
                        .println("Invalid command, For assistance press TAB or type \"help\" then hit ENTER.");
            }
        }

        return retVal;
    }*/

    private boolean hasToExit(String commandName) {
        boolean retVal = false;
        if(commandName.equalsIgnoreCase("exit")
                || commandName.equalsIgnoreCase("quit")
                || commandName.equalsIgnoreCase("shutdown")){
            retVal = true;
        }
        return retVal;
    }

    private void executeOperation(List args) {
        if(args == null || args.isEmpty()){
            return;
        }
        String operationName = args.get(0);
        String operationParams = null;
        if(args.size() > 1){
            operationParams = args.get(1);
        }

        log.info("Operation {}",operationName);
        log.info("Params {}",operationParams);

        String fullyQualifiedDomainName = getFullyQualifiedDomain(domainStack);

        if(!domainService.isValidOperationAt(fullyQualifiedDomainName,operationName)){
            printf("No such operation '%s' found under '%s'",operationName,getPrompt(domainStack,""));
        }else{
            if(operationParams != null) {
                //log.info("PREQUOTE IN {}", operationParams);
                //String opParams = quoteParams(operationParams);
                String opParams = unQuoteParams(operationParams);
                //log.info("MVEL IN {}", opParams);

                Object expressionObj = MVEL.eval(opParams);
                printf("Params %s, %s", expressionObj.getClass(), expressionObj);
                Operation operation = domainService.getOperationAt(fullyQualifiedDomainName,operationName);
                URI functionURI = operation.getFunctionURI();
                printf("About to invoke function %s",functionURI);
            }
        }
        //textTerminal.printf("Operation Name %s, Args %s",operationName,operationParams);


    }

    private void printf(String formattingText, Object... args) {
        System.out.println(String.format(formattingText,args));
    }

    private String unQuoteParams(String operationParams) {
        if(operationParams.startsWith("\"") && operationParams.endsWith("\"")){
            operationParams = operationParams.substring(1,operationParams.length()-1);
        }
        return operationParams;
    }

    private String quoteParams(String operationParams) {
        StringBuffer paramBuffer = new StringBuffer();

        paramBuffer.append("\"");

        paramBuffer.append(operationParams);

        paramBuffer.append("\"");

        return paramBuffer.toString();
    }

    private void exit( List args) {
        printf("Bye! Bye!...");
    }

    private void printCurrentDomain(List args) {
        printf("%s",getPrompt(domainStack,""));
    }

    private void changeDomain(List args) {
        String domainToChange = args.get(0);

        List domainNamesAt = domainService.getDomainNamesAt(getFullyQualifiedDomain(domainStack));

        if(isNavigationToPrevious(domainToChange)){
            if(domainStack.size() > 0){
                domainStack.pop();
            }// if not we are already in the root so nothing to do
        }else if(isNavigationToRoot(domainToChange)){
            domainStack.clear();
            domainStack.push(ROOT_DOMAIN);
            //currentDomain = "";
        }else if(domainNamesAt.contains(domainToChange)){
            //domainStack.push(currentDomain);
            //currentDomain = domainToChange;
            domainStack.push(domainToChange);
        }else{
            printf("no such domain %s",domainToChange);
        }
    }

    private boolean isNavigationToRoot(String domainToChange) {
        return domainToChange.equalsIgnoreCase("/");
    }

    private boolean isNavigationToPrevious(String domainToChange) {
        return domainToChange.equalsIgnoreCase("..");
    }


    private String getFullyQualifiedDomain_working(Stack domainStack, String currentDomain) {
        StringBuffer fullyQualifiedDomain = new StringBuffer();
        for(int i=0;i domainStack) {
        StringBuffer fullyQualifiedDomain = new StringBuffer();
        for(int i=0;i args) {
        String fullyQualifiedDomain = getFullyQualifiedDomain(domainStack);
        //log.info("FCN {}",fullyQualifiedDomain);
        List operationsAt = domainService.getOperationsAt(fullyQualifiedDomain);
        printf("%s",operationsAt);
    }

    private void listDomains(List args) {
        String fullyQualifiedDomain = getFullyQualifiedDomain(domainStack);
        //log.info("FCN {}",fullyQualifiedDomain);
        List domainNamesAt = domainService.getDomainNamesAt(fullyQualifiedDomain);
        printf("%s",domainNamesAt);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy