bear.main.FXConf.java Source code

Java tutorial

Introduction

Here is the source code for bear.main.FXConf.java

Source

/*
 * Copyright (C) 2013 Andrey Chaschev.
 *
 * 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 bear.main;

import bear.annotations.Project;
import bear.core.*;
import bear.main.event.LogEventToUI;
import bear.main.event.NoticeEventToUI;
import bear.main.event.RMIEventToUI;
import bear.main.phaser.ComputingGrid;
import bear.main.phaser.SettableFuture;
import bear.plugins.CommandInterpreter;
import bear.plugins.Plugin;
import bear.plugins.PomPlugin;
import bear.plugins.groovy.Replacement;
import bear.plugins.groovy.Replacements;
import bear.plugins.sh.GenericUnixRemoteEnvironmentPlugin;
import bear.task.*;
import chaschev.json.JacksonMapper;
import chaschev.lang.Lists2;
import chaschev.lang.OpenBean;
import chaschev.lang.Predicates2;
import chaschev.lang.reflect.MethodDesc;
import chaschev.util.Exceptions;
import com.fasterxml.jackson.core.JsonGenerator;
import com.google.common.base.Charsets;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import com.google.common.io.CharStreams;
import com.google.common.io.Files;
import javafx.scene.input.Clipboard;
import javafx.scene.input.DataFormat;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

import static com.google.common.collect.Lists.transform;
import static java.util.Collections.singletonList;

/**
 * @author Andrey Chaschev chaschev@gmail.com
 */
public class FXConf extends BearMain {
    private static final Logger logger = LoggerFactory.getLogger(FXConf.class);
    private static final org.apache.logging.log4j.Logger ui = LogManager.getLogger("ui");

    protected BearCommandInterpreter commandInterpreter;

    public FXConf(String... args) {
        super(GlobalContextFactory.INSTANCE.getGlobal(), getCompilerManager(), args);

        fxApp = true;
    }

    public String getFileText(String className) {
        return compileManager.findClass(className).get().getText();
    }

    public void saveFileText(String className, String text) {
        compileManager.findClass(className).get().saveText(text);
    }

    public String getSelectedSettings() {
        return FilenameUtils.getBaseName($(projectFile).getName());
    }

    public Response run(String uiContextS) throws Exception {
        logger.info("running a script with params: {}", uiContextS);

        BearScriptRunner.UIContext uiContext = commandInterpreter.mapper.fromJSON(uiContextS,
                BearScriptRunner.UIContext.class);

        BearProject<?> project = newProject(uiContext);

        project.invoke(uiContext.projectMethodName);

        //        run(newProject(new File(uiContext.projectPath)).setInteractiveMode(), null, false, true);

        return sendHostsEtc(lastRunner);
    }

    private BearProject newProject(BearScriptRunner.UIContext uiContext) {
        return newProject(new File(uiContext.projectPath));
    }

    public BearProject newProject(File file) {
        return ((BearProject<?>) OpenBean.newInstance((Class) findEntry(file).get().aClass)).injectMain(this)
                .setInteractiveMode();
    }

    private Response sendHostsEtc(GlobalTaskRunner runner) {
        List<BearScriptRunner.RunResponse.Host> hosts = getHosts(runner.getSessions());

        ui.info(new RMIEventToUI("terminals", "onScriptStart", hosts));

        return new BearScriptRunner.RunResponse(runner, hosts);
    }

    public static List<BearScriptRunner.RunResponse.Host> getHosts(List<SessionContext> $s) {
        return transform($s, new Function<SessionContext, BearScriptRunner.RunResponse.Host>() {
            public BearScriptRunner.RunResponse.Host apply(SessionContext $) {
                return new BearScriptRunner.RunResponse.Host($.sys.getName(), $.sys.getAddress());
            }
        });
    }

    public Response interpret(String command, String uiContextS) throws Exception {
        return commandInterpreter.interpret(command, uiContextS);
    }

    public String pasteFromClipboard() {
        return Clipboard.getSystemClipboard().getString();
    }

    public void copyToClipboard(String text) {
        HashMap<DataFormat, Object> map = new HashMap<DataFormat, Object>();
        map.put(DataFormat.PLAIN_TEXT, text);

        Clipboard.getSystemClipboard().setContent(map);
    }

    public String completeCode(String script, int caretPos) {
        return commandInterpreter.completeCode(script, caretPos);
    }

    public void evaluateInFX(Runnable runnable) {
        bearFX.bearFXApp.runLater(runnable);
    }

    public <V> Future<V> evaluateInFX(final Callable<V> callable) {
        final SettableFuture<V> future = new SettableFuture<V>();

        bearFX.bearFXApp.runLater(new Runnable() {
            @Override
            public void run() {
                try {
                    future.set(callable.call());
                } catch (Exception e) {
                    future.setException(e);
                }
            }
        });

        return future;
    }

