org.eclipse.tcf.internal.debug.ui.trace.TraceView.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.tcf.internal.debug.ui.trace.TraceView.java

Source

/*******************************************************************************
 * Copyright (c) 2007, 2012 Wind River Systems, Inc. and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Wind River Systems - initial API and implementation
 *******************************************************************************/
package org.eclipse.tcf.internal.debug.ui.trace;

import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationListener;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.jface.resource.ColorRegistry;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabFolder2Adapter;
import org.eclipse.swt.custom.CTabFolderEvent;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.tcf.core.AbstractChannel;
import org.eclipse.tcf.internal.debug.model.TCFLaunch;
import org.eclipse.tcf.protocol.IChannel;
import org.eclipse.tcf.protocol.IPeer;
import org.eclipse.tcf.protocol.JSON;
import org.eclipse.tcf.protocol.Protocol;
import org.eclipse.tcf.util.TCFTask;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;

public class TraceView extends ViewPart implements Protocol.ChannelOpenListener {

    private Composite parent;
    private CTabFolder tabs;
    private Label no_data;
    private final Map<CTabItem, Page> tab2page = new HashMap<CTabItem, Page>();
    private final ILaunchManager launch_manager = DebugPlugin.getDefault().getLaunchManager();

    private final ILaunchConfigurationListener launch_conf_listener = new ILaunchConfigurationListener() {

        public void launchConfigurationAdded(ILaunchConfiguration cfg) {
            cfg = launch_manager.getMovedFrom(cfg);
            if (cfg != null)
                launchConfigurationChanged(cfg);
        }

        public void launchConfigurationChanged(final ILaunchConfiguration cfg) {
            HashSet<IChannel> set = new HashSet<IChannel>();
            for (final ILaunch launch : launch_manager.getLaunches()) {
                if (launch instanceof TCFLaunch && cfg.equals(launch.getLaunchConfiguration())) {
                    set.add(((TCFLaunch) launch).getChannel());
                }
            }
            for (final IChannel channel : set) {
                parent.getDisplay().asyncExec(new Runnable() {
                    public void run() {
                        for (final Page p : tab2page.values()) {
                            if (p.channel == channel) {
                                p.tab.setToolTipText(new TCFTask<String>(p.channel) {
                                    public void run() {
                                        done(getPageToolTipText(p.channel));
                                    }
                                }.getE());
                            }
                        }
                    }
                });
            }
        }

        public void launchConfigurationRemoved(ILaunchConfiguration cfg) {
        }
    };

    private class Page implements AbstractChannel.TraceListener {

        final AbstractChannel channel;

        private CTabItem tab;
        private Text text;

        private final StringBuffer bf = new StringBuffer();
        private int bf_line_cnt = 0;
        private boolean closed;
        private boolean scroll_locked;
        private int key_pressed;
        private int mouse_button_pressed;

        private final Thread update_thread = new Thread() {
            public void run() {
                synchronized (Page.this) {
                    while (!closed) {
                        if (bf_line_cnt > 0 && (!scroll_locked || bf_line_cnt >= 5000)) {
                            Runnable r = new Runnable() {
                                public void run() {
                                    String str = null;
                                    int cnt = 0;
                                    synchronized (Page.this) {
                                        str = bf.toString();
                                        cnt = bf_line_cnt;
                                        bf.setLength(0);
                                        bf_line_cnt = 0;
                                    }
                                    if (text == null)
                                        return;
                                    if (text.getLineCount() > 1000 - cnt) {
                                        String s = text.getText();
                                        int n = 0;
                                        int i = -1;
                                        while (n < cnt) {
                                            int j = s.indexOf('\n', i + 1);
                                            if (j < 0)
                                                break;
                                            i = j;
                                            n++;
                                        }
                                        if (i >= 0) {
                                            text.setText(s.substring(i + 1));
                                        }
                                    }
                                    text.append(str);
                                }
                            };
                            parent.getDisplay().asyncExec(r);
                        }
                        try {
                            Page.this.wait(1000);
                        } catch (InterruptedException e) {
                            break;
                        }
                    }
                }
            }
        };

        Page(AbstractChannel channel) {
            this.channel = channel;
            update_thread.setName("TCF Trace View");
            update_thread.start();
        }

