blob: 03e4629264abed73f7cd94fe5677006d8ee73b8f [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.selenium2.server;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.BindException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.PreferenceChangeEvent;
import java.util.prefs.PreferenceChangeListener;
import java.util.prefs.Preferences;
import javax.swing.SwingUtilities;
import org.openide.util.Exceptions;
import org.openide.util.NbPreferences;
import org.openide.util.RequestProcessor;
import org.openide.util.Task;
import org.openide.util.Utilities;
/**
*
* @author Theofanis Oikonomou
*/
public class Selenium2ServerSupport implements Runnable {
private static final Logger LOGGER = Logger.getLogger(Selenium2ServerSupport.class.getName());
private static final Selenium2ServerSupport INSTANCE = new Selenium2ServerSupport();
private static Object server = null;
private static boolean isRunning = false;
private static boolean isStarting = false;
private static Action action = null;
private static Task latestTask = null;
public static final int PORT_DEFAULT = 4444;
public static final String PORT = "port"; //NOI18N
public static final String USER_EXTENSION_FILE = "user.extension.file"; //NOI18N
public static final String SELENIUM_SERVER_JAR = "selenium.server.jar"; //NOI18N
public static final boolean SINGLE_WINDOW_DEFAULT = false;
public static final String SINGLE_WINDOW = "single.window"; //NOI18N
public static final String FIREFOX_PROFILE_TEMPLATE_DIR = "firefox.profile.template.dir"; //NOI18N
private Selenium2ServerSupport() {
getPrefs().addPreferenceChangeListener(new PreferenceChangeListener() {
@Override
public void preferenceChange(PreferenceChangeEvent evt) {
if (isRunning()) {
action = Action.RELOAD;
RequestProcessor.getDefault().post(INSTANCE);
} else try {
initializeServer();
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, "Cannot re-initialize Selenium server after change of its configuration.", ex); //NOI18N
}
}
});
}
public static Selenium2ServerSupport getInstance() {
return INSTANCE;
}
public Task startServer() {
if (isRunning()) {
return Task.EMPTY;
}
if (!Selenium2Customizer.isConfiguredProperly()) {
if (!configureServer()) {
return Task.EMPTY;
}
}
action = Action.START;
return postTask();
}
public Task stopServer() {
if (!isRunning()) {
return Task.EMPTY;
}
action = Action.STOP;
return postTask();
}
public Task restartServer() {
if (!isRunning()) {
return startServer();
} else {
action = Action.RESTART;
return postTask();
}
}
public boolean configureServer() {
final boolean[] res = new boolean[1];
Runnable r = new Runnable() {
@Override
public void run() {
boolean b = Selenium2Customizer.showCustomizer();
Selenium2ServicesNode.getInstance().refresh();
res[0] = b;
}
};
try {
if (SwingUtilities.isEventDispatchThread()) {
r.run();
} else {
// it should be safe to call invokeAndWait here
// as this action will be either called from AWT thread or from
// RequestProcessor as a result of "start server" in
// case when configuration is missing the first time:
SwingUtilities.invokeAndWait(r);
}
} catch (InterruptedException ex) {
Exceptions.printStackTrace(ex);
} catch (InvocationTargetException ex) {
Exceptions.printStackTrace(ex);
}
return res[0];
}
public boolean isRunning() {
return isRunning;
}
public boolean isStarting() {
return isStarting;
}
private static Task postTask(){
Task t = RequestProcessor.getDefault().post(INSTANCE);
latestTask = t;
return t;
}
@Override
public void run() {
try {
isStarting = true;
Selenium2ServicesNode.getInstance().refresh();
if (server == null) {
initializeServer();
}
switch (action) {
case START:
callSeleniumServerMethod("boot");
callSeleniumServerMethod("start");
break;
case STOP:
callSeleniumServerMethod("stop");
break;
case RESTART:
callSeleniumServerMethod("stop");
callSeleniumServerMethod("boot");
callSeleniumServerMethod("start");
break;
case RELOAD:
callSeleniumServerMethod("stop");
server = null;
initializeServer();
callSeleniumServerMethod("boot");
callSeleniumServerMethod("start");
break;
default:
assert false : "Invalid option";
}
isStarting = false;
Selenium2ServicesNode.getInstance().refresh();
if (action == null) {
return;
}
isRunning = (!action.equals(Action.STOP));
action = null;
} catch (BindException bi) {
LOGGER.log(Level.INFO, "Port already in use - the server is probably already running.", bi); //NOI18N
} catch (Exception exc) {
LOGGER.log(Level.INFO, null, exc);
}
}
protected static URLClassLoader getSeleniumServerClassLoader() {
URL url = null;
try {
url = Utilities.toURI(new File(getPrefs().get(SELENIUM_SERVER_JAR, null))).toURL();
} catch (MalformedURLException ex) {
LOGGER.log(Level.SEVERE, null, ex);
}
return URLClassLoader.newInstance(new URL[] {url});
}
private void callSeleniumServerMethod(String method) {
ClassLoader original = Thread.currentThread().getContextClassLoader();
try {
ClassLoader curr = server.getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(curr);
server.getClass().getMethod(method).invoke(server);
} catch (IllegalAccessException ex) {
LOGGER.log(Level.WARNING, null, ex);
} catch (IllegalArgumentException ex) {
LOGGER.log(Level.WARNING, null, ex);
} catch (NoSuchMethodException ex) {
LOGGER.log(Level.WARNING, null, ex);
} catch (SecurityException ex) {
LOGGER.log(Level.WARNING, null, ex);
} catch (InvocationTargetException ex) {
LOGGER.log(Level.WARNING, null, ex);
} finally {
Thread.currentThread().setContextClassLoader(original);
}
}
private static void initializeServer() throws Exception {
URLClassLoader urlClassLoader = getSeleniumServerClassLoader();
Class seleniumServer = urlClassLoader.loadClass("org.openqa.selenium.server.SeleniumServer"); //NOI18N
Class remoteControlConfiguration = urlClassLoader.loadClass(
"org.openqa.selenium.server.RemoteControlConfiguration"); //NOI18N
Object remoteControlConfigurationInstance = remoteControlConfiguration.newInstance();
int port = getPrefs().getInt(PORT, PORT_DEFAULT);
remoteControlConfiguration.getMethod("setPort", int.class).invoke(
remoteControlConfigurationInstance, port); //NOI18N
boolean runInSingleWindow = getPrefs().getBoolean(SINGLE_WINDOW, SINGLE_WINDOW_DEFAULT);
remoteControlConfiguration.getMethod("setSingleWindow", Boolean.TYPE).invoke( //NOI18N
remoteControlConfigurationInstance, runInSingleWindow);
String firefoxProfileDir = getPrefs().get(FIREFOX_PROFILE_TEMPLATE_DIR, ""); //NOI18N
if (!firefoxProfileDir.isEmpty()) {
File ffProfileDir = new File(firefoxProfileDir);
if (ffProfileDir.exists()) {
remoteControlConfiguration.getMethod("setFirefoxProfileTemplate", File.class).invoke( //NOI18N
remoteControlConfigurationInstance, ffProfileDir);
}
}
String userExtensionsString = getPrefs().get(USER_EXTENSION_FILE, ""); //NOI18N
if (!userExtensionsString.isEmpty()) {
File userExtensionFile = new File(userExtensionsString);
if (userExtensionFile.exists()) {
remoteControlConfiguration.getMethod("setUserExtensions", File.class).invoke( //NOI18N
remoteControlConfigurationInstance, userExtensionFile);
}
}
server = seleniumServer.getConstructor(remoteControlConfiguration).
newInstance(remoteControlConfigurationInstance);
}
public static Preferences getPrefs() {
return NbPreferences.forModule(Selenium2Customizer.class);
}
private static enum Action {
START, STOP, RESTART, RELOAD
}
static void waitAllTasksFinished(){
if (latestTask == null){
return;
}
while (!latestTask.isFinished()){
latestTask.waitFinished();
}
}
}