    public FileResponse getPropertyAsFile(String property) {
        String file = bearFX.bearProperties.getProperty(property);

        Preconditions.checkNotNull(file, "no such property: %s", property);

        if (file.indexOf('/') == -1 && file.indexOf('\'') == -1) {
            return new FileResponse(new File($(scriptsDir), file));
        }

        return new FileResponse(new File(file));
    }

    public void createPom() {
        try {
            File file = new File(".bear/pom.xml");

            logger.info("writing POM to {}...", file.getAbsolutePath());

            CharStreams.write(bear.getGlobal().plugin(PomPlugin.class).generate(),
                    Files.newWriterSupplier(file, Charsets.UTF_8));

            ui.info(new NoticeEventToUI("Create POM", "POM has been created in " + file.getAbsolutePath()));
        } catch (IOException e) {
            throw Exceptions.runtime(e);
        }
    }

    @Override
    public FXConf configure() throws IOException {
        super.configure();

        commandInterpreter = $.wire(new BearCommandInterpreter());
        commandInterpreter.switchToPlugin(GenericUnixRemoteEnvironmentPlugin.class);

        return this;
    }

    public static class FileResponse {
        public String dir;
        public String filename;
        public String path;
        public String absPath;

        public FileResponse(File file) {
            dir = file.getParent();
            filename = file.getName();
            path = file.getPath();
            absPath = file.getAbsolutePath();
        }
    }

    private String[] getNames(List classes) {
        return (String[]) Lists2.projectMethod(classes, "getName").toArray(new String[classes.size()]);
    }

    public void cancelAll() {
        GlobalTaskRunner runContext = global.currentGlobalRunner;

        if (runContext == null) {
            ui.warn(new LogEventToUI("shell", "not running"));
            return;
        }

        List<SessionContext> entries = runContext.getSessions();

        for (SessionContext $ : entries) {
            if ($.isRunning()) {
                try {
                    $.terminate();
                } catch (Exception e) {
                    logger.warn("could not terminate", e);
                }
            }
        }

        global.interruptAll();
    }

    public void cancelThread(String name) {
        GlobalTaskRunner runContext = global.currentGlobalRunner;

        if (runContext == null) {
            ui.warn(new LogEventToUI("shell", "not running"));
            return;
        }

        SessionContext $ = Iterables.find(runContext.getSessions(), Predicates2.methodEquals("getName", name));

        $.terminate();
    }

    public class BearCommandInterpreter {
        GlobalContext global;

        Plugin currentShellPlugin;

        public CommandInterpreter currentInterpreter() {
            return currentShellPlugin.getShell();
        }

        public final JacksonMapper mapper = new JacksonMapper();

        /**
         * Scope: GLOBAL
         *
         * : -> system command
         * :help
         * :use shell <plugin>
         *
         * @param command
         */
        public Response interpret(final String command, String uiContextS) throws Exception {
            String firstLine = StringUtils.substringBefore(command, "\n");

            ui.info("interpreting command: '{}', params: {}", firstLine.trim(), uiContextS);

            final BearScriptRunner.UIContext uiContext = mapper.fromJSON(uiContextS,
                    BearScriptRunner.UIContext.class);

            final BearProject<?> project = newProject(uiContext);

            boolean runInSingleShell = !"shell".equals(uiContext.shell) && !"status".equals(uiContext.shell);

            global.putConst(bear.internalInteractiveRun, true);

            if (runInSingleShell) {
                //better to call saveMap
                global.putConst(bear.activeHosts, singletonList(uiContext.shell));
                global.putConst(bear.activeRoles, Collections.<String>emptyList());
            }

            GlobalTaskRunner runner = project.run(singletonList(
                    new NamedCallable<Object, TaskResult<?>>(firstLine, new TaskCallable<Object, TaskResult<?>>() {
                        @Override
                        public TaskResult<?> call(SessionContext $, Task<Object, TaskResult<?>> task)
                                throws Exception {
                            Plugin<TaskDef> shellPlugin = project.findShell(uiContext.plugin).get();

                            Task<Object, TaskResult<?>> interpretedTask = shellPlugin.getShell().interpret(command,
                                    $, task, task.getDefinition());
                            return $.runner.runSession(interpretedTask);
                        }
                    })));

            if (runInSingleShell) {
                //not safe when quickly fails, better to restore the map
                runner.whenAllFinished(new ComputingGrid.WhenAllFinished() {
                    @Override
                    public void run(int failedParties, int okParties) {
                        global.removeConst(bear.activeHosts);
                        global.removeConst(bear.activeRoles);
                    }
                });
            }

            return sendHostsEtc(runner);
        }

        private void switchToPlugin(Class<? extends Plugin> aClass) {
            this.currentShellPlugin = global.plugin(aClass);
        }