        private void updateScrollLock() {
            if (text == null) {
                scroll_locked = false;
            } else {
                scroll_locked = key_pressed > 0 || mouse_button_pressed > 0 || text.getSelectionCount() > 0;
            }
        }

        public void dispose() {
            if (closed)
                return;
            Protocol.invokeAndWait(new Runnable() {
                public void run() {
                    channel.removeTraceListener(Page.this);
                }
            });
            synchronized (this) {
                closed = true;
                update_thread.interrupt();
            }
            try {
                update_thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (tab != null) {
                tab2page.remove(tab);
                tab.dispose();
                tab = null;
            }
            text = null;
            if (tab2page.isEmpty())
                hideTabs();
        }

        public synchronized void onChannelClosed(Throwable error) {
            if (error == null) {
                parent.getDisplay().asyncExec(new Runnable() {
                    public void run() {
                        dispose();
                    }
                });
            } else {
                bf.append("Channel terminated: " + error);
                bf_line_cnt++;
            }
        }

        public synchronized void onMessageReceived(char type, String token, String service, String name,
                byte[] data) {
            try {
                if ("Locator".equals(service) && "peerHeartBeat".equals(name))
                    return;
                appendTime(bf);
                bf.append("Inp: ");
                bf.append(type);
                if (token != null) {
                    bf.append(' ');
                    bf.append(token);
                }
                if (service != null) {
                    bf.append(' ');
                    bf.append(service);
                }
                if (name != null) {
                    bf.append(' ');
                    bf.append(name);
                }
                if (data != null) {
                    appendData(bf, data);
                }
                bf.append('\n');
                bf_line_cnt++;
            } catch (UnsupportedEncodingException x) {
                x.printStackTrace();
            }
        }

        public synchronized void onMessageSent(char type, String token, String service, String name, byte[] data) {
            try {
                if ("Locator".equals(service) && "peerHeartBeat".equals(name))
                    return;
                appendTime(bf);
                bf.append("Out: ");
                bf.append(type);
                if (token != null) {
                    bf.append(' ');
                    bf.append(token);
                }
                if (service != null) {
                    bf.append(' ');
                    bf.append(service);
                }
                if (name != null) {
                    bf.append(' ');
                    bf.append(name);
                }
                if (data != null) {
                    appendData(bf, data);
                }
                bf.append('\n');
                bf_line_cnt++;
            } catch (UnsupportedEncodingException x) {
                x.printStackTrace();
            }
        }
    }

    @Override
    public void createPartControl(Composite parent) {
        this.parent = parent;
        Protocol.invokeAndWait(new Runnable() {
            public void run() {
                IChannel[] arr = Protocol.getOpenChannels();
                for (IChannel c : arr)
                    onChannelOpen(c);
                Protocol.addChannelOpenListener(TraceView.this);
            }
        });
        if (tab2page.size() == 0)
            hideTabs();
        launch_manager.addLaunchConfigurationListener(launch_conf_listener);
    }

    @Override
    public void setFocus() {
        if (tabs != null)
            tabs.setFocus();
    }

    @Override
    public void dispose() {
        launch_manager.removeLaunchConfigurationListener(launch_conf_listener);
        final Page[] pages = tab2page.values().toArray(new Page[tab2page.size()]);
        Protocol.invokeAndWait(new Runnable() {
            public void run() {
                Protocol.removeChannelOpenListener(TraceView.this);
            }
        });
        for (Page p : pages)
            p.dispose();
        assert tab2page.isEmpty();
        if (tabs != null) {
            tabs.dispose();
            tabs = null;
        }
        if (no_data != null) {
            no_data.dispose();
            no_data = null;
        }
        super.dispose();
    }

    private String getPageTitle(IChannel c) {
        IPeer rp = c.getRemotePeer();
        String title = rp.getName();
        String host = rp.getAttributes().get(IPeer.ATTR_IP_HOST);
        String port = rp.getAttributes().get(IPeer.ATTR_IP_PORT);
        if (host != null) {
            title += ", " + host;
            if (port != null) {
                title += ":" + port;
            }
        }
        return title;
    }

