blob: d69d69c6cbb8d96a6a3bebcf71252f94b68d3903 [file] [log] [blame]
/*
* 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.TerminationCallback {
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 (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);
viewerServiceClient.initialize(clientId, cachedStartupUrls);
viewerServiceClient.checkCapabilities();
}
public void onTermination(Exception e) {
getTopLogger().log(TreeLogger.INFO,
"Remote UI connection terminated due to exception: " + e);
getTopLogger().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);
}
}