launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/WebDebug.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 08 Jun 2013 12:09:10 +0200
changeset 1169 c19ac78b940e
child 1173 aa82f9de8e33
permissions -rw-r--r--
LiveHTML WebKitDebugging protocol through CLI that supports --livehtml command
jaroslav@1169
     1
/**
jaroslav@1169
     2
 * Back 2 Browser Bytecode Translator
jaroslav@1169
     3
 * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
jaroslav@1169
     4
 *
jaroslav@1169
     5
 * This program is free software: you can redistribute it and/or modify
jaroslav@1169
     6
 * it under the terms of the GNU General Public License as published by
jaroslav@1169
     7
 * the Free Software Foundation, version 2 of the License.
jaroslav@1169
     8
 *
jaroslav@1169
     9
 * This program is distributed in the hope that it will be useful,
jaroslav@1169
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
jaroslav@1169
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
jaroslav@1169
    12
 * GNU General Public License for more details.
jaroslav@1169
    13
 *
jaroslav@1169
    14
 * You should have received a copy of the GNU General Public License
jaroslav@1169
    15
 * along with this program. Look for COPYING file in the top folder.
jaroslav@1169
    16
 * If not, see http://opensource.org/licenses/GPL-2.0.
jaroslav@1169
    17
 */
jaroslav@1169
    18
package org.apidesign.bck2brwsr.launcher.fximpl;
jaroslav@1169
    19
jaroslav@1169
    20
import com.sun.javafx.scene.web.Debugger;
jaroslav@1169
    21
import java.io.File;
jaroslav@1169
    22
import java.io.IOException;
jaroslav@1169
    23
import java.io.InputStream;
jaroslav@1169
    24
import java.io.InterruptedIOException;
jaroslav@1169
    25
import java.io.OutputStream;
jaroslav@1169
    26
import java.io.UnsupportedEncodingException;
jaroslav@1169
    27
import java.lang.reflect.Method;
jaroslav@1169
    28
import java.util.concurrent.ArrayBlockingQueue;
jaroslav@1169
    29
import java.util.concurrent.Executors;
jaroslav@1169
    30
import java.util.concurrent.TimeUnit;
jaroslav@1169
    31
import java.util.concurrent.atomic.AtomicReference;
jaroslav@1169
    32
import java.util.logging.Level;
jaroslav@1169
    33
import java.util.logging.Logger;
jaroslav@1169
    34
import javafx.application.Platform;
jaroslav@1169
    35
import javafx.util.Callback;
jaroslav@1169
    36
jaroslav@1169
    37
/** Simulates WebKit protocol over WebSockets.
jaroslav@1169
    38
 *
jaroslav@1169
    39
 * @author Jaroslav Tulach
jaroslav@1169
    40
 */
jaroslav@1169
    41
abstract class WebDebug extends OutputStream 
jaroslav@1169
    42
