| /* |
| * Copyright 2009 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.gwt.dev.shell.remoteui; |
| |
| import com.google.gwt.core.ext.TreeLogger; |
| import com.google.gwt.core.ext.TreeLogger.Type; |
| import com.google.gwt.dev.ModuleHandle; |
| import com.google.gwt.dev.ui.DevModeUI; |
| import com.google.gwt.dev.ui.DoneCallback; |
| import com.google.gwt.dev.ui.DoneEvent; |
| import com.google.gwt.dev.ui.RestartServerCallback; |
| import com.google.gwt.dev.ui.RestartServerEvent; |
| |
| import java.io.IOException; |
| import java.net.Socket; |
| import java.net.URL; |
| import java.net.UnknownHostException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * An implementation of a UI for the development mode server that sends UI |
| * events over the network to a remote viewer. Also receives commands from the |
| * remote viewer (such as a web server restart) and forwards the requests to the |
| * development mode server. |
| */ |
| public class RemoteUI extends DevModeUI implements |
| MessageTransport.ErrorCallback { |
| |
| private final String clientId; |
| private final DevModeServiceRequestProcessor devModeRequestProcessor; |
| private final List<ModuleHandle> modules = new ArrayList<ModuleHandle>(); |
| private final Object modulesLock = new Object(); |
| private final Socket transportSocket; |
| private final MessageTransport transport; |
| private ViewerServiceClient viewerServiceClient = null; |
| private final List<String> cachedStartupUrls = new ArrayList<String>(); |
| |
| public RemoteUI(String host, int port, String clientId) { |
| try { |
| this.clientId = clientId; |
| transportSocket = new Socket(host, port); |
| transportSocket.setKeepAlive(true); |
| transportSocket.setTcpNoDelay(true); |
| devModeRequestProcessor = new DevModeServiceRequestProcessor(this); |
| transport = new MessageTransport(transportSocket.getInputStream(), |
| transportSocket.getOutputStream(), devModeRequestProcessor, this); |
| transport.start(); |
| } catch (UnknownHostException e) { |
| throw new RuntimeException(e); |
| } catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| @Override |
| public ModuleHandle getModuleLogger(String userAgent, String remoteSocket, |
| String url, String tabKey, String moduleName, String sessionKey, |
| String agentTag, byte[] agentIcon, Type logLevel) { |
| |
| final int logHandle = viewerServiceClient.addModuleLog(remoteSocket, url, |
| tabKey, moduleName, sessionKey, agentTag, agentIcon); |
| final ViewerServiceTreeLogger moduleLogger = new ViewerServiceTreeLogger( |
| viewerServiceClient); |
| moduleLogger.initLogHandle(logHandle); |
| moduleLogger.setMaxDetail(getLogLevel()); |
| ModuleHandle handle = new ModuleHandle() { |
| public TreeLogger getLogger() { |
| return moduleLogger; |
| } |
| |
| public void unload() { |
| synchronized (modulesLock) { |
| if (!modules.contains(this)) { |
| return; |
| } |
| } |
| try { |
| viewerServiceClient.disconnectLog(logHandle); |
| } finally { |
| synchronized (modulesLock) { |
| modules.remove(this); |
| } |
| } |
| } |
| }; |
| synchronized (modulesLock) { |
| modules.add(handle); |
| } |
| |
| if (moduleLogger.isLoggable(TreeLogger.SPAM)) { |
| if (url != null) { |
| moduleLogger.log(TreeLogger.SPAM, "Top URL: " + url); |
| } |
| |
| moduleLogger.log(TreeLogger.SPAM, "User agent: " + userAgent); |
| moduleLogger.log(TreeLogger.SPAM, "Remote socket: " + remoteSocket); |
| if (tabKey != null) { |
| moduleLogger.log(TreeLogger.SPAM, "Tab key: " + tabKey); |
| } |
| if (sessionKey != null) { |
| moduleLogger.log(TreeLogger.SPAM, "Session key: " + sessionKey); |
| } |
| } |
| |
| return handle; |
| } |
| |
| @Override |
| public TreeLogger getWebServerLogger(String serverName, byte[] serverIcon) { |
| return getConsoleLogger(); |
| } |
| |
| @Override |
| public void moduleLoadComplete(boolean success) { |
| // Until the RemoteMessage protobuf's backwards compatibility issues are |
| // resolved, we send the startup URLs as part of the moduleLoadComplete so |
| // they are not displayed before the server is ready to serve the modules at |
| // the URLs. |
| viewerServiceClient = new ViewerServiceClient(transport, getTopLogger()); |
| viewerServiceClient.initialize(clientId, cachedStartupUrls); |
| viewerServiceClient.checkCapabilities(); |
| } |
| |
| public void onResponseException(Exception e) { |
| getTopLogger().log(TreeLogger.INFO, |
| "An exception occured while attempting to send a response message.", e); |
| } |
| |
| public void onTermination(Exception e) { |
| getConsoleLogger().log(TreeLogger.INFO, |
| "Remote UI connection terminated due to exception: " + e); |
| getConsoleLogger().log(TreeLogger.INFO, |
| "Shutting down development mode server."); |
| |
| try { |
| // Close the transport socket |
| transportSocket.close(); |
| } catch (IOException e1) { |
| // Purposely ignored |
| } |
| |
| ((DoneCallback) getCallback(DoneEvent.getType())).onDone(); |
| } |
| |
| public boolean restartWebServer() { |
| TreeLogger webServerLogger = getConsoleLogger(); |
| assert (webServerLogger != null); |
| |
| RestartServerCallback callback = ((RestartServerCallback) getCallback(RestartServerEvent.getType())); |
| if (callback != null) { |
| callback.onRestartServer(webServerLogger); |
| return true; |
| } else { |
| // The server is still starting up |
| } |
| |
| return false; |
| } |
| |
| @Override |
| public void setStartupUrls(Map<String, URL> urls) { |
| for (URL url : urls.values()) { |
| cachedStartupUrls.add(url.toExternalForm()); |
| } |
| |
| super.setStartupUrls(urls); |
| } |
| } |