Java tutorial
/* * 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; } } }