/** * MailArchiver is an application that provides services for storing and managing e-mail messages through a Web Services SOAP interface. * Copyright (C) 2012 Marcio Andre Scholl Levien and Fernando Alberto Reuter Wendt and Jose Ronaldo Nogueira Fonseca Junior * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ /******************************************************************************\ * * This product was developed by * * SERVIÇO FEDERAL DE PROCESSAMENTO DE DADOS (SERPRO), * * a government company established under Brazilian law (5.615/70), * at Department of Development of Porto Alegre. * \******************************************************************************/ package serpro.mailarchiver.util.bshcommands; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import javax.annotation.PostConstruct; import bsh.CallStack; import bsh.EvalError; import bsh.Interpreter; import bsh.InterpreterError; import bsh.ParseException; import bsh.TargetError; import com.eventrouter.SubscriptionRegistry; import com.eventrouter.annotation.AnnotationProcessor; import com.eventrouter.annotation.Subscribe; import org.springframework.beans.factory.annotation.Configurable; import com.vaadin.event.LayoutEvents.LayoutClickEvent; import com.vaadin.event.LayoutEvents.LayoutClickListener; import com.vaadin.terminal.Sizeable; import com.vaadin.ui.ComponentContainer; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.VerticalSplitPanel; import com.vaadin.ui.Window; import com.vaadin.ui.Window.CloseEvent; import com.vaadin.ui.Window.CloseListener; import com.vaadin.ui.themes.Reindeer; import org.vaadin.codeeditor.DefaultCodeEditor; import org.vaadin.codeeditor.frontend.ace.AceFrontEnd; import org.vaadin.peter.contextmenu.ContextMenu; import org.vaadin.peter.contextmenu.ContextMenu.ContextMenuItem; import serpro.mailarchiver.view.BaseApplication; import serpro.mailarchiver.view.admin.AdminConsoleApp; import serpro.mailarchiver.util.Logger; @Configurable public class scriptEditor { private static final Logger log = Logger.getLocalLogger(); @PostConstruct private void postConstruct() { SubscriptionRegistry subscriptionRegistry = BaseApplication.getInstance().getDispatchContext().getSubscriptionRegistry(); AnnotationProcessor processor = new AnnotationProcessor(subscriptionRegistry); processor.process(this); } private final Interpreter globalInterpreter; private final CallStack callstack; private Interpreter interpreter; private PrintStream interpreterOut; private ByteArrayOutputStream interpreterOutByteArray; private StringBuffer interpreterOutBuffer; private PrintStream interpreterErr; private ByteArrayOutputStream interpreterErrByteArray; private StringBuffer interpreterErrBuffer; private Window mainWindow; private Window window; private VerticalSplitPanel split; private EditorComponent editor; private OutputComponent output; private scriptEditor(Interpreter interpreter, CallStack callstack) { this.globalInterpreter = interpreter; this.callstack = callstack; } public static void invoke(Interpreter interpreter, CallStack callstack) { new scriptEditor(interpreter, callstack).init(); } @Subscribe({"/mailarchiver/refresh"}) private void refresh() { if(interpreterOutBuffer.length() > 0) { String content = interpreterOutBuffer.toString(); interpreterOutBuffer.setLength(0); for(String line : content.split("\\r?\\n")) { output.printLn(line); } } if(interpreterErrBuffer.length() > 0) { String content = interpreterErrBuffer.toString(); interpreterErrBuffer.setLength(0); for(String line : content.split("\\r?\\n")) { output.printErrLn(line); } } } private void init() { mainWindow = AdminConsoleApp.getInstance().getMainWindow(); interpreter = new Interpreter(); interpreter.setNameSpace(globalInterpreter.getNameSpace()); interpreter.setStrictJava(false); interpreterOutByteArray = new ByteArrayOutputStream(); interpreterOutBuffer = new StringBuffer(); try { interpreterOut = new PrintStream(interpreterOutByteArray, false, "UTF-8") { @Override public void flush() { super.flush(); if(interpreterOutByteArray.size() > 0) { try { String content = interpreterOutByteArray.toString("UTF-8"); interpreterOutByteArray.reset(); if(!content.isEmpty()) { interpreterOutBuffer.append(content); } } catch (UnsupportedEncodingException ex) { log.error(ex); } } } }; } catch (UnsupportedEncodingException ex) { log.error(ex); } interpreter.setOut(interpreterOut); interpreterErrByteArray = new ByteArrayOutputStream(); interpreterErrBuffer = new StringBuffer(); try { interpreterErr = new PrintStream(interpreterErrByteArray, false, "UTF-8") { @Override public void flush() { super.flush(); if(interpreterErrByteArray.size() > 0) { try { String content = interpreterErrByteArray.toString("UTF-8"); interpreterErrByteArray.reset(); if(!content.isEmpty()) { interpreterErrBuffer.append(content); } } catch (UnsupportedEncodingException ex) { log.error(ex); } } } }; } catch (UnsupportedEncodingException ex) { log.error(ex); } interpreter.setErr(interpreterErr); window = new Window("MailArchiver ScriptEditor"); window.setWidth(400, Sizeable.UNITS_PIXELS); window.setHeight(300, Sizeable.UNITS_PIXELS); split = new VerticalSplitPanel(); split.setSizeFull(); editor = new EditorComponent(); editor.setStyleName("script-editor"); editor.setMargin(false); editor.setSpacing(false); editor.setSizeFull(); split.addComponent(editor); output = new OutputComponent(); output.setSizeFull(); split.addComponent(output); window.setContent(split); mainWindow.addWindow(window); window.addListener(new CloseListener() { @Override public void windowClose(CloseEvent e) { mainWindow.removeWindow(window); } }); } private void eval(String script) { StringWriter sw = new StringWriter(); try { Object ret = interpreter.eval(script); sw.append("Script result: ").append(String.valueOf(ret)).append("\n"); print(sw); } catch(ParseException e) { sw.append("Parser error: ").append(e.toString()).append("\n"); stackTrace(sw, e); printErr(sw); } catch(InterpreterError e) { sw.append("Internal error: ").append(e.toString()).append("\n"); stackTrace(sw, e); printErr(sw); } catch(TargetError e) { sw.append("Uncaught exception: ").append(e.getTarget().toString()).append("\n"); if(e.inNativeCode()) { stackTrace(sw, e.getTarget()); } printErr(sw); } catch(EvalError e) { sw.append("Eval error: ").append(e.toString()).append("\n"); stackTrace(sw, e); printErr(sw); } catch(Exception e) { sw.append("Unknown error: ").append(e.toString()).append("\n"); stackTrace(sw, e); printErr(sw); } } private void print(StringWriter sw) { for(String line : sw.toString().split("\\r?\\n")) { output.printLn(line); } } private void printErr(StringWriter sw) { for(String line : sw.toString().split("\\r?\\n")) { output.printErrLn(line); } } private void stackTrace(StringWriter sw, Throwable e) { PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); pw.flush(); sw.append("\n"); } private class EditorComponent extends VerticalLayout { private final DefaultCodeEditor codeEditor; private final ContextMenu editorMenu; private final ContextMenuItem editorEvalItem; private final ContextMenuItem editorClearItem; private final ContextMenuItem editorOpenItem; private final ContextMenuItem editorSaveItem; public EditorComponent() { codeEditor = new DefaultCodeEditor(); AceFrontEnd frontEnd = new AceFrontEnd(); codeEditor.setFrontEnd(frontEnd); codeEditor.setSizeFull(); addComponent(codeEditor); editorMenu = new ContextMenu(); editorEvalItem = editorMenu.addItem("Eval"); editorClearItem = editorMenu.addItem("Clear"); editorOpenItem = editorMenu.addItem("Open"); editorSaveItem = editorMenu.addItem("Save"); addListener(new LayoutClickListener() { @Override public void layoutClick(LayoutClickEvent event) { if(LayoutClickEvent.BUTTON_RIGHT == event.getButton()) { window.focus(); editorMenu.show(event.getClientX(), event.getClientY()); } } }); editorMenu.addListener(new ContextMenu.ClickListener() { @Override public void contextItemClick(ContextMenu.ClickEvent event) { ContextMenuItem clickedItem = event.getClickedItem(); if(clickedItem == editorEvalItem) { final String script = (String)codeEditor.getValue(); new Thread() { @Override public void run() { eval(script); } } .start(); } else if(clickedItem == editorClearItem) { clear(); } else if(clickedItem == editorOpenItem) { open(); } else if(clickedItem == editorSaveItem) { save(); } } }); editorMenu.setVisible(false); mainWindow.addComponent(editorMenu); } private void clear() { codeEditor.setValue(""); } private void open() { System.out.println("TODO: editor open"); } private void save() { System.out.println("TODO: editor save"); } } private class OutputComponent extends Panel { private final VerticalLayout layout; private final ContextMenu outputMenu; private final ContextMenuItem outputClearItem; private final ContextMenuItem outputSaveItem; private final ContextMenuItem outputWrapItem; private final ContextMenuItem outputUnwrapItem; public OutputComponent() { setScrollable(true); setStyleName(Reindeer.PANEL_LIGHT); ComponentContainer container = this.getContent(); layout = (VerticalLayout) container; layout.setWidth(Sizeable.SIZE_UNDEFINED, Sizeable.UNITS_PIXELS); outputMenu = new ContextMenu(); outputClearItem = outputMenu.addItem("Clear"); outputSaveItem = outputMenu.addItem("Save"); outputWrapItem = outputMenu.addItem("Wrap"); outputUnwrapItem = outputMenu.addItem("Unwrap"); outputUnwrapItem.setVisible(false); layout.addListener(new LayoutClickListener() { @Override public void layoutClick(LayoutClickEvent event) { if(LayoutClickEvent.BUTTON_RIGHT == event.getButton()) { window.focus(); outputMenu.show(event.getClientX(), event.getClientY()); } } }); outputMenu.addListener(new ContextMenu.ClickListener() { @Override public void contextItemClick(ContextMenu.ClickEvent event) { ContextMenuItem clickedItem = event.getClickedItem(); if(clickedItem == outputClearItem) { clear(); } else if(clickedItem == outputSaveItem) { save(); } else if(clickedItem == outputWrapItem) { wrap(); } else if(clickedItem == outputUnwrapItem) { unwrap(); } } }); outputMenu.setVisible(false); mainWindow.addComponent(outputMenu); clear(); } private void clear() { removeAllComponents(); } private void save() { System.out.println("TODO: output save"); } private void wrap() { layout.setWidth("100%"); outputWrapItem.setVisible(false); outputUnwrapItem.setVisible(true); requestRepaint(); } private void unwrap() { layout.setWidth(Sizeable.SIZE_UNDEFINED, Sizeable.UNITS_PIXELS); outputWrapItem.setVisible(true); outputUnwrapItem.setVisible(false); requestRepaint(); } public void printLn(String s) { Label line = new Label(s, Label.CONTENT_TEXT); line.setStyleName("script-editor-output"); addComponent(line); } public void printErrLn(String s) { Label line = new Label(s, Label.CONTENT_TEXT); line.setStyleName("script-editor-output-error"); addComponent(line); } } }