jsedek@14783
|
1 |
/*
|
jsedek@14783
|
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
jsedek@14783
|
3 |
*
|
jsedek@14783
|
4 |
* Copyright 1997-2008 Sun Microsystems, Inc. All rights reserved.
|
jsedek@14783
|
5 |
*
|
jsedek@14783
|
6 |
* The contents of this file are subject to the terms of either the GNU
|
jsedek@14783
|
7 |
* General Public License Version 2 only ("GPL") or the Common
|
jsedek@14783
|
8 |
* Development and Distribution License("CDDL") (collectively, the
|
jsedek@14783
|
9 |
* "License"). You may not use this file except in compliance with the
|
jsedek@14783
|
10 |
* License. You can obtain a copy of the License at
|
jsedek@14783
|
11 |
* http://www.netbeans.org/cddl-gplv2.html
|
jsedek@14783
|
12 |
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
|
jsedek@14783
|
13 |
* specific language governing permissions and limitations under the
|
jsedek@14783
|
14 |
* License. When distributing the software, include this License Header
|
jsedek@14783
|
15 |
* Notice in each file and include the License file at
|
jsedek@14783
|
16 |
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
|
jsedek@14783
|
17 |
* particular file as subject to the "Classpath" exception as provided
|
jsedek@14783
|
18 |
* by Sun in the GPL Version 2 section of the License file that
|
jsedek@14783
|
19 |
* accompanied this code. If applicable, add the following below the
|
jsedek@14783
|
20 |
* License Header, with the fields enclosed by brackets [] replaced by
|
jsedek@14783
|
21 |
* your own identifying information:
|
jsedek@14783
|
22 |
* "Portions Copyrighted [year] [name of copyright owner]"
|
jsedek@14783
|
23 |
*
|
jsedek@14783
|
24 |
* Contributor(s):
|
jsedek@14783
|
25 |
*
|
jsedek@14783
|
26 |
* The Original Software is NetBeans. The Initial Developer of the Original
|
jsedek@14783
|
27 |
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
|
jsedek@14783
|
28 |
* Microsystems, Inc. All Rights Reserved.
|
jsedek@14783
|
29 |
*
|
jsedek@14783
|
30 |
* If you wish your version of this file to be governed by only the CDDL
|
jsedek@14783
|
31 |
* or only the GPL Version 2, indicate your decision by adding
|
jsedek@14783
|
32 |
* "[Contributor] elects to include this software in this distribution
|
jsedek@14783
|
33 |
* under the [CDDL or GPL Version 2] license." If you do not indicate a
|
jsedek@14783
|
34 |
* single choice of license, a recipient has the option to distribute
|
jsedek@14783
|
35 |
* your version of this file under either the CDDL, the GPL Version 2 or
|
jsedek@14783
|
36 |
* to extend the choice of license to its licensees as provided above.
|
jsedek@14783
|
37 |
* However, if you add GPL Version 2 code and therefore, elected the GPL
|
jsedek@14783
|
38 |
* Version 2 license, then the option applies only if the new code is
|
jsedek@14783
|
39 |
* made subject to such option by the copyright holder.
|
jsedek@14783
|
40 |
*/
|
jsedek@14783
|
41 |
package org.netbeans.modules.selenium.server;
|
jsedek@14783
|
42 |
|
jsedek@14783
|
43 |
import java.beans.PropertyChangeEvent;
|
jsedek@14783
|
44 |
import java.beans.PropertyChangeListener;
|
marfous@17795
|
45 |
import java.io.File;
|
marfous@17590
|
46 |
import java.lang.reflect.InvocationTargetException;
|
jsedek@14784
|
47 |
import java.net.BindException;
|
marfous@17590
|
48 |
import java.net.MalformedURLException;
|
marfous@17590
|
49 |
import java.net.URL;
|
marfous@17590
|
50 |
import java.net.URLClassLoader;
|
jsedek@14784
|
51 |
import java.util.logging.Level;
|
jsedek@14784
|
52 |
import java.util.logging.Logger;
|
jsedek@14783
|
53 |
import org.netbeans.api.server.properties.InstanceProperties;
|
marfous@17590
|
54 |
import org.openide.modules.InstalledFileLocator;
|
jsedek@14783
|
55 |
import org.openide.util.RequestProcessor;
|
jsedek@14783
|
56 |
import org.openide.util.Task;
|
jsedek@14783
|
57 |
|
jsedek@14783
|
58 |
/**
|
jsedek@14783
|
59 |
*
|
jsedek@14783
|
60 |
* @author Jindrich Sedek
|
marfous@17590
|
61 |
* @author Martin Fousek
|
jsedek@14783
|
62 |
*/
|
jsedek@14783
|
63 |
class SeleniumServerRunner implements Runnable, PropertyChangeListener {
|
jsedek@14783
|
64 |
|
marfous@17590
|
65 |
private static final Logger LOGGER = Logger.getLogger(SeleniumServerRunner.class.getName());
|
marfous@17590
|
66 |
|
jsedek@14783
|
67 |
private static final SeleniumServerRunner instance = new SeleniumServerRunner();
|
marfous@17590
|
68 |
private static Object server = null;
|
jsedek@14783
|
69 |
private boolean isRunning = false;
|
jsedek@14783
|
70 |
private static Action action = null;
|
jsedek@14783
|
71 |
private static Task latestTask = null;
|
jsedek@14783
|
72 |
|
jsedek@14783
|
73 |
private SeleniumServerRunner() {
|
jsedek@14783
|
74 |
}
|
jsedek@14783
|
75 |
|
jsedek@14783
|
76 |
static Task startServer() {
|
jsedek@14783
|
77 |
if (isRunning()) {
|
jsedek@14783
|
78 |
return Task.EMPTY;
|
jsedek@14783
|
79 |
}
|
jsedek@14783
|
80 |
action = Action.START;
|
jsedek@14783
|
81 |
return postTask();
|
jsedek@14783
|
82 |
}
|
jsedek@14783
|
83 |
|
jsedek@14783
|
84 |
static Task stopServer() {
|
jsedek@14783
|
85 |
if (!isRunning()) {
|
jsedek@14783
|
86 |
return Task.EMPTY;
|
jsedek@14783
|
87 |
}
|
jsedek@14783
|
88 |
action = Action.STOP;
|
jsedek@14783
|
89 |
return postTask();
|
jsedek@14783
|
90 |
}
|
jsedek@14783
|
91 |
|
jsedek@14783
|
92 |
static Task restartServer() {
|
jsedek@14783
|
93 |
if (!isRunning()) {
|
jsedek@14783
|
94 |
return startServer();
|
jsedek@14783
|
95 |
} else {
|
jsedek@14783
|
96 |
action = Action.RESTART;
|
jsedek@14783
|
97 |
return postTask();
|
jsedek@14783
|
98 |
}
|
jsedek@14783
|
99 |
}
|
jsedek@14783
|
100 |
|
jsedek@14783
|
101 |
static boolean isRunning() {
|
jsedek@14783
|
102 |
return instance.isRunning;
|
jsedek@14783
|
103 |
}
|
jsedek@14783
|
104 |
|
jsedek@14783
|
105 |
private static Task postTask(){
|
jsedek@14783
|
106 |
Task t = RequestProcessor.getDefault().post(instance);
|
jsedek@14783
|
107 |
latestTask = t;
|
jsedek@14783
|
108 |
return t;
|
jsedek@14783
|
109 |
}
|
jsedek@14783
|
110 |
|
marfous@17402
|
111 |
@Override
|
jsedek@14783
|
112 |
public void run() {
|
jsedek@14783
|
113 |
try {
|
jsedek@14783
|
114 |
if (server == null) {
|
jsedek@14783
|
115 |
initializeServer();
|
jsedek@14783
|
116 |
}
|
jsedek@14783
|
117 |
switch (action) {
|
jsedek@14783
|
118 |
case START:
|
marfous@17893
|
119 |
callSeleniumServerMethod("boot");
|
marfous@17590
|
120 |
callSeleniumServerMethod("start");
|
jsedek@14783
|
121 |
break;
|
jsedek@14783
|
122 |
case STOP:
|
marfous@17590
|
123 |
callSeleniumServerMethod("stop");
|
jsedek@14783
|
124 |
break;
|
jsedek@14783
|
125 |
case RESTART:
|
marfous@17590
|
126 |
callSeleniumServerMethod("stop");
|
marfous@17893
|
127 |
callSeleniumServerMethod("boot");
|
marfous@17590
|
128 |
callSeleniumServerMethod("start");
|
jsedek@14783
|
129 |
break;
|
jsedek@14783
|
130 |
case RELOAD:
|
marfous@17590
|
131 |
callSeleniumServerMethod("stop");
|
jsedek@14783
|
132 |
server = null;
|
jsedek@14783
|
133 |
initializeServer();
|
marfous@17893
|
134 |
callSeleniumServerMethod("boot");
|
marfous@17590
|
135 |
callSeleniumServerMethod("start");
|
jsedek@14783
|
136 |
break;
|
jsedek@14783
|
137 |
default:
|
jsedek@14783
|
138 |
assert false : "Invalid option";
|
jsedek@14783
|
139 |
}
|
marfous@17402
|
140 |
if (action == null) {
|
marfous@17402
|
141 |
return;
|
marfous@17402
|
142 |
}
|
jsedek@14783
|
143 |
isRunning = (!action.equals(Action.STOP));
|
jsedek@14783
|
144 |
action = null;
|
marfous@17590
|
145 |
} catch (BindException bi) {
|
marfous@17590
|
146 |
LOGGER.log(Level.INFO, "Port already in use - the server is probably already running.", bi); //NOI18N
|
jsedek@14783
|
147 |
} catch (Exception exc) {
|
marfous@17590
|
148 |
LOGGER.log(Level.INFO, null, exc);
|
jsedek@14783
|
149 |
}
|
jsedek@14783
|
150 |
}
|
jsedek@14783
|
151 |
|
marfous@17590
|
152 |
protected static URLClassLoader getSeleniumServerClassLoader() {
|
marfous@17590
|
153 |
URL url = null;
|
marfous@17590
|
154 |
try {
|
marfous@17590
|
155 |
url = InstalledFileLocator.getDefault().locate(
|
marfous@17740
|
156 |
"modules/ext/selenium/selenium-server-2.16.1.jar", //NOI18N
|
marfous@17590
|
157 |
null, //NOI18N
|
marfous@17590
|
158 |
false).toURI().toURL();
|
marfous@17590
|
159 |
} catch (MalformedURLException ex) {
|
marfous@17590
|
160 |
LOGGER.log(Level.SEVERE, null, ex);
|
marfous@17590
|
161 |
}
|
marfous@17590
|
162 |
return URLClassLoader.newInstance(new URL[] {url}); //NOI18N
|
marfous@17590
|
163 |
}
|
marfous@17590
|
164 |
|
marfous@17590
|
165 |
private void callSeleniumServerMethod(String method) {
|
marfous@17590
|
166 |
ClassLoader original = Thread.currentThread().getContextClassLoader();
|
marfous@17590
|
167 |
try {
|
marfous@17590
|
168 |
ClassLoader curr = server.getClass().getClassLoader();
|
marfous@17590
|
169 |
Thread.currentThread().setContextClassLoader(curr);
|
marfous@17590
|
170 |
server.getClass().getMethod(method).invoke(server);
|
marfous@17590
|
171 |
} catch (IllegalAccessException ex) {
|
marfous@17745
|
172 |
LOGGER.log(Level.WARNING, null, ex);
|
marfous@17590
|
173 |
} catch (IllegalArgumentException ex) {
|
marfous@17745
|
174 |
LOGGER.log(Level.WARNING, null, ex);
|
marfous@17590
|
175 |
} catch (NoSuchMethodException ex) {
|
marfous@17745
|
176 |
LOGGER.log(Level.WARNING, null, ex);
|
marfous@17590
|
177 |
} catch (SecurityException ex) {
|
marfous@17745
|
178 |
LOGGER.log(Level.WARNING, null, ex);
|
marfous@17590
|
179 |
} catch (InvocationTargetException ex) {
|
marfous@17745
|
180 |
LOGGER.log(Level.WARNING, null, ex);
|
marfous@17590
|
181 |
} finally {
|
marfous@17590
|
182 |
Thread.currentThread().setContextClassLoader(original);
|
marfous@17590
|
183 |
}
|
marfous@17590
|
184 |
}
|
marfous@17590
|
185 |
|
marfous@17590
|
186 |
private static void initializeServer() throws Exception {
|
marfous@17590
|
187 |
URLClassLoader urlClassLoader = getSeleniumServerClassLoader();
|
marfous@17590
|
188 |
Class seleniumServer = urlClassLoader.loadClass("org.openqa.selenium.server.SeleniumServer"); //NOI18N
|
marfous@17590
|
189 |
Class remoteControlConfiguration = urlClassLoader.loadClass(
|
marfous@17590
|
190 |
"org.openqa.selenium.server.RemoteControlConfiguration"); //NOI18N
|
marfous@17590
|
191 |
|
jsedek@14783
|
192 |
InstanceProperties ip = SeleniumProperties.getInstanceProperties();
|
marfous@17590
|
193 |
Object remoteControlConfigurationInstance = remoteControlConfiguration.newInstance();
|
marfous@17795
|
194 |
int port = ip.getInt(SeleniumProperties.PORT, SeleniumProperties.getSeleniumDefaultPort());
|
marfous@17590
|
195 |
remoteControlConfiguration.getMethod("setPort", int.class).invoke(
|
marfous@17795
|
196 |
remoteControlConfigurationInstance, port); //NOI18N
|
marfous@17795
|
197 |
boolean runInSingleWindow = ip.getBoolean(SeleniumProperties.SINGLE_WINDOW, false);
|
marfous@17795
|
198 |
remoteControlConfiguration.getMethod("setSingleWindow", Boolean.TYPE).invoke( //NOI18N
|
marfous@17795
|
199 |
remoteControlConfigurationInstance, runInSingleWindow);
|
marfous@17795
|
200 |
String firefoxProfileDir = ip.getString(SeleniumProperties.FIREFOX_PROFILE, ""); //NOI18N
|
marfous@17795
|
201 |
if (!firefoxProfileDir.isEmpty()) {
|
marfous@17795
|
202 |
File ffProfileDir = new File(firefoxProfileDir);
|
marfous@17795
|
203 |
if (ffProfileDir.exists()) {
|
marfous@17795
|
204 |
remoteControlConfiguration.getMethod("setFirefoxProfileTemplate", File.class).invoke( //NOI18N
|
marfous@17795
|
205 |
remoteControlConfigurationInstance, ffProfileDir);
|
marfous@17795
|
206 |
}
|
marfous@17795
|
207 |
}
|
marfous@17893
|
208 |
String userExtensionsString = ip.getString(SeleniumProperties.USER_EXTENSIONS, ""); //NOI18N
|
marfous@17893
|
209 |
if (!userExtensionsString.isEmpty()) {
|
marfous@17893
|
210 |
File userExtensionFile = new File(userExtensionsString);
|
marfous@17893
|
211 |
if (userExtensionFile.exists()) {
|
marfous@17893
|
212 |
remoteControlConfiguration.getMethod("setUserExtensions", File.class).invoke( //NOI18N
|
marfous@17893
|
213 |
remoteControlConfigurationInstance, userExtensionFile);
|
marfous@17893
|
214 |
}
|
marfous@17893
|
215 |
}
|
marfous@17893
|
216 |
|
marfous@17590
|
217 |
server = seleniumServer.getConstructor(remoteControlConfiguration).
|
marfous@17590
|
218 |
newInstance(remoteControlConfigurationInstance);
|
jsedek@14783
|
219 |
}
|
jsedek@14783
|
220 |
|
marfous@17402
|
221 |
@Override
|
jsedek@14783
|
222 |
public void propertyChange(PropertyChangeEvent evt) {
|
jsedek@14783
|
223 |
if (SeleniumProperties.PORT.equals(evt.getPropertyName())){
|
jsedek@14783
|
224 |
action = Action.RELOAD;
|
jsedek@14783
|
225 |
RequestProcessor.getDefault().post(instance);
|
jsedek@14783
|
226 |
}
|
jsedek@14783
|
227 |
}
|
jsedek@14783
|
228 |
|
jsedek@14783
|
229 |
// listen on SeleniumProperties
|
jsedek@14783
|
230 |
static PropertyChangeListener getPropertyChangeListener() {
|
jsedek@14783
|
231 |
return instance;
|
jsedek@14783
|
232 |
}
|
jsedek@14783
|
233 |
|
jsedek@14783
|
234 |
private static enum Action {
|
jsedek@14783
|
235 |
|
jsedek@14783
|
236 |
START, STOP, RESTART, RELOAD
|
jsedek@14783
|
237 |
}
|
jsedek@14783
|
238 |
|
jsedek@14783
|
239 |
static void waitAllTasksFinished(){
|
jsedek@14783
|
240 |
if (latestTask == null){
|
jsedek@14783
|
241 |
return;
|
jsedek@14783
|
242 |
}
|
jsedek@14783
|
243 |
while (!latestTask.isFinished()){
|
jsedek@14783
|
244 |
latestTask.waitFinished();
|
jsedek@14783
|
245 |
}
|
jsedek@14783
|
246 |
}
|
jsedek@14783
|
247 |
}
|