|
1 package org.chromium.debug.core.model; |
|
2 |
|
3 import java.io.IOException; |
|
4 import java.net.InetSocketAddress; |
|
5 import java.net.SocketAddress; |
|
6 import java.text.MessageFormat; |
|
7 import java.util.HashMap; |
|
8 import java.util.Map; |
|
9 |
|
10 import org.chromium.debug.core.ChromiumDebugPlugin; |
|
11 import org.chromium.sdk.Browser; |
|
12 import org.chromium.sdk.BrowserFactory; |
|
13 import org.chromium.sdk.BrowserTab; |
|
14 import org.chromium.sdk.ConnectionLogger; |
|
15 import org.chromium.sdk.DebugEventListener; |
|
16 import org.chromium.sdk.JavascriptVm; |
|
17 import org.chromium.sdk.StandaloneVm; |
|
18 import org.chromium.sdk.TabDebugEventListener; |
|
19 import org.chromium.sdk.UnsupportedVersionException; |
|
20 import org.chromium.sdk.Browser.TabFetcher; |
|
21 import org.eclipse.core.runtime.CoreException; |
|
22 import org.eclipse.core.runtime.Status; |
|
23 |
|
24 |
|
25 public class JavascriptVmEmbedderFactory { |
|
26 |
|
27 private static final String LOCALHOST = "127.0.0.1"; //$NON-NLS-1$ |
|
28 |
|
29 public static JavascriptVmEmbedder.ConnectionToRemote connectToChromeDevTools(int port, |
|
30 NamedConnectionLoggerFactory connectionLoggerFactory, final TabSelector tabSelector) |
|
31 throws CoreException { |
|
32 |
|
33 SocketAddress address = new InetSocketAddress(LOCALHOST, port); |
|
34 final Browser browser = browserCache.getOrCreateBrowser(address, connectionLoggerFactory); |
|
35 |
|
36 final TabFetcher tabFetcher; |
|
37 try { |
|
38 tabFetcher = browser.createTabFetcher(); |
|
39 } catch (UnsupportedVersionException e) { |
|
40 throw newCoreException(e); |
|
41 } catch (IOException e) { |
|
42 throw newCoreException(e); |
|
43 } |
|
44 |
|
45 return new JavascriptVmEmbedder.ConnectionToRemote() { |
|
46 public JavascriptVmEmbedder.VmConnector selectVm() throws CoreException { |
|
47 Browser.TabConnector targetTabConnector; |
|
48 try { |
|
49 targetTabConnector = tabSelector.selectTab(tabFetcher); |
|
50 } catch (IOException e) { |
|
51 throw newCoreException("Failed to get tabs for debugging", e); |
|
52 } |
|
53 if (targetTabConnector == null) { |
|
54 return null; |
|
55 } |
|
56 |
|
57 return new EmbeddingTabConnector(targetTabConnector); |
|
58 } |
|
59 |
|
60 public void disposeConnection() { |
|
61 tabFetcher.dismiss(); |
|
62 } |
|
63 }; |
|
64 } |
|
65 |
|
66 private static final class EmbeddingTabConnector implements JavascriptVmEmbedder.VmConnector { |
|
67 private final Browser.TabConnector targetTabConnector; |
|
68 |
|
69 EmbeddingTabConnector(Browser.TabConnector targetTabConnector) { |
|
70 this.targetTabConnector = targetTabConnector; |
|
71 } |
|
72 |
|
73 public JavascriptVmEmbedder attach(final JavascriptVmEmbedder.Listener embedderListener, |
|
74 final DebugEventListener debugEventListener) throws CoreException { |
|
75 TabDebugEventListener tabDebugEventListener = new TabDebugEventListener() { |
|
76 public DebugEventListener getDebugEventListener() { |
|
77 return debugEventListener; |
|
78 } |
|
79 public void closed() { |
|
80 embedderListener.closed(); |
|
81 } |
|
82 public void navigated(String newUrl) { |
|
83 embedderListener.reset(); |
|
84 } |
|
85 }; |
|
86 final BrowserTab browserTab; |
|
87 try { |
|
88 browserTab = targetTabConnector.attach(tabDebugEventListener); |
|
89 } catch (IOException e) { |
|
90 throw newCoreException("Failed to connect to browser tab", e); |
|
91 } |
|
92 return new JavascriptVmEmbedder() { |
|
93 public JavascriptVm getJavascriptVm() { |
|
94 return browserTab; |
|
95 } |
|
96 |
|
97 public String getTargetName() { |
|
98 return Messages.DebugTargetImpl_TargetName; |
|
99 } |
|
100 |
|
101 public String getThreadName() { |
|
102 return browserTab.getUrl(); |
|
103 } |
|
104 }; |
|
105 } |
|
106 } |
|
107 |
|
108 public static JavascriptVmEmbedder.ConnectionToRemote connectToStandalone(int port, |
|
109 NamedConnectionLoggerFactory connectionLoggerFactory) { |
|
110 SocketAddress address = new InetSocketAddress(LOCALHOST, port); |
|
111 ConnectionLogger connectionLogger = |
|
112 connectionLoggerFactory.createLogger(address.toString()); |
|
113 final StandaloneVm standaloneVm = BrowserFactory.getInstance().createStandalone(address, |
|
114 connectionLogger); |
|
115 |
|
116 return new JavascriptVmEmbedder.ConnectionToRemote() { |
|
117 public JavascriptVmEmbedder.VmConnector selectVm() { |
|
118 return new JavascriptVmEmbedder.VmConnector() { |
|
119 public JavascriptVmEmbedder attach(JavascriptVmEmbedder.Listener embedderListener, |
|
120 DebugEventListener debugEventListener) |
|
121 throws CoreException { |
|
122 embedderListener = null; |
|
123 try { |
|
124 standaloneVm.attach(debugEventListener); |
|
125 } catch (IOException e) { |
|
126 throw newCoreException("Failed to connect to V8 VM", e); |
|
127 } catch (UnsupportedVersionException e) { |
|
128 throw newCoreException("Failed to connect to V8 VM", e); |
|
129 } |
|
130 return new JavascriptVmEmbedder() { |
|
131 public JavascriptVm getJavascriptVm() { |
|
132 return standaloneVm; |
|
133 } |
|
134 public String getTargetName() { |
|
135 String embedderName = standaloneVm.getEmbedderName(); |
|
136 String vmVersion = standaloneVm.getVmVersion(); |
|
137 String disconnectReason = standaloneVm.getDisconnectReason(); |
|
138 String targetTitle; |
|
139 if (embedderName == null) { |
|
140 targetTitle = ""; //$NON-NLS-1$ |
|
141 } else { |
|
142 targetTitle = MessageFormat.format( |
|
143 Messages.JavascriptVmEmbedderFactory_TargetName0, embedderName, vmVersion); |
|
144 } |
|
145 boolean isAttached = standaloneVm.isAttached(); |
|
146 if (!isAttached) { |
|
147 String disconnectMessage; |
|
148 if (disconnectReason == null) { |
|
149 disconnectMessage = Messages.JavascriptVmEmbedderFactory_Terminated; |
|
150 } else { |
|
151 disconnectMessage = MessageFormat.format( |
|
152 Messages.JavascriptVmEmbedderFactory_TerminatedWithReason, |
|
153 disconnectReason); |
|
154 } |
|
155 targetTitle = "<" + disconnectMessage + "> " + targetTitle; |
|
156 } |
|
157 return targetTitle; |
|
158 } |
|
159 public String getThreadName() { |
|
160 return ""; //$NON-NLS-1$ |
|
161 } |
|
162 }; |
|
163 } |
|
164 }; |
|
165 } |
|
166 |
|
167 public void disposeConnection() { |
|
168 // Nothing to do. We do not take connection for ConnectionToRemote. |
|
169 } |
|
170 }; |
|
171 } |
|
172 |
|
173 private static CoreException newCoreException(String message, Throwable cause) { |
|
174 return new CoreException( |
|
175 new Status(Status.ERROR, ChromiumDebugPlugin.PLUGIN_ID, message, cause)); |
|
176 } |
|
177 private static CoreException newCoreException(Exception e) { |
|
178 return new CoreException( |
|
179 new Status(Status.ERROR, ChromiumDebugPlugin.PLUGIN_ID, |
|
180 "Failed to connect to the remote browser", e)); |
|
181 } |
|
182 |
|
183 private static final BrowserCache browserCache = new BrowserCache(); |
|
184 /** |
|
185 * Cache of browser instances. |
|
186 */ |
|
187 private static class BrowserCache { |
|
188 |
|
189 /** |
|
190 * Tries to return already created instance of Browser connected to {@code address} |
|
191 * or create new instance. |
|
192 * However, it creates a new instance each time that {@code ConnectionLogger} is not null |
|
193 * (because you cannot add connection logger to existing connection). |
|
194 * @throws CoreException if browser can't be created because of conflict with connectionLogger |
|
195 */ |
|
196 synchronized Browser getOrCreateBrowser(final SocketAddress address, |
|
197 final NamedConnectionLoggerFactory connectionLoggerFactory) throws CoreException { |
|
198 Browser result = address2Browser.get(address); |
|
199 if (result == null) { |
|
200 |
|
201 ConnectionLogger.Factory wrappedFactory = new ConnectionLogger.Factory() { |
|
202 public ConnectionLogger newConnectionLogger() { |
|
203 return connectionLoggerFactory.createLogger(address.toString()); |
|
204 } |
|
205 }; |
|
206 result = createBrowserImpl(address, wrappedFactory); |
|
207 |
|
208 address2Browser.put(address, result); |
|
209 } |
|
210 return result; |
|
211 } |
|
212 private Browser createBrowserImpl(SocketAddress address, |
|
213 ConnectionLogger.Factory connectionLoggerFactory) { |
|
214 return BrowserFactory.getInstance().create(address, connectionLoggerFactory); |
|
215 } |
|
216 |
|
217 private final Map<SocketAddress, Browser> address2Browser = |
|
218 new HashMap<SocketAddress, Browser>(); |
|
219 } |
|
220 } |