blob: 5bbe45b946bbdc04d26e500d5b8557011fe790c5 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.netbeans.modules.cordova.platforms.api;
import java.awt.Image;
import java.net.URL;
import org.netbeans.api.debugger.Session;
import org.netbeans.api.project.Project;
import org.netbeans.modules.cordova.platforms.spi.Device;
import org.netbeans.modules.cordova.platforms.spi.MobileDebugTransport;
import org.netbeans.modules.web.browser.api.PageInspector;
import org.netbeans.modules.web.browser.spi.BrowserURLMapperImplementation;
import org.netbeans.modules.web.browser.spi.MessageDispatcher;
import org.netbeans.modules.web.common.api.ServerURLMapping;
import org.netbeans.modules.web.common.api.WebServer;
import org.netbeans.modules.web.common.api.WebUtils;
import org.netbeans.modules.web.webkit.debugging.api.WebKitDebugging;
import org.netbeans.modules.web.webkit.debugging.api.WebKitUIManager;
import org.netbeans.modules.web.webkit.debugging.spi.Factory;
import org.openide.filesystems.FileObject;
import org.openide.loaders.DataObject;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.RequestProcessor;
import org.openide.util.lookup.Lookups;
import org.netbeans.api.progress.*;
import org.netbeans.modules.web.browser.api.BrowserFamilyId;
import org.openide.util.Cancellable;
import org.openide.util.NbBundle;
/**
*
* @author Jan Becicka
*/
public final class WebKitDebuggingSupport {
private static WebKitDebuggingSupport instance;
private Session debuggerSession;
private Lookup consoleLogger;
private Lookup networkMonitor;
private WebKitDebugging webKitDebugging;
private MobileDebugTransport transport;
private MessageDispatcherImpl dispatcher;
private final RequestProcessor RP = new RequestProcessor(WebKitDebuggingSupport.class.getName(), 10);
private volatile boolean startDebuggingInProgress = true;
public static synchronized WebKitDebuggingSupport getDefault() {
if (instance == null) {
instance = new WebKitDebuggingSupport();
}
return instance;
}
@NbBundle.Messages({
"LBL_ConnectingIOSDevice=Connecting to iOS Device...",
"LBL_ConnectionIOSSimulator=Connecting to iOS Simulator...",
"LBL_ConnectionAndroidDevice=Connecting to Android Device...",
"LBL_ConnectionAndroidEmulator=Connecting to Android Emulator...",})
private static String getProgressLabel(Device dev) {
if (PlatformManager.IOS_TYPE.equals(dev.getPlatform().getType())) {
return dev.isEmulator() ? Bundle.LBL_ConnectionIOSSimulator() : Bundle.LBL_ConnectingIOSDevice();
} else {
return dev.isEmulator() ? Bundle.LBL_ConnectionAndroidEmulator() : Bundle.LBL_ConnectionAndroidDevice();
}
}
public synchronized void startDebugging(Device device, Project p, Lookup context, boolean navigateToUrl) {
if (transport != null || webKitDebugging != null) {
//stop old session
stopDebuggingNow(false);
}
ProgressHandle handle = ProgressHandleFactory.createHandle(getProgressLabel(device), new Cancellable() {
@Override
public boolean cancel() {
stopDebugging(true);
return true;
}
});
handle.start();
startDebuggingInProgress = true;
try {
transport = device.getDebugTransport();
final String url = getUrl(p, context);
transport.setBaseUrl(url);
if (url == null) {
//phonegap
String id = context.lookup(String.class);
transport.setBundleIdentifier(id);
BrowserURLMapperImplementation.BrowserURLMapper mapper = context.lookup(BrowserURLMapperImplementation.BrowserURLMapper.class);
transport.setBrowserURLMapper(mapper);
}
boolean attached = transport.attach();
if (!attached) {
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Exceptions.printStackTrace(ex);
}
if (transport == null) {
return;
}
webKitDebugging = Factory.createWebKitDebugging(transport);
if (navigateToUrl) {
webKitDebugging.getPage().navigate(url);
}
webKitDebugging.getDebugger().enable();
Lookup projectContext = Lookups.singleton(p);
debuggerSession = WebKitUIManager.getDefault().createDebuggingSession(webKitDebugging, projectContext);
consoleLogger = WebKitUIManager.getDefault().createBrowserConsoleLogger(webKitDebugging, projectContext);
networkMonitor = WebKitUIManager.getDefault().createNetworkMonitor(webKitDebugging, projectContext);
dispatcher = new MessageDispatcherImpl();
BrowserFamilyId browserFamilyId = context.lookup(BrowserFamilyId.class);
if (browserFamilyId == null) {
browserFamilyId = BrowserFamilyId.UNKNOWN;
}
PageInspector.getDefault().inspectPage(Lookups.fixed(
webKitDebugging,
p,
context.lookup(Image.class),
browserFamilyId,
dispatcher));
} finally {
startDebuggingInProgress = false;
handle.finish();
}
}
public void stopDebugging(final boolean fullCleanup) {
if (transport != null && fullCleanup) {
transport.flush();
if (webKitDebugging==null) {
transport.detach();
transport = null;
}
}
if (startDebuggingInProgress && !fullCleanup)
return;
RP.post(new Runnable() {
@Override
public void run() {
stopDebuggingNow(fullCleanup);
}
});
}
private synchronized void stopDebuggingNow(boolean fullCleanup) {
if (webKitDebugging == null || webKitDebugging == null) {
return;
}
if (debuggerSession != null) {
WebKitUIManager.getDefault().stopDebuggingSession(debuggerSession);
}
debuggerSession = null;
if (consoleLogger != null) {
WebKitUIManager.getDefault().stopBrowserConsoleLogger(consoleLogger);
}
consoleLogger = null;
if (networkMonitor != null) {
WebKitUIManager.getDefault().stopNetworkMonitor(networkMonitor);
}
networkMonitor = null;
if (webKitDebugging.getDebugger().isEnabled()) {
webKitDebugging.getDebugger().disable();
}
dispatcher.dispose();
if (fullCleanup) {
// Perform a dummy blocking call that ensures that the previous
// calls are processed before we continue and detach the transport.
webKitDebugging.getRuntime().evaluate("0"); // NOI18N
}
webKitDebugging.reset();
if (transport!=null) {
transport.detach();
transport = null;
}
webKitDebugging = null;
}
public void reload() {
RP.post(new Runnable() {
@Override
public void run() {
if (webKitDebugging != null) {
webKitDebugging.getPage().reload(true, null);
}
}
});
}
public FileObject getFile(Project p, Lookup context) {
DataObject dObject = context.lookup(DataObject.class);
FileObject fileObject = dObject==null?ClientProjectUtilities.getStartFile(p):dObject.getPrimaryFile();
return fileObject;
}
private String getUrl(Project p) {
return getUrl(p, Lookup.EMPTY);
}
public String getUrl(Project p, Lookup context) {
if (ClientProjectUtilities.isUsingEmbeddedServer(p)) {
WebServer.getWebserver().start(p, ClientProjectUtilities.getSiteRoot(p), ClientProjectUtilities.getWebContextRoot(p));
} else {
WebServer.getWebserver().stop(p);
}
if (context == null || context.lookup(BrowserURLMapperImplementation.BrowserURLMapper.class)!=null) {
return null;
}
URL url = context.lookup(URL.class);
if (url!=null) {
//TODO: hack to workaround #221791
return url.toExternalForm().replace("localhost", WebUtils.getLocalhostInetAddress().getHostAddress()); // NOI18N
}
DataObject dObject = context.lookup(DataObject.class);
FileObject fileObject = dObject == null ? ClientProjectUtilities.getStartFile(p) : dObject.getPrimaryFile();
if (fileObject == null) {
return null;
}
//TODO: hack to workaround #221791
return ServerURLMapping.toServer(p, fileObject).toExternalForm().replace("localhost", WebUtils.getLocalhostInetAddress().getHostAddress()); // NOI18N
}
static class MessageDispatcherImpl extends MessageDispatcher {
void dispose() {
dispatchMessage(PageInspector.MESSAGE_DISPATCHER_FEATURE_ID, null);
}
}
}