        public String completeCode(String script, int caretPos) {
            try {
                Replacements replacements = currentInterpreter().completeCode(script, caretPos);

                StringWriter writer = new StringWriter(1024);
                JsonGenerator g = mapper.getMapper().getFactory().createGenerator(writer);

                g.writeStartArray();

                for (Replacement replacement : replacements.getReplacements()) {
                    g.writeStartObject();
                    g.writeStringField("caption", replacement.name);
                    g.writeStringField("meta", replacement.type);
                    g.writeStringField("snippet", replacement.snippet);
                    g.writeEndObject();
                }

                g.writeEndArray();

                g.close();

                return writer.toString();
            } catch (IOException e) {
                throw Exceptions.runtime(e);
            }
        }
    }

    public ProjectInfosResponse getProjectInfos() {
        List<CompiledEntry<? extends BearProject>> list = compileManager.findProjects();

        List<ProjectInfo> infos = new ArrayList<ProjectInfo>();

        for (CompiledEntry<? extends BearProject> compiledEntry : list) {
            infos.add(new ProjectInfo(compiledEntry.aClass, compiledEntry.file.getAbsolutePath(), global));
        }

        Class<? extends BearProject> prjClass;

        if (global.isSet(bear.activeProject)) {
            prjClass = global.var(bear.activeProject).getClass();

            selectProject(prjClass.getAnnotation(Project.class).shortName());
        } else {
            File currentProjectFile = new File(bearFX.bearProperties.getProperty("bear-fx.project"));

            Optional<CompiledEntry<?>> aClass = compileManager.findClass(currentProjectFile);

            prjClass = (Class<? extends BearProject>) aClass.get().aClass;
        }

        return new ProjectInfosResponse(infos).setSelectedProject(prjClass.getSimpleName());
    }

    //todo refactor to properties management?
    void selectProject(String shortName) {
        for (CompiledEntry<? extends BearProject> entry : compileManager.findProjects()) {
            if (entry.aClass.getAnnotation(Project.class).shortName().equals(shortName)) {
                try {
                    bearFX.bearProperties.setProperty("bear-fx.project", entry.file.getAbsolutePath());
                    bearFX.bearProperties.store(new FileWriter(BearFX.BEAR_FX_PROPERTIES), "");
                    return;
                } catch (IOException e) {
                    throw Exceptions.runtime(e);
                }
            }
        }

        throw new IllegalArgumentException("didn't find project: " + shortName);
    }

    public class ProjectInfo {
        public String shortName;
        public String name;
        public List<String> methods;
        public String path;
        public String defaultMethod;
        public List<String> shells;

        public ProjectInfo() {
        }

        public ProjectInfo(Class<? extends BearProject> project, String path, GlobalContext global) {
            Project projectAnnotation = project.getAnnotation(Project.class);

            shortName = projectAnnotation.shortName();
            name = project.getSimpleName();
            defaultMethod = projectAnnotation.method();
            methods = new ArrayList<String>();
            shells = new ArrayList<String>();
            this.path = path;

            Set<String> temp = new LinkedHashSet<String>();

            //            BearProject<?> prj = newProject(new File(path));

            //            prj.configureWithAnnotations(true);

            for (MethodDesc desc : OpenBean.methods(project)) {
                if (desc.getMethod().isAnnotationPresent(bear.annotations.Method.class)) {
                    temp.add(desc.getName());
                }
            }
            for (MethodDesc<? extends GlobalTaskRunner> methodDesc : OpenBean.methodsReturning(project,
                    GlobalTaskRunner.class)) {
                if (methodDesc.getMethod().getParameterTypes().length == 0) {
                    temp.add(methodDesc.getName());
                }
            }

            for (Method method : project.getDeclaredMethods()) {
                if (Modifier.isPublic(method.getModifiers()) && method.getReturnType().equals(void.class)
                        && method.getParameterTypes().length == 0) {
                    temp.add(method.getName());
                }
            }

            for (String s : temp) {
                if (s.contains("$1") || s.contains("$2") || s.contains("__$"))
                    continue;

                methods.add(s);
            }

            //            for (Plugin<TaskDef> plugin : prj.getAllShellPlugins(global, project)) {
            //                shells.add(plugin.cmdAnnotation());
            //            }

            //            System.out.println(this);
        }

        public ProjectInfo setPath(String path) {
            this.path = path;
            return this;
        }
    }

    public static class ProjectInfosResponse {
        public String selectedProject;
        public String selectedMethod;

        public List<ProjectInfo> infos;

        public ProjectInfosResponse() {
        }

        public ProjectInfosResponse(List<ProjectInfo> infos) {
            this.infos = infos;
        }

        public ProjectInfosResponse setSelectedProject(String selectedProject) {
            this.selectedProject = selectedProject;

            for (ProjectInfo info : infos) {
                if (info.name.equals(selectedProject)) {
                    selectedMethod = info.defaultMethod;
                    break;
                }
            }

            return this;
        }
    }
}