1 package com.atlassian.webdriver;
2
3 import com.atlassian.browsers.BrowserConfig;
4 import com.atlassian.webdriver.browsers.AutoInstallConfiguration;
5 import com.atlassian.webdriver.utils.WebDriverUtil;
6 import com.google.common.base.Preconditions;
7 import com.google.common.base.Supplier;
8 import org.openqa.selenium.WebDriver;
9 import org.openqa.selenium.WebDriverException;
10 import org.openqa.selenium.ie.InternetExplorerDriver;
11 import org.openqa.selenium.remote.UnreachableBrowserException;
12 import org.slf4j.Logger;
13 import org.slf4j.LoggerFactory;
14
15 import java.lang.ref.WeakReference;
16 import java.util.Map;
17 import java.util.concurrent.ConcurrentHashMap;
18
19 import static com.atlassian.webdriver.utils.WebDriverUtil.getUnderlyingDriver;
20
21
22
23
24
25
26
27
28
29
30
31
32
33 public class LifecycleAwareWebDriverGrid
34 {
35 private static final Logger log = LoggerFactory.getLogger(LifecycleAwareWebDriverGrid.class);
36 private final static Map<String,AtlassianWebDriver> drivers = new ConcurrentHashMap<String, AtlassianWebDriver>();
37 private volatile static AtlassianWebDriver currentDriver;
38
39 private static final Map<String,WeakReference<Thread>> SHUTDOWN_HOOKS = new ConcurrentHashMap<String, WeakReference<Thread>>();
40
41 private LifecycleAwareWebDriverGrid() {}
42
43
44
45
46
47
48
49
50 public static AtlassianWebDriver getDriver()
51 {
52 String browserProperty = WebDriverFactory.getBrowserProperty();
53 if (browserIsConfigured(browserProperty))
54 {
55 AtlassianWebDriver driver = drivers.get(browserProperty);
56 currentDriver = driver;
57 return driver;
58 }
59
60 AtlassianWebDriver driver = null;
61 if (RemoteWebDriverFactory.matches(browserProperty))
62 {
63 log.info("Loading remote driver: " + browserProperty);
64 driver = RemoteWebDriverFactory.getDriver(browserProperty);
65 }
66 else
67 {
68 log.info("Loading local driver: " + browserProperty);
69 BrowserConfig browserConfig = AutoInstallConfiguration.setupBrowser();
70 driver = WebDriverFactory.getDriver(browserConfig);
71 }
72 drivers.put(browserProperty, driver);
73 currentDriver = driver;
74
75 addShutdownHook(browserProperty, driver);
76 return driver;
77 }
78
79 public static AtlassianWebDriver getCurrentDriver()
80 {
81 Preconditions.checkState(currentDriver != null, "The current driver has not been initialised");
82 return currentDriver;
83 }
84
85 public static Supplier<AtlassianWebDriver> currentDriverSupplier()
86 {
87 return new Supplier<AtlassianWebDriver>()
88 {
89 @Override
90 public AtlassianWebDriver get()
91 {
92 return getCurrentDriver();
93 }
94 };
95 }
96
97
98
99
100
101
102 public static void shutdown()
103 {
104 for (Map.Entry<String,AtlassianWebDriver> driver: drivers.entrySet())
105 {
106 quit(driver.getValue());
107 removeHook(driver);
108 }
109 drivers.clear();
110 SHUTDOWN_HOOKS.clear();
111 currentDriver = null;
112 }
113
114 private static void removeHook(Map.Entry<String, AtlassianWebDriver> driver)
115 {
116 WeakReference<Thread> hookRef = SHUTDOWN_HOOKS.get(driver.getKey());
117 final Thread hook = hookRef != null ? hookRef.get() : null;
118 if (hook != null)
119 {
120 Runtime.getRuntime().removeShutdownHook(hook);
121 }
122 }
123
124 private static void quit(AtlassianWebDriver webDriver)
125 {
126 try
127 {
128 webDriver.quit();
129 }
130 catch (WebDriverException e)
131 {
132 onQuitError(webDriver, e);
133 }
134 }
135
136
137 private static boolean browserIsConfigured(String browserProperty)
138 {
139 return drivers.containsKey(browserProperty);
140 }
141
142 private static void addShutdownHook(final String browserProperty, final WebDriver driver) {
143 final Thread quitter = new Thread()
144 {
145 @Override
146 public void run()
147 {
148 log.debug("Running shut down hook for {}", driver);
149 try
150 {
151 drivers.remove(browserProperty);
152 if (driver.equals(currentDriver))
153 {
154 currentDriver = null;
155 }
156 log.info("Quitting {}", getUnderlyingDriver(driver));
157 driver.quit();
158 log.debug("Finished shutdown hook {}", this);
159 }
160 catch (NullPointerException e)
161 {
162
163
164 onQuitError(driver, e);
165 }
166 catch (WebDriverException e)
167 {
168 onQuitError(driver, e);
169 }
170 }
171 };
172 SHUTDOWN_HOOKS.put(browserProperty, new WeakReference<Thread>(quitter));
173 Runtime.getRuntime().addShutdownHook(quitter);
174 }
175
176
177 private static void onQuitError(WebDriver webDriver, Exception e)
178 {
179
180
181 log.warn("Exception when trying to quit driver {}: {}", webDriver, e.getMessage());
182 log.debug("Exception when trying to quit driver - details", e);
183 }
184
185 }