    private String getPageToolTipText(IChannel c) {
        StringBuffer bf = new StringBuffer();
        for (ILaunch launch : launch_manager.getLaunches()) {
            if (launch instanceof TCFLaunch && ((TCFLaunch) launch).getChannel() == c) {
                if (bf.length() > 0)
                    bf.append('\n');
                bf.append("Launch configuration: ");
                bf.append(launch.getLaunchConfiguration().getName());
            }
        }
        IPeer rp = c.getRemotePeer();
        String host = rp.getAttributes().get(IPeer.ATTR_IP_HOST);
        if (host != null) {
            if (bf.length() > 0)
                bf.append('\n');
            bf.append("Agent address: ");
            bf.append(host);
            String port = rp.getAttributes().get(IPeer.ATTR_IP_PORT);
            if (port != null) {
                bf.append(':');
                bf.append(port);
            }
        }
        if (bf.length() > 0)
            bf.append('\n');
        bf.append("Agent name: ");
        bf.append(rp.getName());
        String user_name = rp.getAttributes().get(IPeer.ATTR_USER_NAME);
        if (user_name != null) {
            bf.append('\n');
            bf.append("Agent user: ");
            bf.append(user_name);
        }
        return bf.toString();
    }

    public void onChannelOpen(final IChannel channel) {
        if (!(channel instanceof AbstractChannel))
            return;
        AbstractChannel c = (AbstractChannel) channel;
        final Page p = new Page(c);
        c.addTraceListener(p);
        final String title = getPageTitle(c);
        final String tool_tip = getPageToolTipText(c);
        parent.getDisplay().asyncExec(new Runnable() {
            public void run() {
                if (parent.isDisposed())
                    return;
                showTabs();
                p.tab = new CTabItem(tabs, SWT.NONE);
                tab2page.put(p.tab, p);
                p.tab.setText(title);
                p.tab.setToolTipText(tool_tip);
                p.text = new Text(tabs, SWT.H_SCROLL | SWT.V_SCROLL | SWT.READ_ONLY | SWT.MULTI);
                p.text.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
                p.text.addKeyListener(new KeyListener() {
                    public void keyReleased(KeyEvent e) {
                        if (p.key_pressed > 0)
                            p.key_pressed--;
                        if (e.character == SWT.ESC) {
                            p.key_pressed = 0;
                        }
                        p.updateScrollLock();
                    }

                    public void keyPressed(KeyEvent e) {
                        p.key_pressed++;
                        p.updateScrollLock();
                        if (e.character == SWT.ESC) {
                            p.text.clearSelection();
                        }
                    }
                });
                p.text.addMouseListener(new MouseListener() {
                    public void mouseUp(MouseEvent e) {
                        p.mouse_button_pressed--;
                        p.updateScrollLock();
                    }

                    public void mouseDown(MouseEvent e) {
                        p.mouse_button_pressed++;
                        p.updateScrollLock();
                    }

                    public void mouseDoubleClick(MouseEvent e) {
                    }
                });
                p.tab.setControl(p.text);
                if (tabs.getSelection() == null)
                    tabs.setSelection(p.tab);
            }
        });
    }

    private void appendTime(StringBuffer bf) {
        String s = Long.toString(System.currentTimeMillis());
        int l = s.length();
        if (l < 6)
            return;
        bf.append(s.charAt(l - 6));
        bf.append(s.charAt(l - 5));
        bf.append(s.charAt(l - 4));
        bf.append('.');
        bf.append(s.charAt(l - 3));
        bf.append(s.charAt(l - 2));
        bf.append(s.charAt(l - 1));
        bf.append(' ');
    }

    private void appendData(StringBuffer bf, byte[] data) throws UnsupportedEncodingException {
        int pos = bf.length();
        try {
            Object[] o = JSON.parseSequence(data);
            for (int i = 0; i < o.length; i++) {
                bf.append(' ');
                appendJSON(bf, o[i]);
            }
        } catch (Throwable z) {
            bf.setLength(pos);
            for (int i = 0; i < data.length; i++) {
                bf.append(' ');
                int x = (data[i] >> 4) & 0xf;
                int y = data[i] & 0xf;
                bf.append((char) (x < 10 ? '0' + x : 'a' + x - 10));
                bf.append((char) (y < 10 ? '0' + y : 'a' + y - 10));
            }
        }
    }

