|
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.IOException; |
|
8 import java.io.Reader; |
|
9 import java.io.Writer; |
|
10 |
|
11 import org.chromium.sdk.ConnectionLogger; |
|
12 import org.eclipse.debug.core.DebugPlugin; |
|
13 import org.eclipse.debug.core.model.ITerminate; |
|
14 |
|
15 /** |
|
16 * Connection logger that writes both incoming and outgoing streams into |
|
17 * logWriter with simple annotations. |
|
18 */ |
|
19 public class ConnectionLoggerImpl implements ConnectionLogger { |
|
20 /** |
|
21 * Additional interface logger sends its output to. |
|
22 */ |
|
23 public interface LogLifecycleListener { |
|
24 /** |
|
25 * Notifies about logging start. Before this call {@link ConnectionLoggerImpl} |
|
26 * is considered to be simply garbage-collectible. After this call |
|
27 * {@link ConnectionLoggerImpl} must call {@link #logClosed()}. |
|
28 * |
|
29 * @param connectionLogger instance of host {@link ConnectionLoggerImpl}, which is nice |
|
30 * to have because theoretically we may receive this call before constructor of |
|
31 * {@link ConnectionLoggerImpl} returned |
|
32 */ |
|
33 void logStarted(ConnectionLoggerImpl connectionLogger); |
|
34 |
|
35 /** |
|
36 * Notifies about log stream being closed. Technically, last messages may arrive |
|
37 * even after this. It is supposed that log representation may be closed on this call |
|
38 * because we are not 100% accurate. |
|
39 */ |
|
40 void logClosed(); |
|
41 } |
|
42 |
|
43 |
|
44 public ConnectionLoggerImpl(Writer logWriter, LogLifecycleListener lifecycleListener) { |
|
45 this.logWriter = logWriter; |
|
46 this.lifecycleListener = lifecycleListener; |
|
47 } |
|
48 |
|
49 public Writer wrapWriter(final Writer streamWriter) { |
|
50 return new Writer() { |
|
51 @Override |
|
52 public void close() throws IOException { |
|
53 streamWriter.close(); |
|
54 flushLogWriter(); |
|
55 } |
|
56 @Override |
|
57 public void flush() throws IOException { |
|
58 streamWriter.flush(); |
|
59 flushLogWriter(); |
|
60 } |
|
61 @Override |
|
62 public void write(char[] cbuf, int off, int len) throws IOException { |
|
63 streamWriter.write(cbuf, off, len); |
|
64 |
|
65 writeToLog(cbuf, off, len, this, |
|
66 Messages.ConnectionLoggerImpl_SentToChrome); |
|
67 } |
|
68 }; |
|
69 } |
|
70 public Reader wrapReader(final Reader streamReader) { |
|
71 return new Reader() { |
|
72 @Override |
|
73 public void close() throws IOException { |
|
74 streamReader.close(); |
|
75 flushLogWriter(); |
|
76 } |
|
77 |
|
78 @Override |
|
79 public int read(char[] cbuf, int off, int len) throws IOException { |
|
80 int res = streamReader.read(cbuf, off, len); |
|
81 if (res > 0) { |
|
82 writeToLog(cbuf, off, res, this, |
|
83 Messages.ConnectionLoggerImpl_ReceivedFromChrome); |
|
84 flushLogWriter(); |
|
85 } |
|
86 return res; |
|
87 } |
|
88 }; |
|
89 } |
|
90 |
|
91 public void start() { |
|
92 lifecycleListener.logStarted(this); |
|
93 } |
|
94 |
|
95 public void handleEos() { |
|
96 isClosed = true; |
|
97 lifecycleListener.logClosed(); |
|
98 } |
|
99 |
|
100 public ITerminate getConnectionTerminate() { |
|
101 return connectionTerminate; |
|
102 } |
|
103 |
|
104 public void setConnectionCloser(ConnectionCloser connectionCloser) { |
|
105 this.connectionCloser = connectionCloser; |
|
106 } |
|
107 |
|
108 private synchronized void writeToLog(char[] cbuf, int off, int len, Object source, |
|
109 String sourceName) { |
|
110 try { |
|
111 if (lastSource != source) { |
|
112 if (lastSource != null) { |
|
113 logWriter.append('\n'); |
|
114 } |
|
115 logWriter.append("> ").append(sourceName).append('\n'); //$NON-NLS-1$ |
|
116 lastSource = source; |
|
117 } |
|
118 logWriter.write(cbuf, off, len); |
|
119 } catch (IOException e) { |
|
120 DebugPlugin.log(e); |
|
121 } |
|
122 } |
|
123 private void flushLogWriter() { |
|
124 try { |
|
125 logWriter.flush(); |
|
126 } catch (IOException e) { |
|
127 DebugPlugin.log(e); |
|
128 } |
|
129 } |
|
130 |
|
131 private final Writer logWriter; |
|
132 private final LogLifecycleListener lifecycleListener; |
|
133 private Object lastSource = null; |
|
134 private volatile ConnectionCloser connectionCloser = null; |
|
135 private volatile boolean isClosed = false; |
|
136 |
|
137 private final ITerminate connectionTerminate = new ITerminate() { |
|
138 public boolean canTerminate() { |
|
139 return !isClosed && connectionCloser != null; |
|
140 } |
|
141 |
|
142 public boolean isTerminated() { |
|
143 return isClosed; |
|
144 } |
|
145 |
|
146 public void terminate() { |
|
147 ConnectionCloser connectionCloser0 = ConnectionLoggerImpl.this.connectionCloser; |
|
148 if (connectionCloser0 == null) { |
|
149 throw new IllegalStateException(); |
|
150 } |
|
151 connectionCloser0.closeConnection(); |
|
152 } |
|
153 }; |
|
154 } |