implements Callback<String, Void>, Runnable {
jaroslav@1169
    43
    private static final Logger LOG = Logger.getLogger(WebDebug.class.getName());
jaroslav@1169
    44
jaroslav@1169
    45
    private final Debugger debug;
jaroslav@1169
    46
    private final StringBuilder cmd = new StringBuilder();
jaroslav@1169
    47
    private final ToDbgInputStream toDbg;
jaroslav@1169
    48
    private final String ud;
jaroslav@1169
    49
    
jaroslav@1169
    50
    WebDebug(Debugger debug, String ud) throws Exception {
jaroslav@1169
    51
        this.debug = debug;
jaroslav@1169
    52
        this.ud = ud;
jaroslav@1169
    53
        toDbg = new ToDbgInputStream();
jaroslav@1169
    54
        debug.setEnabled(true);
jaroslav@1169
    55
        debug.setMessageCallback(this);
jaroslav@1169
    56
    }
jaroslav@1169
    57
    
jaroslav@1169
    58
    static WebDebug create(Debugger debug, String ud) throws Exception {
jaroslav@1169
    59
        WebDebug web = new WebDebug(debug, ud) {};
jaroslav@1169
    60
        
jaroslav@1169
    61
        Executors.newFixedThreadPool(1).execute(web);
jaroslav@1169
    62
        
jaroslav@1169
    63
        return web;
jaroslav@1169
    64
    }
jaroslav@1169
    65
jaroslav@1169
    66
    @Override
jaroslav@1169
    67
    public void run() {
jaroslav@1169
    68
        try {
jaroslav@1169
    69
            String p = "/home/jarda/src/bck2brwsr/html~demo/twitter/src/main/resources/org/apidesign/html/demo/twitter/index.html";
jaroslav@1169
    70
            File f = new File(p);
jaroslav@1169
    71
            String[] args = {"--livehtml", f.getAbsolutePath()};
jaroslav@1169
    72
            File dir = f.getParentFile();
jaroslav@1169
    73
            cliHandler(args, toDbg, this, System.err, dir);
jaroslav@1169
    74
        } catch (Exception ex) {
jaroslav@1169
    75
            LOG.log(Level.SEVERE, null, ex);
jaroslav@1169
    76
        }
jaroslav@1169
    77
    }
jaroslav@1169
    78
jaroslav@1169
    79
    @Override
jaroslav@1169
    80
    public void close() {
jaroslav@1169
    81
        try {
jaroslav@1169
    82
            toDbg.close();
jaroslav@1169
    83
        } catch (IOException ex) {
jaroslav@1169
    84
            LOG.log(Level.SEVERE, null, ex);
jaroslav@1169
    85
        }
jaroslav@1169
    86
    }
jaroslav@1169
    87
jaroslav@1169
    88
    @Override
jaroslav@1169
    89
    public Void call(String p) {
jaroslav@1169
    90
        assert p.indexOf('\n') == -1 : "No new line: " + p;
jaroslav@1169
    91
        LOG.log(Level.INFO, "toDbgr: {0}", p);
jaroslav@1169
    92
        toDbg.pushMsg(p);
jaroslav@1169
    93
        return null;
jaroslav@1169
    94
    }
jaroslav@1169
    95
jaroslav@1169
    96
    @Override
jaroslav@1169
    97
    public void write(int b) throws IOException {
jaroslav@1169
    98
        if (b == '\n') {
jaroslav@1169
    99
            final String msg = cmd.toString();
jaroslav@1169
   100
            Platform.runLater(new Runnable() {
jaroslav@1169
   101
                @Override
jaroslav@1169
   102
                public void run() {
jaroslav@1169
   103
                    LOG.log(Level.INFO, "toView: {0}", msg);
jaroslav@1169
   104
                    debug.sendMessage(msg);
jaroslav@1169
   105
                }
jaroslav@1169
   106
            });
jaroslav@1169
   107
            cmd.setLength(0);
jaroslav@1169
   108
        } else {
jaroslav@1169
   109
            if (cmd.length() > 100000) {
jaroslav@1169
   110
                LOG.log(Level.WARNING, "Too big:\n{0}", cmd);
jaroslav@1169
   111
            }
jaroslav@1169
   112
            cmd.append((char)b);
jaroslav@1169
   113
        }
jaroslav@1169
   114
    }   
jaroslav@1169
   115
jaroslav@1169
   116
    private void cliHandler(
jaroslav@1169
   117
        String[] args, InputStream is, OutputStream os, OutputStream err, File dir
jaroslav@1169
   118
    ) {
jaroslav@1169
   119
        try {
jaroslav@1169
   120
            Class<?> main = Class.forName("org.netbeans.MainImpl");
jaroslav@1169
   121
            Method m = main.getDeclaredMethod("execute", String[].class, InputStream.class, 
jaroslav@1169
   122
                OutputStream.class, OutputStream.class, AtomicReference.class
jaroslav@1169
   123
            );
jaroslav@1169
   124
            m.setAccessible(true);
jaroslav@1169
   125
            System.setProperty("netbeans.user", ud);
jaroslav@1169
   126
            int ret = (Integer)m.invoke(null, args, is, os, err, null);
jaroslav@1169
   127
            LOG.log(Level.INFO, "Return value: {0}", ret);
jaroslav@1169
   128
        } catch (Exception ex) {
jaroslav@1169
   129
            LOG.log(Level.SEVERE, null, ex);
jaroslav@1169
   130
        } finally {
jaroslav@1169
   131
            LOG.info("Communication is over");
jaroslav@1169
   132
        }
jaroslav@1169
   133
        
jaroslav@1169
   134
    }
jaroslav@1169
   135
jaroslav@1169
   136
    private class ToDbgInputStream extends InputStream {
jaroslav@1169
   137
        private byte[] current;
jaroslav@1169
   138
        private int currentPos;
jaroslav@1169
   139
        private final ArrayBlockingQueue<byte[]> pending = new ArrayBlockingQueue<byte[]>(64);
jaroslav@1169
   140
jaroslav@1169
   141
        public ToDbgInputStream() {
jaroslav@1169
   142
        }
jaroslav@1169
   143
jaroslav@1169
   144
        @Override
jaroslav@1169
   145
        public int read() throws IOException {
jaroslav@1169
   146
            return read(null, 0, 1);
jaroslav@1169
   147
        }
jaroslav@1169
   148
        
jaroslav@1169
   149
        @Override
jaroslav@1169
   150
        public int read(byte[] arr, int offset, int len) throws IOException {
jaroslav@1169
   151
            if (current == null || current.length <= currentPos) {
jaroslav@1169
   152
                for (;;) {
jaroslav@1169
   153
                    WebDebug.this.flush();
jaroslav@1169
   154
                    try {
jaroslav@1169
   155
                        current = pending.poll(100, TimeUnit.MILLISECONDS);
jaroslav@1169
   156
                        if (current == null) {
jaroslav@1169
   157
                            return 0;
jaroslav@1169
   158
                        }
jaroslav@1169
   159
                        break;
jaroslav@1169
   160
                    } catch (InterruptedException ex) {
jaroslav@1169
   161
                        throw (InterruptedIOException)new InterruptedIOException().initCause(ex);
jaroslav@1169
   162
                    }
jaroslav@1169
   163
                }
jaroslav@1169
   164
                LOG.info("Will return: " + new String(current));
jaroslav@1169
   165
                currentPos = 0;
jaroslav@1169
   166
            }
jaroslav@1169
   167
            int cnt = 0;
jaroslav@1169
   168
            while (len-- > 0 && currentPos < current.length) {
jaroslav@1169
   169
                final byte nextByte = current[currentPos++];
jaroslav@1169
   170
                if (arr == null) {
jaroslav@1169
   171
                    return nextByte;
jaroslav@1169
   172
                }
jaroslav@1169
   173
                arr[offset + cnt++] = nextByte;
jaroslav@1169
   174
            }
jaroslav@1169
   175
            LOG.log(Level.INFO, "read returns: {0}", new String(arr, offset, cnt));
jaroslav@1169
   176
            return cnt;
jaroslav@1169
   177
        }
jaroslav@1169
   178
jaroslav@1169
   179
        private void pushMsg(String p) {
jaroslav@1169
   180
            try {
jaroslav@1169
   181
                pending.offer((p + '\n').getBytes("UTF-8"));
jaroslav@1169
   182
            } catch (UnsupportedEncodingException ex) {
jaroslav@1169
   183
                throw new IllegalStateException(ex);
jaroslav@1169
   184
            }
jaroslav@1169
   185
        }
jaroslav@1169
   186
    }
jaroslav@1169
   187
}