    private void appendJSON(StringBuffer bf, Object o) {
        if (o instanceof byte[]) {
            int l = ((byte[]) o).length;
            bf.append('(');
            bf.append(l);
            bf.append(')');
        } else if (o instanceof Collection) {
            int cnt = 0;
            bf.append('[');
            for (Object i : (Collection<?>) o) {
                if (cnt > 0)
                    bf.append(',');
                appendJSON(bf, i);
                cnt++;
            }
            bf.append(']');
        } else if (o instanceof Map) {
            int cnt = 0;
            bf.append('{');
            for (Object k : ((Map<?, ?>) o).keySet()) {
                if (cnt > 0)
                    bf.append(',');
                bf.append(k.toString());
                bf.append(':');
                appendJSON(bf, ((Map<?, ?>) o).get(k));
                cnt++;
            }
            bf.append('}');
        } else if (o instanceof String) {
            bf.append('"');
            String s = (String) o;
            int l = s.length();
            for (int i = 0; i < l; i++) {
                char ch = s.charAt(i);
                if (ch < ' ') {
                    bf.append('\\');
                    bf.append('u');
                    for (int j = 0; j < 4; j++) {
                        int x = (ch >> (4 * (3 - j))) & 0xf;
                        bf.append((char) (x < 10 ? '0' + x : 'a' + x - 10));
                    }
                } else {
                    bf.append(ch);
                }
            }
            bf.append('"');
        } else {
            bf.append(o);
        }
    }

    private void showTabs() {
        boolean b = false;
        if (no_data != null) {
            no_data.dispose();
            no_data = null;
            b = true;
        }
        if (tabs == null && !parent.isDisposed()) {
            tabs = new CTabFolder(parent, SWT.FLAT | SWT.CLOSE);
            ColorRegistry reg = JFaceResources.getColorRegistry();
            Color c1 = reg.get("org.eclipse.ui.workbench.ACTIVE_TAB_BG_START"); //$NON-NLS-1$
            Color c2 = reg.get("org.eclipse.ui.workbench.ACTIVE_TAB_BG_END"); //$NON-NLS-1$
            tabs.setSelectionBackground(new Color[] { c1, c2 }, new int[] { 100 }, true);
            tabs.setSelectionForeground(reg.get("org.eclipse.ui.workbench.ACTIVE_TAB_TEXT_COLOR")); //$NON-NLS-1$
            tabs.setSimple(PlatformUI.getPreferenceStore()
                    .getBoolean(IWorkbenchPreferenceConstants.SHOW_TRADITIONAL_STYLE_TABS));
            tabs.addCTabFolder2Listener(new CTabFolder2Adapter() {
                public void close(CTabFolderEvent event) {
                    CTabItem s = (CTabItem) event.item;
                    Page p = tab2page.get(s);
                    if (p != null)
                        p.dispose();
                    else
                        s.dispose();
                    event.doit = false;
                }
            });
            Menu menu = new Menu(tabs);
            MenuItem mi_close = new MenuItem(menu, SWT.NONE);
            mi_close.setText("Close");
            mi_close.addSelectionListener(new SelectionListener() {
                public void widgetDefaultSelected(SelectionEvent e) {
                }

                public void widgetSelected(SelectionEvent e) {
                    if (tabs == null)
                        return;
                    CTabItem s = tabs.getSelection();
                    Page p = tab2page.get(s);
                    if (p != null)
                        p.dispose();
                    else
                        s.dispose();
                }
            });
            MenuItem mi_close_all = new MenuItem(menu, SWT.NONE);
            mi_close_all.setText("Close All");
            mi_close_all.addSelectionListener(new SelectionListener() {
                public void widgetDefaultSelected(SelectionEvent e) {
                }

                public void widgetSelected(SelectionEvent e) {
                    if (tabs == null)
                        return;
                    CTabItem[] s = tabs.getItems();
                    for (CTabItem i : s) {
                        Page p = tab2page.get(i);
                        if (p != null)
                            p.dispose();
                        else
                            i.dispose();
                    }
                }
            });
            tabs.setMenu(menu);
            b = true;
        }
        if (b)
            parent.layout();
    }

    private void hideTabs() {
        boolean b = false;
        if (tabs != null) {
            tabs.dispose();
            tabs = null;
            b = true;
        }
        if (!parent.isDisposed()) {
            if (no_data == null) {
                no_data = new Label(parent, SWT.NONE);
                no_data.setText("No open communication channels at this time.");
                b = true;
            }
            if (b)
                parent.layout();
        }
    }
}