org.chromium.debug.core/src/org/chromium/debug/core/model/ConsolePseudoProcess.java
changeset 2 e4420d2515f1
equal deleted inserted replaced
1:ef76fc2ac88c 2:e4420d2515f1
       
     1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
       
     2 // Use of this source code is governed by a BSD-style license that can be
       
     3 // found in the LICENSE file.
       
     4 
       
     5 package org.chromium.debug.core.model;
       
     6 
       
     7 import java.io.StringWriter;
       
     8 import java.io.Writer;
       
     9 import java.util.ArrayList;
       
    10 import java.util.HashMap;
       
    11 import java.util.List;
       
    12 import java.util.Map;
       
    13 
       
    14 import org.chromium.debug.core.ChromiumDebugPlugin;
       
    15 import org.eclipse.core.runtime.IStatus;
       
    16 import org.eclipse.core.runtime.PlatformObject;
       
    17 import org.eclipse.core.runtime.Status;
       
    18 import org.eclipse.debug.core.DebugEvent;
       
    19 import org.eclipse.debug.core.DebugException;
       
    20 import org.eclipse.debug.core.DebugPlugin;
       
    21 import org.eclipse.debug.core.ILaunch;
       
    22 import org.eclipse.debug.core.ILaunchConfiguration;
       
    23 import org.eclipse.debug.core.IStreamListener;
       
    24 import org.eclipse.debug.core.model.IProcess;
       
    25 import org.eclipse.debug.core.model.IStreamMonitor;
       
    26 import org.eclipse.debug.core.model.IStreamsProxy;
       
    27 import org.eclipse.debug.core.model.ITerminate;
       
    28 
       
    29 /**
       
    30  * This process corresponds to a Debugger-Chrome connection and its main
       
    31  * purpose is to expose connection log (see process console in UI).
       
    32  */
       
    33 public class ConsolePseudoProcess extends PlatformObject implements IProcess {
       
    34 
       
    35   private final ILaunch launch;
       
    36   private final Retransmitter outputMonitor;
       
    37   private final ITerminate connectionTerminate;
       
    38   private final String name;
       
    39   private Map<String, String> attributes = null;
       
    40 
       
    41   private final IStreamsProxy streamsProxy = new IStreamsProxy() {
       
    42     public IStreamMonitor getErrorStreamMonitor() {
       
    43       return NullStreamMonitor.INSTANCE;
       
    44     }
       
    45     public IStreamMonitor getOutputStreamMonitor() {
       
    46       return outputMonitor;
       
    47     }
       
    48     public void write(String input) {
       
    49       // ignore
       
    50     }
       
    51   };
       
    52 
       
    53   /**
       
    54    * Constructs a ConsolePseudoProcess, adding this process to the given launch.
       
    55    *
       
    56    * @param launch the parent launch of this process
       
    57    * @param name the label used for this process
       
    58    */
       
    59   public ConsolePseudoProcess(ILaunch launch, String name, Retransmitter retransmitter,
       
    60       ITerminate connectionTerminate) {
       
    61     this.launch = launch;
       
    62     this.name = name;
       
    63     this.outputMonitor = retransmitter;
       
    64     outputMonitor.consolePseudoProcess = this;
       
    65     this.connectionTerminate = connectionTerminate;
       
    66 
       
    67     this.launch.addProcess(this);
       
    68     fireCreationEvent();
       
    69   }
       
    70 
       
    71   /**
       
    72    * @return writer which directs its contents to process console
       
    73    */
       
    74   public Writer getOutputWriter() {
       
    75     return outputMonitor;
       
    76   }
       
    77 
       
    78   public String getLabel() {
       
    79       return name;
       
    80   }
       
    81 
       
    82   public ILaunch getLaunch() {
       
    83       return launch;
       
    84   }
       
    85 
       
    86   public boolean isTerminated() {
       
    87       return connectionTerminate.isTerminated();
       
    88   }
       
    89 
       
    90   public void terminate() throws DebugException {
       
    91     connectionTerminate.terminate();
       
    92   }
       
    93 
       
    94   public boolean canTerminate() {
       
    95     return connectionTerminate.canTerminate();
       
    96   }
       
    97 
       
    98   public IStreamsProxy getStreamsProxy() {
       
    99     return streamsProxy;
       
   100   }
       
   101 
       
   102   /*
       
   103    * We do not expect intensive usage of attributes for this class. In fact, other option was to
       
   104    * keep this method no-op.
       
   105    */
       
   106   public synchronized void setAttribute(String key, String value) {
       
   107     if (attributes == null) {
       
   108       attributes = new HashMap<String, String>(1);
       
   109     }
       
   110     String origVal = attributes.get(key);
       
   111     if (origVal != null && origVal.equals(value)) {
       
   112       return;
       
   113     }
       
   114 
       
   115     attributes.put(key, value);
       
   116     fireChangeEvent();
       
   117   }
       
   118 
       
   119   /*
       
   120    * We do not expect intensive usage of attributes for this class. In fact, other option was to
       
   121    * put a stub here.
       
   122    */
       
   123   public synchronized String getAttribute(String key) {
       
   124     if (attributes == null) {
       
   125       return null;
       
   126     }
       
   127     return attributes.get(key);
       
   128   }
       
   129 
       
   130   public int getExitValue() throws DebugException {
       
   131     if (isTerminated()) {
       
   132       return 0;
       
   133     }
       
   134     throw new DebugException(new Status(IStatus.ERROR, ChromiumDebugPlugin.PLUGIN_ID,
       
   135         "Process hasn't been terminated yet"));  //$NON-NLS-1$
       
   136   }
       
   137 
       
   138   private void fireCreationEvent() {
       
   139     fireEvent(new DebugEvent(this, DebugEvent.CREATE));
       
   140   }
       
   141 
       
   142   private void fireEvent(DebugEvent event) {
       
   143     DebugPlugin manager = DebugPlugin.getDefault();
       
   144     if (manager != null) {
       
   145       manager.fireDebugEventSet(new DebugEvent[] { event });
       
   146     }
       
   147   }
       
   148 
       
   149   private void fireTerminateEvent() {
       
   150     outputMonitor.flush();
       
   151     fireEvent(new DebugEvent(this, DebugEvent.TERMINATE));
       
   152   }
       
   153 
       
   154   private void fireChangeEvent() {
       
   155     fireEvent(new DebugEvent(this, DebugEvent.CHANGE));
       
   156   }
       
   157 
       
   158   @Override
       
   159   public Object getAdapter(Class adapter) {
       
   160     if (adapter.equals(IProcess.class)) {
       
   161       return this;
       
   162     }
       
   163     if (adapter.equals(ILaunch.class)) {
       
   164       return getLaunch();
       
   165     }
       
   166     if (adapter.equals(ILaunchConfiguration.class)) {
       
   167       return getLaunch().getLaunchConfiguration();
       
   168     }
       
   169     return super.getAdapter(adapter);
       
   170   }
       
   171 
       
   172 
       
   173   private static class NullStreamMonitor implements IStreamMonitor {
       
   174     public void addListener(IStreamListener listener) {
       
   175     }
       
   176     public String getContents() {
       
   177       return null;
       
   178     }
       
   179     public void removeListener(IStreamListener listener) {
       
   180     }
       
   181     static final NullStreamMonitor INSTANCE = new NullStreamMonitor();
       
   182   }
       
   183 
       
   184   /**
       
   185    * Responsible for getting text as {@link Writer} and retransmitting it
       
   186    * as {@link IStreamMonitor} to whoever is interested.
       
   187    * However in its initial state it only receives signal (the text) and saves it in a buffer.
       
   188    * For {@link Retransmitter} to start giving the signal away one should
       
   189    * call {@link #startFlushing} method.
       
   190    */
       
   191   public static class Retransmitter extends Writer implements IStreamMonitor {
       
   192     private StringWriter writer = new StringWriter();
       
   193     private boolean isFlushing = false;
       
   194     private final List<IStreamListener> listeners = new ArrayList<IStreamListener>(2);
       
   195     private volatile ConsolePseudoProcess consolePseudoProcess = null;
       
   196 
       
   197     public synchronized void addListener(IStreamListener listener) {
       
   198       listeners.add(listener);
       
   199     }
       
   200 
       
   201     public String getContents() {
       
   202       return null;
       
   203     }
       
   204 
       
   205     public synchronized void removeListener(IStreamListener listener) {
       
   206       listeners.remove(listener);
       
   207     }
       
   208 
       
   209     @Override
       
   210     public synchronized void flush() {
       
   211       if (!isFlushing) {
       
   212         return;
       
   213       }
       
   214       String text = writer.toString();
       
   215       int lastLinePos;
       
   216       final boolean flushOnlyFullLines = true;
       
   217       if (flushOnlyFullLines) {
       
   218         int pos = text.lastIndexOf('\n');
       
   219         if (pos == -1) {
       
   220           // No full line in the buffer.
       
   221           return;
       
   222         }
       
   223         lastLinePos = pos + 1;
       
   224       } else {
       
   225         lastLinePos = text.length();
       
   226       }
       
   227       String readyText = text.substring(0, lastLinePos);
       
   228       writer = new StringWriter();
       
   229       if (lastLinePos != text.length()) {
       
   230         String rest = text.substring(lastLinePos);
       
   231         writer.append(rest);
       
   232       }
       
   233       for (IStreamListener listener : listeners) {
       
   234         listener.streamAppended(readyText, this);
       
   235       }
       
   236     }
       
   237 
       
   238     @Override
       
   239     public synchronized void close() {
       
   240       // do nothing
       
   241     }
       
   242 
       
   243     @Override
       
   244     public synchronized void write(char[] cbuf, int off, int len) {
       
   245       writer.write(cbuf, off, len);
       
   246     }
       
   247 
       
   248     public synchronized void startFlushing() {
       
   249       isFlushing = true;
       
   250       flush();
       
   251     }
       
   252 
       
   253     public void processClosed() {
       
   254       ConsolePseudoProcess consolePseudoProcess0 = this.consolePseudoProcess;
       
   255       if (consolePseudoProcess0 != null) {
       
   256         consolePseudoProcess0.fireTerminateEvent();
       
   257       }
       
   258     }
       
   259   }
       
   260 }