com.gargoylesoftware.htmlunit.javascript.host.ActiveXObject Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of htmlunit Show documentation
Show all versions of htmlunit Show documentation
A headless browser intended for use in testing web-based applications.
/*
* Copyright (c) 2002-2016 Gargoyle Software 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 com.gargoylesoftware.htmlunit.javascript.host;
import static com.gargoylesoftware.htmlunit.javascript.configuration.BrowserName.IE;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebWindow;
import com.gargoylesoftware.htmlunit.activex.javascript.msxml.MSXMLActiveXObjectFactory;
import com.gargoylesoftware.htmlunit.javascript.SimpleScriptable;
import com.gargoylesoftware.htmlunit.javascript.configuration.JsxClass;
import com.gargoylesoftware.htmlunit.javascript.configuration.JsxConstructor;
import com.gargoylesoftware.htmlunit.javascript.configuration.JsxGetter;
import com.gargoylesoftware.htmlunit.javascript.configuration.JsxSetter;
import com.gargoylesoftware.htmlunit.javascript.configuration.WebBrowser;
import net.sourceforge.htmlunit.corejs.javascript.Context;
import net.sourceforge.htmlunit.corejs.javascript.Function;
import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
/**
* This is the host object that allows JavaScript to instantiate Java objects via the ActiveXObject
* constructor. This host object enables a person to emulate ActiveXObjects in JavaScript with Java
* objects. See the WebClient
class to see how ActiveXObject string parameter specifies
* which Java class is instantiated.
*
* @see com.gargoylesoftware.htmlunit.WebClient
* @author Ben Curren
* @author Ahmed Ashour
* @author Chuck Dumont
* @author Ronald Brill
* @author Frank Danek
*/
@JsxClass(browsers = @WebBrowser(IE))
public class ActiveXObject extends SimpleScriptable {
private static final Log LOG = LogFactory.getLog(ActiveXObject.class);
/**
* The default constructor.
*/
public ActiveXObject() {
}
/**
* This method
*
* - instantiates the MSXML (ActiveX) object if requested (
XMLDOMDocument
,
* XMLHTTPRequest
, XSLTemplate
)
* - searches the map specified in the
WebClient
class for the Java object to instantiate based
* on the ActiveXObject constructor String
* - uses
ActiveXObjectImpl
to initiate Jacob.
*
*
* @param cx the current context
* @param args the arguments to the ActiveXObject constructor
* @param ctorObj the function object
* @param inNewExpr Is new or not
* @return the java object to allow JavaScript to access
*/
@JsxConstructor
public static Scriptable jsConstructor(
final Context cx, final Object[] args, final Function ctorObj,
final boolean inNewExpr) {
if (args.length < 1 || args.length > 2) {
throw Context.reportRuntimeError(
"ActiveXObject Error: constructor must have one or two String parameters.");
}
if (args[0] == Context.getUndefinedValue()) {
throw Context.reportRuntimeError("ActiveXObject Error: constructor parameter is undefined.");
}
if (!(args[0] instanceof String)) {
throw Context.reportRuntimeError("ActiveXObject Error: constructor parameter must be a String.");
}
final String activeXName = (String) args[0];
final WebWindow window = getWindow(ctorObj).getWebWindow();
final MSXMLActiveXObjectFactory factory = window.getWebClient().getMSXMLActiveXObjectFactory();
if (factory.supports(activeXName)) {
final Scriptable scriptable = factory.create(activeXName, window);
if (scriptable != null) {
return scriptable;
}
}
final WebClient webClient = getWindow(ctorObj).getWebWindow().getWebClient();
final Map map = webClient.getActiveXObjectMap();
if (map != null) {
final String xClassString = map.get(activeXName);
if (xClassString != null) {
try {
final Class xClass = Class.forName(xClassString);
final Object object = xClass.newInstance();
return Context.toObject(object, ctorObj);
}
catch (final Exception e) {
throw Context.reportRuntimeError("ActiveXObject Error: failed instantiating class " + xClassString
+ " because " + e.getMessage() + ".");
}
}
}
if (webClient.getOptions().isActiveXNative() && System.getProperty("os.name").contains("Windows")) {
try {
return new ActiveXObjectImpl(activeXName);
}
catch (final Exception e) {
LOG.warn("Error initiating Jacob", e);
}
}
LOG.warn("Automation server can't create object for '" + activeXName + "'.");
throw Context.reportRuntimeError("Automation server can't create object for '" + activeXName + "'.");
}
/**
* Adds a specific property to this object.
* @param scriptable the scriptable
* @param propertyName the property name
* @param isGetter is getter
* @param isSetter is setter
*/
public static void addProperty(final SimpleScriptable scriptable, final String propertyName,
final boolean isGetter, final boolean isSetter) {
final String initialUpper = Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
String getterName = null;
if (isGetter) {
getterName = "get" + initialUpper;
}
String setterName = null;
if (isSetter) {
setterName = "set" + initialUpper;
}
addProperty(scriptable, propertyName, getterName, setterName);
}
static void addProperty(final SimpleScriptable scriptable, final String propertyName,
final String getterMethodName, final String setterMethodName) {
scriptable.defineProperty(propertyName, null,
getMethod(scriptable.getClass(), getterMethodName, JsxGetter.class),
getMethod(scriptable.getClass(), setterMethodName, JsxSetter.class), PERMANENT);
}
/**
* Gets the first method found of the class with the given name
* and the correct annotation
* @param clazz the class to search on
* @param name the name of the searched method
* @param annotationClass the class of the annotation required
* @return {@code null} if not found
*/
static Method getMethod(final Class clazz,
final String name, final Class annotationClass) {
if (name == null) {
return null;
}
Method foundMethod = null;
int foundByNameOnlyCount = 0;
for (final Method method : clazz.getMethods()) {
if (method.getName().equals(name)) {
if (null != method.getAnnotation(annotationClass)) {
return method;
}
foundByNameOnlyCount++;
foundMethod = method;
}
}
if (foundByNameOnlyCount > 1) {
throw new IllegalArgumentException("Found " + foundByNameOnlyCount + " methods for name '"
+ name + "' in class '" + clazz + "'.");
}
return foundMethod;
}
}