View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.geronimo.mavenplugins.selenium;
21  
22  import java.io.File;
23  import java.io.PrintWriter;
24  import java.io.BufferedWriter;
25  import java.io.FileWriter;
26  
27  import java.net.URL;
28  import java.net.MalformedURLException;
29  import java.util.Map;
30  
31  import org.apache.maven.project.MavenProject;
32  import org.apache.maven.artifact.Artifact;
33  import org.apache.maven.plugin.MojoFailureException;
34  import org.apache.maven.plugin.MojoExecutionException;
35  
36  import org.apache.geronimo.genesis.AntMojoSupport;
37  import org.apache.geronimo.genesis.ObjectHolder;
38  
39  import org.apache.commons.io.IOUtils;
40  
41  import org.apache.tools.ant.taskdefs.Java;
42  import org.apache.tools.ant.types.Environment;
43  import org.apache.tools.ant.types.Path;
44  
45  import org.codehaus.plexus.util.FileUtils;
46  
47  /**
48   * Start the Selenium server.
49   *
50   * @goal start-server
51   *
52   * @version $Rev: 451403 $ $Date: 2006-09-29 12:48:14 -0700 (Fri, 29 Sep 2006) $
53   */
54  public class StartServerMojo
55      extends AntMojoSupport
56  {
57      /**
58       * The port number the server will use.
59       *
60       * @parameter expression="${port}" default-value="4444"
61       */
62      private int port = -1;
63  
64      /**
65       * Timeout for the server in seconds.
66       *
67       * @parameter expression="${timeout}" default-value="-1"
68       */
69      private int timeout = -1;
70  
71      /**
72       * Enable the server's debug mode..
73       *
74       * @parameter expression="${debug}" default-value="false"
75       */
76      private boolean debug = false;
77  
78      /**
79       * The file or resource to use for default user-extentions.js.
80       *
81       * @parameter default-value="org/apache/geronimo/mavenplugins/selenium/default-user-extentions.js"
82       */
83      private String defaultUserExtensions = null;
84  
85      /**
86       * Enable or disable default user-extentions.js
87       *
88       * @parameter default-value="true"
89       */
90      private boolean defaultUserExtensionsEnabled = true;
91  
92      /**
93       * Location of the user-extentions.js to load into the server.
94       * If defaultUserExtensionsEnabled is true, then this file will be appended to the defaults.
95       *
96       * @parameter
97       */
98      private String userExtensions = null;
99  
100     /**
101      * Map of of plugin artifacts.
102      *
103      * @parameter expression="${plugin.artifactMap}"
104      * @required
105      * @readonly
106      */
107     private Map pluginArtifactMap = null;
108 
109     /**
110      * Working directory where Selenium server will be started from.
111      *
112      * @parameter expression="${project.build.directory}/selenium"
113      * @required
114      */
115     private File workingDirectory = null;
116     
117     /**
118      * Enable logging mode.
119      *
120      * @parameter expression="${logOutput}" default-value="false"
121      */
122     protected boolean logOutput = false;
123     
124     /**
125      * The file that Selenium server logs will be written to.
126      *
127      * @parameter expression="${logFile}" default-value="${project.build.directory}/selenium/server.log"
128      * @required
129      */
130     private File logFile = null;
131 
132     /**
133      * Flag to control if we background the server or block Maven execution.
134      *
135      * @parameter default-value="false"
136      * @required
137      */
138     private boolean background = false;
139 
140     //
141     // MojoSupport Hooks
142     //
143 
144     /**
145      * The maven project.
146      *
147      * @parameter expression="${project}"
148      * @required
149      * @readonly
150      */
151     private MavenProject project = null;
152 
153     protected MavenProject getProject() {
154         return project;
155     }
156 
157     //
158     // Mojo
159     //
160 
161     private File getPluginArchive() {
162         String path = getClass().getProtectionDomain().getCodeSource().getLocation().getFile();
163         return new File(path);
164     }
165 
166     private Artifact getPluginArtifact(final String name) throws MojoExecutionException {
167         Artifact artifact = (Artifact)pluginArtifactMap.get(name);
168         if (artifact == null) {
169             throw new MojoExecutionException("Unable to locate '" + name + "' in the list of plugin artifacts");
170         }
171 
172         return artifact;
173     }
174 
175     protected void doExecute() throws Exception {
176         log.info("Starting Selenium server...");
177 
178         final Java java = (Java)createTask("java");
179         
180         FileUtils.forceMkdir(workingDirectory);
181         
182         java.setFork(true);
183         java.setDir(workingDirectory);
184         java.setFailonerror(true);
185         
186         if (logOutput) {
187             FileUtils.forceMkdir(logFile.getParentFile());
188 
189             log.info("Redirecting output to: " + logFile);
190             
191             java.setLogError(true);
192             java.setOutput(logFile);
193         }
194         
195         java.setClassname("org.openqa.selenium.server.SeleniumServer");
196 
197         Path classpath = java.createClasspath();
198         classpath.createPathElement().setLocation(getPluginArchive());
199         classpath.createPathElement().setLocation(getPluginArtifact("log4j:log4j").getFile());
200         classpath.createPathElement().setLocation(getPluginArtifact("org.openqa.selenium.server:selenium-server").getFile());
201 
202         Environment.Variable var;
203 
204         var = new Environment.Variable();
205         var.setKey("selenium.log");
206         var.setFile(logFile);
207         java.addSysproperty(var);
208 
209         var = new Environment.Variable();
210         var.setKey("selenium.loglevel");
211         var.setValue(debug == true ? "DEBUG" : "INFO");
212         java.addSysproperty(var);
213 
214         var = new Environment.Variable();
215         var.setKey("log4j.configuration");
216         var.setValue("org/apache/geronimo/mavenplugins/selenium/log4j.properties");
217         java.addSysproperty(var);
218 
219         // Server arguments
220 
221         java.createArg().setValue("-port");
222         java.createArg().setValue(String.valueOf(port));
223 
224         if (debug) {
225             java.createArg().setValue("-debug");
226         }
227 
228         if (timeout > 0) {
229             log.info("Timeout after: " + timeout + " seconds");
230 
231             java.createArg().setValue("-timeout");
232             java.createArg().setValue(String.valueOf(timeout));
233         }
234 
235         File userExtentionsFile = getUserExtentionsFile();
236         if (userExtentionsFile != null) {
237             log.info("User extensions: " + userExtentionsFile);
238 
239             java.createArg().setValue("-userExtensions");
240             java.createArg().setFile(userExtentionsFile);
241         }
242 
243         // Holds any exception that was thrown during startup
244         final ObjectHolder errorHolder = new ObjectHolder();
245 
246         // Start the server int a seperate thread
247         Thread t = new Thread("Selenium Server Runner") {
248             public void run() {
249                 try {
250                     java.execute();
251                 }
252                 catch (Exception e) {
253                     errorHolder.set(e);
254 
255                     //
256                     // NOTE: Don't log here, as when the JVM exists an exception will get thrown by Ant
257                     //       but that should be fine.
258                     //
259                 }
260             }
261         };
262         t.start();
263 
264         log.debug("Waiting for Selenium server...");
265 
266         // Verify server started
267         URL url = new URL("http://localhost:" + port + "/selenium-server");
268         boolean started = false;
269         while (!started) {
270             if (errorHolder.isSet()) {
271                 throw new MojoExecutionException("Failed to start Selenium server", (Throwable)errorHolder.get());
272             }
273 
274             log.debug("Trying connection to: " + url);
275 
276             try {
277                 Object input = url.openConnection().getContent();
278                 started = true;
279             }
280             catch (Exception e) {
281                 // ignore
282             }
283 
284             Thread.sleep(1000);
285         }
286 
287         log.info("Selenium server started");
288 
289         if (!background) {
290             log.info("Waiting for Selenium to shutdown...");
291 
292             t.join();
293         }
294     }
295 
296     /**
297      * Resolve a resource to a file, URL or resource.
298      */
299     private URL resolveResource(final String name) throws MalformedURLException, MojoFailureException {
300         assert name != null;
301 
302         URL url;
303 
304         File file = new File(name);
305         if (file.exists()) {
306             url = file.toURL();
307         }
308         else {
309             try {
310                 url = new URL(name);
311             }
312             catch (MalformedURLException e) {
313                 url = Thread.currentThread().getContextClassLoader().getResource(name);
314             }
315         }
316 
317         if (url == null) {
318             throw new MojoFailureException("Could not resolve resource: " + name);
319         }
320 
321         log.debug("Resolved resource '" + name + "' as: " + url);
322 
323         return url;
324     }
325 
326     /**
327      * Retutn the user-extentions.js file to use, or null if it should not be installed.
328      */
329     private File getUserExtentionsFile() throws Exception {
330         if (!defaultUserExtensionsEnabled && userExtensions == null) {
331             return null;
332         }
333 
334         // File needs to be named 'user-extensions.js' or Selenium server will puke
335         File file = new File(workingDirectory, "user-extensions.js");
336         if (file.exists()) {
337             log.debug("Reusing previously generated file: " + file);
338 
339             return file;
340         }
341 
342         PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(file)));
343 
344         if (defaultUserExtensionsEnabled) {
345             URL url = resolveResource(defaultUserExtensions);
346             log.debug("Using defaults: " + url);
347 
348             writer.println("//");
349             writer.println("// Default user extentions; from: " + url);
350             writer.println("//");
351 
352             IOUtils.copy(url.openStream(), writer);
353         }
354 
355         if (userExtensions != null) {
356             URL url = resolveResource(userExtensions);
357             log.debug("Using user extentions: " + url);
358 
359             writer.println("//");
360             writer.println("// User extentions; from: " + url);
361             writer.println("//");
362 
363             IOUtils.copy(url.openStream(), writer);
364         }
365 
366         writer.flush();
367         writer.close();
368 
369         return file;
370     }
371 }