-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
SimonStewart: Adding the ability to augment a remote webdriver instan…
…ce at run time. This is considered experimental. git-svn-id: http://selenium.googlecode.com/svn/trunk@8657 07704840-8298-11de-bf8c-fd130f914ac9
- Loading branch information
simon.m.stewart
committed
Apr 8, 2010
1 parent
9022a6b
commit 093c045
Showing
15 changed files
with
653 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
remote/client/src/java/org/openqa/selenium/remote/AddTakesScreenshot.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* | ||
Copyright 2007-2010 WebDriver committers | ||
Copyright 2007-2010 Google Inc. | ||
Licensed 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.openqa.selenium.remote; | ||
|
||
import java.lang.reflect.Method; | ||
|
||
import org.openqa.selenium.OutputType; | ||
import org.openqa.selenium.TakesScreenshot; | ||
|
||
// Deliberately package level visibility | ||
class AddTakesScreenshot implements AugmenterProvider { | ||
|
||
public Class<?> getDescribedInterface() { | ||
return TakesScreenshot.class; | ||
} | ||
|
||
public InterfaceImplementation getImplementation(Object ignored) { | ||
// The only method on TakesScreenshot is the one to take a screenshot | ||
return new InterfaceImplementation() { | ||
public Object invoke(ExecuteMethod executeMethod, Method method, Object... args) { | ||
String base64 = (String) executeMethod.execute(DriverCommand.SCREENSHOT, null); | ||
return ((OutputType<?>) args[0]).convertFromBase64Png(base64); | ||
} | ||
}; | ||
} | ||
} |
179 changes: 179 additions & 0 deletions
179
remote/client/src/java/org/openqa/selenium/remote/Augmenter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
/* | ||
Copyright 2007-2010 WebDriver committers | ||
Copyright 2007-2010 Google Inc. | ||
Licensed 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.openqa.selenium.remote; | ||
|
||
import java.lang.reflect.InvocationHandler; | ||
import java.lang.reflect.InvocationTargetException; | ||
import java.lang.reflect.Method; | ||
import java.lang.reflect.Proxy; | ||
import java.util.HashMap; | ||
import java.util.HashSet; | ||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
import org.openqa.selenium.WebDriver; | ||
|
||
/** | ||
* Enhance the interfaces implemented by an instance of the | ||
* {@link org.openqa.selenium.remote.RemoteWebDriver} based on the returned | ||
* {@link org.openqa.selenium.remote.Capabilities} of the driver. | ||
* | ||
* Note: this class is still experimental. Use at your own risk. | ||
*/ | ||
public class Augmenter { | ||
private final Map<String, AugmenterProvider> augmentors = | ||
new HashMap<String, AugmenterProvider>(); | ||
|
||
public Augmenter() { | ||
addAugmentation(CapabilityType.TAKES_SCREENSHOT, new AddTakesScreenshot()); | ||
} | ||
|
||
/** | ||
* Add a mapping between a capability name and the implementation of the | ||
* interface that name represents. For example | ||
* (@link CapabilityType#TAKES_SCREENSHOT} is represents the interface | ||
* {@link org.openqa.selenium.TakesScreenshot}, which is implemented via the | ||
* {@link org.openqa.selenium.remote.AddTakesScreenshot} provider. | ||
* | ||
* Note: This method is still experimental. Use at your own risk. | ||
* | ||
* @param capabilityName The name of the capability to model | ||
* @param handlerClass The provider of the interface and implementation | ||
*/ | ||
public void addAugmentation(String capabilityName, AugmenterProvider handlerClass) { | ||
augmentors.put(capabilityName, handlerClass); | ||
} | ||
|
||
/** | ||
* Enhance the interfaces implemented by this instance of WebDriver iff that | ||
* instance is a {@link org.openqa.selenium.remote.RemoteWebDriver}. | ||
* | ||
* The WebDriver that is returned may well be a dynamic proxy. You cannot | ||
* rely on the concrete implementing class to remain constant. | ||
* | ||
* @param driver The driver to enhance | ||
* @return A class implementing the described interfaces. | ||
*/ | ||
public WebDriver augment(WebDriver driver) { | ||
// TODO(simon): We should really add a "SelfDescribing" interface for this | ||
if (!(driver instanceof RemoteWebDriver)) { | ||
return driver; | ||
} | ||
|
||
Map<String,Object> capabilities = ((RemoteWebDriver) driver).getCapabilities().asMap(); | ||
|
||
CompoundHandler handler = new CompoundHandler((RemoteWebDriver) driver); | ||
|
||
for (Map.Entry<String, Object> capablityName : capabilities.entrySet()) { | ||
AugmenterProvider augmenter = augmentors.get(capablityName.getKey()); | ||
if (augmenter == null) { | ||
continue; | ||
} | ||
|
||
Object value = capablityName.getValue(); | ||
if (value instanceof Boolean && !((Boolean) value).booleanValue()) { | ||
continue; | ||
} | ||
|
||
handler.addCapabilityHander(augmenter.getDescribedInterface(), | ||
augmenter.getImplementation(value)); | ||
} | ||
|
||
if (handler.isNeedingApplication()) { | ||
// Gather the existing interfaces | ||
Set<Class<?>> interfaces = new HashSet<Class<?>>(); | ||
interfaces.addAll(handler.getInterfaces()); | ||
interfaces.addAll(getInterfacesFrom(driver.getClass())); | ||
|
||
return (WebDriver) Proxy.newProxyInstance(getClass().getClassLoader(), | ||
interfaces.toArray(new Class<?>[interfaces.size()]), handler); | ||
} | ||
|
||
return driver; | ||
} | ||
|
||
private Set<Class<?>> getInterfacesFrom(Class<?> clazz) { | ||
Set<Class<?>> toReturn = new HashSet<Class<?>>(); | ||
|
||
if (clazz == null || Object.class.equals(clazz)) { | ||
return toReturn; | ||
} | ||
|
||
Class<?>[] interfaces = clazz.getInterfaces(); | ||
for (Class<?> face : interfaces) { | ||
toReturn.add(face); | ||
toReturn.addAll(getInterfacesFrom(face)); | ||
} | ||
toReturn.addAll(getInterfacesFrom(clazz.getSuperclass())); | ||
|
||
return toReturn; | ||
} | ||
|
||
private class CompoundHandler implements InvocationHandler { | ||
private Map<Method, InterfaceImplementation> handlers = | ||
new HashMap<Method, InterfaceImplementation>(); | ||
private Set<Class<?>> interfaces = new HashSet<Class<?>>(); | ||
private final RemoteWebDriver driver; | ||
|
||
private CompoundHandler(RemoteWebDriver driver) { | ||
this.driver = driver; | ||
} | ||
|
||
public void addCapabilityHander(Class<?> fromInterface, InterfaceImplementation handledBy) { | ||
interfaces.add(fromInterface); | ||
for (Method method : fromInterface.getDeclaredMethods()) { | ||
handlers.put(method, handledBy); | ||
} | ||
} | ||
|
||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | ||
InterfaceImplementation handler = handlers.get(method); | ||
|
||
try { | ||
if (handler == null) { | ||
return method.invoke(driver, args); | ||
} else { | ||
return handler.invoke(new ExecuteMethod(driver), method, args); | ||
} | ||
} catch (InvocationTargetException e) { | ||
throw unwrapException(e); | ||
} | ||
} | ||
|
||
private Throwable unwrapException(Throwable e) { | ||
Throwable cause = e.getCause(); | ||
if (cause == null) { | ||
return e; | ||
} | ||
|
||
if (cause.getClass().getName().startsWith("java.lang.reflect")) { | ||
return unwrapException(cause); | ||
} | ||
|
||
return cause; | ||
} | ||
|
||
public Set<Class<?>> getInterfaces() { | ||
return interfaces; | ||
} | ||
|
||
public boolean isNeedingApplication() { | ||
return interfaces.size() > 0; | ||
} | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
remote/client/src/java/org/openqa/selenium/remote/AugmenterProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
Copyright 2007-2010 WebDriver committers | ||
Copyright 2007-2010 Google Inc. | ||
Licensed 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.openqa.selenium.remote; | ||
|
||
/** | ||
* Describes and provides an implementation for a particular interface for use | ||
* with the {@link org.openqa.selenium.remote.Augmenter}. Think of this as a | ||
* simulacrum of mixins. | ||
*/ | ||
public interface AugmenterProvider { | ||
/** | ||
* @return The interface that this augmentor describes. | ||
*/ | ||
Class<?> getDescribedInterface(); | ||
|
||
/** | ||
* For the interface that this provider describes, return an implementation. | ||
* | ||
* @param value The value from the capability map | ||
* @return An interface implementation | ||
*/ | ||
InterfaceImplementation getImplementation(Object value); | ||
} |
52 changes: 52 additions & 0 deletions
52
remote/client/src/java/org/openqa/selenium/remote/ExecuteMethod.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
Copyright 2007-2010 WebDriver committers | ||
Copyright 2007-2010 Google Inc. | ||
Licensed 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.openqa.selenium.remote; | ||
|
||
import java.util.Map; | ||
|
||
/** | ||
* An encapsulation of | ||
* {@link org.openqa.selenium.remote.RemoteWebDriver#executeScript(String, Object...)}. | ||
*/ | ||
public class ExecuteMethod { | ||
private final RemoteWebDriver driver; | ||
|
||
public ExecuteMethod(RemoteWebDriver driver) { | ||
this.driver = driver; | ||
} | ||
|
||
/** | ||
* Execute the given command on the remote webdriver server. Any exceptions | ||
* will be thrown by the underlying execute method. | ||
* | ||
* @param commandName The remote command to execute | ||
* @param parameters The parameters to execute that command with | ||
* @return The result of {@link Response#getValue()}. | ||
*/ | ||
public Object execute(DriverCommand commandName, Map<String, Object> parameters) { | ||
Response response; | ||
|
||
if (parameters == null || parameters.size() == 0) { | ||
response = driver.execute(commandName); | ||
} else { | ||
response = driver.execute(commandName, parameters); | ||
} | ||
|
||
return response.getValue(); | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
remote/client/src/java/org/openqa/selenium/remote/InterfaceImplementation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
Copyright 2007-2010 WebDriver committers | ||
Copyright 2007-2010 Google Inc. | ||
Licensed 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.openqa.selenium.remote; | ||
|
||
import java.lang.reflect.Method; | ||
|
||
/** | ||
* An implementation of a particular interface, used by the | ||
* {@link org.openqa.selenium.remote.Augmenter}. | ||
*/ | ||
public interface InterfaceImplementation { | ||
/** | ||
* Called when it has become apparent that this is the right interface to | ||
* implement a particular method. | ||
* | ||
* @param executeMethod Call this to actually call the remote instance | ||
* @param method The method invoked by the user | ||
* @param args The arguments to the method | ||
* @return The return value, which will be passed to the user directly. | ||
*/ | ||
Object invoke(ExecuteMethod executeMethod, Method method, Object... args); | ||
} |
Oops, something went wrong.