private void doSave(WebPageContext page) throws IOException, ServletException { if (!page.isFormPost()) { throw new IllegalArgumentException("Must post!"); } new DebugFilter.PageWriter(page) { { File file = getFile(page); Preconditions.checkNotNull(file); String code = page.paramOrDefault(String.class, "code", ""); try { CLASS_FOUND: if (file.isDirectory()) { Object result = evaluateJava(page.getServletContext(), code); if (result instanceof Collection) { for (Object item : (Collection<?>) result) { if (item instanceof Class) { file = new File( file, ((Class<?>) item).getName().replace('.', File.separatorChar) + ".java"); IoUtils.createParentDirectories(file); break CLASS_FOUND; } } } throw new IllegalArgumentException("Syntax error!"); } IoUtils.createFile(file); FileOutputStream fileOutput = new FileOutputStream(file); try { fileOutput.write(code.replaceAll("(?:\r\n|[\r\n])", "\n").getBytes("UTF-8")); writeStart("p", "class", "alert alert-success"); writeHtml("Saved Successfully! ("); writeObject(new Date()); writeHtml(")"); writeEnd(); } finally { fileOutput.close(); } } catch (Exception ex) { writeStart("pre", "class", "alert alert-error"); writeObject(ex); writeEnd(); } } }; }
@Override protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { WebPageContext page = new WebPageContext(this, request, response); String action = page.param(String.class, "action"); if ("run".equals(action)) { if (page.param(String.class, "isSave") != null) { doSave(page); } else { page.paramOrDefault(Type.class, "type", Type.JAVA).run(page); } } else { doEdit(page); } }
private static File getFile(WebPageContext page) throws IOException { String file = page.param(String.class, "file"); if (file == null) { String servletPath = page.param(String.class, "servletPath"); if (servletPath != null) { file = page.getServletContext().getRealPath(servletPath); } } if (file == null) { return null; } File fileInstance = new File(file); if (!fileInstance.exists()) { IoUtils.createParentDirectories(fileInstance); } return fileInstance; }
private void doEdit(WebPageContext page) throws IOException, ServletException { final Type type = page.paramOrDefault(Type.class, "type", Type.JAVA); final File file = getFile(page); final StringBuilder codeBuilder = new StringBuilder(); if (file != null) { if (file.exists()) { if (file.isDirectory()) { // Can't edit a directory. } else { codeBuilder.append(IoUtils.toString(file, StandardCharsets.UTF_8)); } } else { String filePath = file.getPath(); if (filePath.endsWith(".java")) { filePath = filePath.substring(0, filePath.length() - 5); for (File sourceDirectory : CodeUtils.getSourceDirectories()) { String sourceDirectoryPath = sourceDirectory.getPath(); if (filePath.startsWith(sourceDirectoryPath)) { String classPath = filePath.substring(sourceDirectoryPath.length()); if (classPath.startsWith(File.separator)) { classPath = classPath.substring(1); } int lastSepAt = classPath.lastIndexOf(File.separatorChar); if (lastSepAt < 0) { codeBuilder.append("public class "); codeBuilder.append(classPath); } else { codeBuilder.append("package "); codeBuilder.append( classPath.substring(0, lastSepAt).replace(File.separatorChar, '.')); codeBuilder.append(";\n\npublic class "); codeBuilder.append(classPath.substring(lastSepAt + 1)); } codeBuilder.append(" {\n}"); break; } } } } } else { Set<String> imports = findImports(); imports.add("com.psddev.dari.db.*"); imports.add("com.psddev.dari.util.*"); imports.add("java.util.*"); String includes = Settings.get(String.class, INCLUDE_IMPORTS_SETTING); if (!ObjectUtils.isBlank(includes)) { Collections.addAll(imports, includes.trim().split("\\s*,?\\s+")); } String excludes = Settings.get(String.class, EXCLUDE_IMPORTS_SETTING); if (!ObjectUtils.isBlank(excludes)) { for (String exclude : excludes.trim().split("\\s*,?\\s+")) { imports.remove(exclude); } } for (String i : imports) { codeBuilder.append("import "); codeBuilder.append(i); codeBuilder.append(";\n"); } codeBuilder.append('\n'); codeBuilder.append("public class Code {\n"); codeBuilder.append(" public static Object main() throws Throwable {\n"); String query = page.param(String.class, "query"); String objectClass = page.paramOrDefault(String.class, "objectClass", "Object"); if (query == null) { codeBuilder.append(" return null;\n"); } else { codeBuilder .append(" Query<") .append(objectClass) .append("> query = ") .append(query) .append(";\n"); codeBuilder .append(" PaginatedResult<") .append(objectClass) .append("> result = query.select(0L, 10);\n"); codeBuilder.append(" return result;\n"); } codeBuilder.append(" }\n"); codeBuilder.append("}\n"); } new DebugFilter.PageWriter(page) { { List<Object> inputs = CodeDebugServlet.Static.getInputs(getServletContext()); Object input = inputs == null || inputs.isEmpty() ? null : inputs.get(0); String name; if (file == null) { name = null; } else { name = file.toString(); int slashAt = name.lastIndexOf('/'); if (slashAt > -1) { name = name.substring(slashAt + 1); } } startPage("Code Editor", name); writeStart("div", "class", "row-fluid"); if (input != null) { writeStart( "div", "class", "codeInput", "style", "bottom: 65px; position: fixed; top: 55px; width: 18%; z-index: 1000;"); writeStart("h2").writeHtml("Input").writeEnd(); writeStart( "div", "style", "bottom: 0; overflow: auto; position: absolute; top: 38px; width: 100%;"); writeObject(input); writeEnd(); writeEnd(); writeStart("style", "type", "text/css"); write(".codeInput pre { white-space: pre; word-break: normal; word-wrap: normal; }"); writeEnd(); writeStart("script", "type", "text/javascript"); write("$('.codeInput').hover(function() {"); write("$(this).css('width', '50%');"); write("}, function() {"); write("$(this).css('width', '18%');"); write("});"); writeEnd(); } writeStart( "div", "class", input != null ? "span9" : "span12", "style", input != null ? "margin-left: 20%" : null); writeStart( "form", "action", page.url(null), "class", "code", "method", "post", "style", "margin-bottom: 70px;", "target", "result"); writeElement("input", "name", "action", "type", "hidden", "value", "run"); writeElement("input", "name", "type", "type", "hidden", "value", type); writeElement("input", "name", "file", "type", "hidden", "value", file); writeElement( "input", "name", "jspPreviewUrl", "type", "hidden", "value", page.param(String.class, "jspPreviewUrl")); writeStart("textarea", "name", "code"); writeHtml(codeBuilder); writeEnd(); writeStart( "div", "class", "form-actions", "style", "bottom: 0; left: 0; margin: 0; padding: 10px 20px; position:fixed; right: 0; z-index: 1000;"); writeElement("input", "class", "btn btn-primary", "type", "submit", "value", "Run"); writeStart( "label", "class", "checkbox", "style", "display: inline-block; margin-left: 10px; white-space: nowrap;"); writeElement("input", "name", "isLiveResult", "type", "checkbox"); writeHtml("Live Result"); writeEnd(); writeStart( "label", "style", "display: inline-block; margin-left: 10px; white-space: nowrap;", "title", "Shortcut: ?_vim=true"); boolean vimMode = page.param(boolean.class, "_vim"); writeStart( "label", "class", "checkbox", "style", "display: inline-block; margin-left: 10px; white-space: nowrap;"); writeElement( "input", "name", "_vim", "type", "checkbox", "value", "true", vimMode ? "checked" : "_unchecked", "true"); writeHtml("Vim Mode"); writeEnd(); writeEnd(); writeElement( "input", "class", "btn btn-success pull-right", "name", "isSave", "type", "submit", "value", "Save"); writeElement( "input", "class", "btn pull-right", "style", "margin-right: 10px;", "name", "clearCode", "type", "submit", "value", "Clear"); writeEnd(); writeEnd(); writeStart( "div", "class", "resultContainer", "style", "background: rgba(255, 255, 255, 0.8);" + "border-color: rgba(0, 0, 0, 0.2);" + "border-style: solid;" + "border-width: 0 0 0 1px;" + "max-height: 45%;" + "top: 55px;" + "overflow: auto;" + "padding: 0px 20px 5px 10px;" + "position: fixed;" + "z-index: 3;" + "right: 0px;" + "width: 35%;"); writeStart("h2").writeHtml("Result").writeEnd(); writeStart("div", "class", "frame", "name", "result"); writeEnd(); writeEnd(); writeStart("script", "type", "text/javascript"); write("$('body').frame();"); write("var $codeForm = $('form.code');"); write("var lineMarkers = [ ];"); write("var columnMarkers = [ ];"); write("var codeMirror = CodeMirror.fromTextArea($('textarea')[0], {"); write("'indentUnit': 4,"); write("'lineNumbers': true,"); write("'lineWrapping': true,"); write("'matchBrackets': true,"); write("'mode': 'text/x-java'"); write("});"); // Save code to local storage when the user stops typing for 1 second write("if (window.localStorage !== undefined) {"); write("var baseCode = $('textarea[name=code]').text();"); write("var windowStorageCodeKey = 'bsp.codeDebugServlet.code';"); write( "if (window.localStorage.getItem(windowStorageCodeKey) !== null && window.localStorage.getItem(windowStorageCodeKey).trim()) {"); write("codeMirror.getDoc().setValue(window.localStorage.getItem(windowStorageCodeKey))"); write("}"); write("var typingTimer;"); write("codeMirror.on('keydown', function() {"); write("clearTimeout(typingTimer);"); write("});"); write("codeMirror.on('keyup', function() {"); write("clearTimeout(typingTimer);"); write("typingTimer = setTimeout(function(){"); write( "window.localStorage.setItem(windowStorageCodeKey, codeMirror.getDoc().getValue());},"); write("1000);"); write("});"); write("}"); // Reset code to original page load value and clear window storage write("$('.form-actions input[name=clearCode]').on('click', function(e) {"); write("e.preventDefault();"); write("if (baseCode !== undefined && baseCode.trim()) {"); write("codeMirror.getDoc().setValue(baseCode);"); write("if (window.localStorage !== undefined) {"); write("window.localStorage.removeItem(windowStorageCodeKey);"); write("}"); write("}"); write("});"); write("codeMirror.on('change', $.throttle(1000, function() {"); write("if ($codeForm.find(':checkbox[name=isLiveResult]').is(':checked')) {"); write("$codeForm.submit();"); write("}"); write("}));"); write("$('input[name=_vim]').change(function() {"); write("codeMirror.setOption('vimMode', $(this).is(':checked'));"); write("});"); write("$('input[name=_vim]').change();"); int line = page.param(int.class, "line"); if (line > 0) { write("var line = "); write(String.valueOf(line)); write(" - 1;"); write("codeMirror.setCursor(line);"); write("codeMirror.addLineClass(line, 'selected', 'selected');"); write("$(window).scrollTop(codeMirror.cursorCoords().top - $(window).height() / 2);"); } write("var $resultContainer = $('.resultContainer');"); write("$resultContainer.find('.frame').bind('load', function() {"); write( "$.each(lineMarkers, function() { codeMirror.clearMarker(this); codeMirror.setLineClass(this, null, null); });"); write("$.each(columnMarkers, function() { this.clear(); });"); write("var $frame = $(this).find('.syntaxErrors li').each(function() {"); write("var $error = $(this);"); write("var line = parseInt($error.attr('data-line')) - 1;"); write("var column = parseInt($error.attr('data-column')) - 1;"); write("if (line > -1 && column > -1) {"); write("lineMarkers.push(codeMirror.setMarker(line, '!'));"); write("codeMirror.setLineClass(line, 'errorLine', 'errorLine');"); write( "columnMarkers.push(codeMirror.markText({ 'line': line, 'ch': column }, { 'line': line, 'ch': column + 1 }, 'errorColumn'));"); write("}"); write("});"); write("});"); writeEnd(); writeEnd(); writeEnd(); endPage(); } @Override public void startBody(String... titles) throws IOException { writeStart("body"); writeStart("div", "class", "navbar navbar-fixed-top"); writeStart("div", "class", "navbar-inner"); writeStart("div", "class", "container-fluid"); writeStart("span", "class", "brand"); writeStart("a", "href", DebugFilter.Static.getServletPath(page.getRequest(), "")); writeHtml("Dari"); writeEnd(); writeHtml("Code Editor \u2192 "); writeEnd(); writeStart( "form", "action", page.url(null), "method", "get", "style", "float: left; height: 40px; line-height: 40px; margin: 0; padding-left: 10px;"); writeStart( "select", "class", "span6", "name", "file", "onchange", "$(this).closest('form').submit();"); writeStart("option", "value", ""); writeHtml("PLAYGROUND"); writeEnd(); for (File sourceDirectory : CodeUtils.getSourceDirectories()) { writeStart("optgroup", "label", sourceDirectory); writeStart( "option", "selected", sourceDirectory.equals(file) ? "selected" : null, "value", sourceDirectory); writeHtml("NEW CLASS IN ").writeHtml(sourceDirectory); writeEnd(); writeFileOption(file, sourceDirectory, sourceDirectory); writeEnd(); } writeEnd(); writeEnd(); includeStylesheet("/_resource/chosen/chosen.css"); includeScript("/_resource/chosen/chosen.jquery.min.js"); writeStart("script", "type", "text/javascript"); write("(function() {"); write("$('select[name=file]').chosen({ 'search_contains': true });"); write("})();"); writeEnd(); writeEnd(); writeEnd(); writeEnd(); writeStart("div", "class", "container-fluid", "style", "padding-top: 54px;"); } private void writeFileOption(File file, File sourceDirectory, File source) throws IOException { if (source.isDirectory()) { for (File child : source.listFiles()) { writeFileOption(file, sourceDirectory, child); } } else { writeStart( "option", "selected", source.equals(file) ? "selected" : null, "value", source); writeHtml(source.toString().substring(sourceDirectory.toString().length())); writeEnd(); } } }; }