# HG changeset patch # User Jaroslav Tulach # Date 1356016651 -3600 # Node ID dc375a56fd15a2b51be3dad75ccb94bf087e8c69 # Parent e078953818d26afc7d5385cd998666019c42f467 Mojo for execution in a browser diff -r e078953818d2 -r dc375a56fd15 javaquery/demo-calculator/nbactions.xml --- a/javaquery/demo-calculator/nbactions.xml Thu Dec 20 11:03:34 2012 +0100 +++ b/javaquery/demo-calculator/nbactions.xml Thu Dec 20 16:17:31 2012 +0100 @@ -23,7 +23,7 @@ run process-classes - org.codehaus.mojo:exec-maven-plugin:1.2.1:exec + org.apidesign.bck2brwsr:mojo:0.3-SNAPSHOT:brwsr diff -r e078953818d2 -r dc375a56fd15 javaquery/demo-calculator/pom.xml --- a/javaquery/demo-calculator/pom.xml Thu Dec 20 11:03:34 2012 +0100 +++ b/javaquery/demo-calculator/pom.xml Thu Dec 20 16:17:31 2012 +0100 @@ -16,34 +16,19 @@ - - org.apidesign.bck2brwsr - mojo - 0.3-SNAPSHOT - - - - j2js - - - - - org.codehaus.mojo - exec-maven-plugin - 1.2.1 + org.apidesign.bck2brwsr + mojo + 0.3-SNAPSHOT - exec + brwsr - xdg-open - - ${project.build.directory}/classes/org/apidesign/bck2brwsr/mavenhtml/Calculator.xhtml - + org/apidesign/bck2brwsr/mavenhtml/Calculator.xhtml diff -r e078953818d2 -r dc375a56fd15 javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/mavenhtml/Calculator.xhtml --- a/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/mavenhtml/Calculator.xhtml Thu Dec 20 11:03:34 2012 +0100 +++ b/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/mavenhtml/Calculator.xhtml Thu Dec 20 16:17:31 2012 +0100 @@ -77,7 +77,11 @@ - + +
diff -r e078953818d2 -r dc375a56fd15 launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java
--- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java	Thu Dec 20 11:03:34 2012 +0100
+++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java	Thu Dec 20 16:17:31 2012 +0100
@@ -33,8 +33,6 @@
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 import javax.script.Invocable;
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineManager;
@@ -50,13 +48,17 @@
 import org.glassfish.grizzly.http.server.ServerConfiguration;
 
 /**
- * Lightweight server to launch Bck2Brwsr applications in real browser.
+ * Lightweight server to launch Bck2Brwsr applications and tests.
+ * Supports execution in native browser as well as Java's internal 
+ * execution engine.
  */
 public class Bck2BrwsrLauncher {
     private Set loaders = new LinkedHashSet<>();
     private List methods = new ArrayList<>();
     private long timeOut;
     private String sen;
+    private String showURL;
+    private final Res resources = new Res();
     
     
     public MethodInvocation addMethod(Class clazz, String method) {
@@ -73,20 +75,24 @@
     public void setScriptEngineName(String sen) {
         this.sen = sen;
     }
+
+    public void setStartPage(String startpage) {
+        if (!startpage.startsWith("/")) {
+            startpage = "/" + startpage;
+        }
+        this.showURL = startpage;
+    }
+
+    public void addClassLoader(ClassLoader url) {
+        this.loaders.add(url);
+    }
     
     public static void main( String[] args ) throws Exception {
         Bck2BrwsrLauncher l = new Bck2BrwsrLauncher();
-        
-        final MethodInvocation[] cases = { 
-            l.addMethod(Console.class, "welcome"),
-            l.addMethod(Console.class, "multiply"),
-        };
-        
+        l.setStartPage("org/apidesign/bck2brwsr/launcher/console.xhtml");
+        l.addClassLoader(Bck2BrwsrLauncher.class.getClassLoader());
         l.execute();
-        
-        for (MethodInvocation c : cases) {
-            System.err.println(c.className + "." + c.methodName + " = " + c.result);
-        }
+        System.in.read();
     }
 
 
@@ -94,6 +100,10 @@
         try {
             if (sen != null) {
                 executeRhino();
+            } else if (showURL != null) {
+                HttpServer server = initServer();
+                server.getServerConfiguration().addHttpHandler(new Page(resources, null), "/");
+                launchServerAndBrwsr(server, showURL);
             } else {
                 executeInBrowser();
             }
@@ -142,21 +152,29 @@
         }
     }
     
-    private void executeInBrowser() throws InterruptedException, URISyntaxException, IOException {
-        final CountDownLatch wait = new CountDownLatch(1);
-        final MethodInvocation[] cases = this.methods.toArray(new MethodInvocation[0]);
-        
+    private HttpServer initServer() {
         HttpServer server = HttpServer.createSimpleServer(".", new PortRange(8080, 65535));
-        
-        Res resources = new Res();
-        
+
         final ServerConfiguration conf = server.getServerConfiguration();
-        conf.addHttpHandler(new Page("console.xhtml", 
+        conf.addHttpHandler(new Page(resources, 
+            "org/apidesign/bck2brwsr/launcher/console.xhtml",
             "org.apidesign.bck2brwsr.launcher.Console", "welcome", "false"
         ), "/console");
         conf.addHttpHandler(new VM(resources), "/bck2brwsr.js");
         conf.addHttpHandler(new VMInit(), "/vm.js");
         conf.addHttpHandler(new Classes(resources), "/classes/");
+        return server;
+    }
+    
+    private void executeInBrowser() throws InterruptedException, URISyntaxException, IOException {
+        final CountDownLatch wait = new CountDownLatch(1);
+        final MethodInvocation[] cases = this.methods.toArray(new MethodInvocation[0]);
+        
+        HttpServer server = initServer();
+        ServerConfiguration conf = server.getServerConfiguration();
+        conf.addHttpHandler(new Page(resources, 
+            "org/apidesign/bck2brwsr/launcher/harness.xhtml"
+        ), "/execute");
         conf.addHttpHandler(new HttpHandler() {
             int cnt;
             @Override
@@ -183,21 +201,8 @@
                 cnt++;
             }
         }, "/data");
-        conf.addHttpHandler(new Page("harness.xhtml"), "/");
-        
-        server.start();
-        NetworkListener listener = server.getListeners().iterator().next();
-        int port = listener.getPort();
-        
-        URI uri = new URI("http://localhost:" + port + "/execute");
-        try {
-            Desktop.getDesktop().browse(uri);
-        } catch (UnsupportedOperationException ex) {
-            String[] cmd = { 
-                "xdg-open", uri.toString()
-            };
-            Runtime.getRuntime().exec(cmd).waitFor();
-        }
+
+        launchServerAndBrwsr(server, "/execute");
         
         wait.await(timeOut, TimeUnit.MILLISECONDS);
         server.stop();
@@ -223,6 +228,23 @@
         }
     }
 
+    private void launchServerAndBrwsr(HttpServer server, final String page) throws IOException, URISyntaxException, InterruptedException {
+        server.start();
+        NetworkListener listener = server.getListeners().iterator().next();
+        int port = listener.getPort();
+        
+        URI uri = new URI("http://localhost:" + port + page);
+        try {
+            Desktop.getDesktop().browse(uri);
+        } catch (UnsupportedOperationException ex) {
+            String[] cmd = { 
+                "xdg-open", uri.toString()
+            };
+            Runtime.getRuntime().exec(cmd).waitFor();
+        }
+        System.err.println("Showing " + uri);
+    }
+
     private class Res implements Bck2Brwsr.Resources {
         @Override
         public InputStream get(String resource) throws IOException {
@@ -243,18 +265,34 @@
     private static class Page extends HttpHandler {
         private final String resource;
         private final String[] args;
+        private final Res res;
         
-        public Page(String resource, String... args) {
+        public Page(Res res, String resource, String... args) {
+            this.res = res;
             this.resource = resource;
             this.args = args;
         }
 
         @Override
         public void service(Request request, Response response) throws Exception {
-            response.setContentType("text/html");
+            String r = resource;
+            if (r == null) {
+                r = request.getHttpHandlerPath();
+                if (r.startsWith("/")) {
+                    r = r.substring(1);
+                }
+            }
+            if (r.endsWith(".html") || r.endsWith(".xhtml")) {
+                response.setContentType("text/html");
+            }
             OutputStream os = response.getOutputStream();
-            InputStream is = Bck2BrwsrLauncher.class.getResourceAsStream(resource);
-            copyStream(is, os, request.getRequestURL().toString(), args);
+            try (InputStream is = res.get(r)) {
+                copyStream(is, os, request.getRequestURL().toString(), args);
+            } catch (IOException ex) {
+                response.setDetailMessage(ex.getLocalizedMessage());
+                response.setError();
+                response.setStatus(404);
+            }
         }
     }
 
@@ -283,7 +321,7 @@
             response.getWriter().append(
                 "function ldCls(res) {\n"
                 + "  var request = new XMLHttpRequest();\n"
-                + "  request.open('GET', 'classes/' + res, false);\n"
+                + "  request.open('GET', '/classes/' + res, false);\n"
                 + "  request.send();\n"
                 + "  var arr = eval('(' + request.responseText + ')');\n"
                 + "  return arr;\n"
diff -r e078953818d2 -r dc375a56fd15 mojo/pom.xml
--- a/mojo/pom.xml	Thu Dec 20 11:03:34 2012 +0100
+++ b/mojo/pom.xml	Thu Dec 20 16:17:31 2012 +0100
@@ -77,5 +77,10 @@
       3.0.2
       jar
     
+    
+        ${project.groupId}
+        launcher
+      ${project.version}
+    
 
 
diff -r e078953818d2 -r dc375a56fd15 mojo/src/main/java/org/apidesign/bck2brwsr/mojo/BrswrMojo.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/BrswrMojo.java	Thu Dec 20 16:17:31 2012 +0100
@@ -0,0 +1,114 @@
+/**
+ * Back 2 Browser Bytecode Translator
+ * Copyright (C) 2012 Jaroslav Tulach 
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. Look for COPYING file in the top folder.
+ * If not, see http://opensource.org/licenses/GPL-2.0.
+ */
+package org.apidesign.bck2brwsr.mojo;
+
+import org.apache.maven.plugin.AbstractMojo;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
+import org.apidesign.bck2brwsr.launcher.Bck2BrwsrLauncher;
+import org.apidesign.vm4brwsr.Bck2Brwsr;
+
+/** Executes given HTML page in a browser. */
+@Mojo(name="brwsr", defaultPhase=LifecyclePhase.DEPLOY)
+public class BrswrMojo extends AbstractMojo {
+    public BrswrMojo() {
+    }
+    /** Resource to show as initial page */
+    @Parameter
+    private String startpage;
+    
+    @Parameter(defaultValue="${project}")
+    private MavenProject prj;
+    
+    /** Root of the class files */
+    @Parameter(defaultValue="${project.build.directory}/classes")
+    private File classes;
+
+    @Override
+    public void execute() throws MojoExecutionException {
+        if (startpage == null) {
+            throw new MojoExecutionException("You have to provide a start page");
+        }
+
+        try {
+            URLClassLoader url = buildClassLoader(classes, prj.getDependencyArtifacts());
+            
+            Bck2BrwsrLauncher httpServer = new Bck2BrwsrLauncher();
+            httpServer.setStartPage(startpage);
+            httpServer.addClassLoader(url);
+            httpServer.execute();
+            
+            System.in.read();
+        } catch (IOException ex) {
+            throw new MojoExecutionException("Can't show the browser", ex);
+        }
+    }
+
+    private static File findNonEmptyFolder(File dir) throws MojoExecutionException {
+        if (!dir.isDirectory()) {
+            throw new MojoExecutionException("Not a directory " + dir);
+        }
+        File[] arr = dir.listFiles();
+        if (arr.length == 1 && arr[0].isDirectory()) {
+            return findNonEmptyFolder(arr[0]);
+        }
+        return dir;
+    }
+
+    private static long collectAllClasses(String prefix, File toCheck, List arr) {
+        File[] files = toCheck.listFiles();
+        if (files != null) {
+            long newest = 0L;
+            for (File f : files) {
+                long lastModified = collectAllClasses(prefix + f.getName() + "/", f, arr);
+                if (newest < lastModified) {
+                    newest = lastModified;
+                }
+            }
+            return newest;
+        } else if (toCheck.getName().endsWith(".class")) {
+            arr.add(prefix.substring(0, prefix.length() - 7));
+            return toCheck.lastModified();
+        } else {
+            return 0L;
+        }
+    }
+
+    private static URLClassLoader buildClassLoader(File root, Collection deps) throws MalformedURLException {
+        List arr = new ArrayList();
+        arr.add(root.toURI().toURL());
+        for (Artifact a : deps) {
+            arr.add(a.getFile().toURI().toURL());
+        }
+        return new URLClassLoader(arr.toArray(new URL[0]), BrswrMojo.class.getClassLoader());
+    }
+}