com.gargoylesoftware.htmlunit.javascript.configuration.JavaScriptConfiguration.java Source code

Java tutorial

Introduction

Here is the source code for com.gargoylesoftware.htmlunit.javascript.configuration.JavaScriptConfiguration.java

Source

/*
 * Copyright (c) 2002-2012 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.configuration;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.WeakHashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.javascript.NamedNodeMap;
import com.gargoylesoftware.htmlunit.javascript.SimpleScriptable;
import com.gargoylesoftware.htmlunit.javascript.host.ActiveXObject;
import com.gargoylesoftware.htmlunit.javascript.host.Attr;
import com.gargoylesoftware.htmlunit.javascript.host.BoxObject;
import com.gargoylesoftware.htmlunit.javascript.host.CDATASection;
import com.gargoylesoftware.htmlunit.javascript.host.CharacterDataImpl;
import com.gargoylesoftware.htmlunit.javascript.host.ClientRect;
import com.gargoylesoftware.htmlunit.javascript.host.ClipboardData;
import com.gargoylesoftware.htmlunit.javascript.host.Comment;
import com.gargoylesoftware.htmlunit.javascript.host.Console;
import com.gargoylesoftware.htmlunit.javascript.host.DOMException;
import com.gargoylesoftware.htmlunit.javascript.host.DOMImplementation;
import com.gargoylesoftware.htmlunit.javascript.host.DOMParser;
import com.gargoylesoftware.htmlunit.javascript.host.DOMTokenList;
import com.gargoylesoftware.htmlunit.javascript.host.Document;
import com.gargoylesoftware.htmlunit.javascript.host.DocumentFragment;
import com.gargoylesoftware.htmlunit.javascript.host.DocumentType;
import com.gargoylesoftware.htmlunit.javascript.host.Element;
import com.gargoylesoftware.htmlunit.javascript.host.Enumerator;
import com.gargoylesoftware.htmlunit.javascript.host.Event;
import com.gargoylesoftware.htmlunit.javascript.host.EventNode;
import com.gargoylesoftware.htmlunit.javascript.host.External;
import com.gargoylesoftware.htmlunit.javascript.host.FormChild;
import com.gargoylesoftware.htmlunit.javascript.host.FormField;
import com.gargoylesoftware.htmlunit.javascript.host.HashChangeEvent;
import com.gargoylesoftware.htmlunit.javascript.host.History;
import com.gargoylesoftware.htmlunit.javascript.host.KeyboardEvent;
import com.gargoylesoftware.htmlunit.javascript.host.Location;
import com.gargoylesoftware.htmlunit.javascript.host.MediaList;
import com.gargoylesoftware.htmlunit.javascript.host.MessageEvent;
import com.gargoylesoftware.htmlunit.javascript.host.MimeType;
import com.gargoylesoftware.htmlunit.javascript.host.MimeTypeArray;
import com.gargoylesoftware.htmlunit.javascript.host.MouseEvent;
import com.gargoylesoftware.htmlunit.javascript.host.MutationEvent;
import com.gargoylesoftware.htmlunit.javascript.host.Namespace;
import com.gargoylesoftware.htmlunit.javascript.host.NamespaceCollection;
import com.gargoylesoftware.htmlunit.javascript.host.Navigator;
import com.gargoylesoftware.htmlunit.javascript.host.Node;
import com.gargoylesoftware.htmlunit.javascript.host.NodeFilter;
import com.gargoylesoftware.htmlunit.javascript.host.NodeList;
import com.gargoylesoftware.htmlunit.javascript.host.OfflineResourceList;
import com.gargoylesoftware.htmlunit.javascript.host.Plugin;
import com.gargoylesoftware.htmlunit.javascript.host.PluginArray;
import com.gargoylesoftware.htmlunit.javascript.host.Popup;
import com.gargoylesoftware.htmlunit.javascript.host.ProcessingInstruction;
import com.gargoylesoftware.htmlunit.javascript.host.Range;
import com.gargoylesoftware.htmlunit.javascript.host.RowContainer;
import com.gargoylesoftware.htmlunit.javascript.host.Screen;
import com.gargoylesoftware.htmlunit.javascript.host.Selection;
import com.gargoylesoftware.htmlunit.javascript.host.SimpleArray;
import com.gargoylesoftware.htmlunit.javascript.host.StaticNodeList;
import com.gargoylesoftware.htmlunit.javascript.host.Storage;
import com.gargoylesoftware.htmlunit.javascript.host.Text;
import com.gargoylesoftware.htmlunit.javascript.host.TextRange;
import com.gargoylesoftware.htmlunit.javascript.host.TreeWalker;
import com.gargoylesoftware.htmlunit.javascript.host.UIEvent;
import com.gargoylesoftware.htmlunit.javascript.host.WebSocket;
import com.gargoylesoftware.htmlunit.javascript.host.Window;
import com.gargoylesoftware.htmlunit.javascript.host.XPathNSResolver;
import com.gargoylesoftware.htmlunit.javascript.host.XPathResult;
import com.gargoylesoftware.htmlunit.javascript.host.XSLTProcessor;
import com.gargoylesoftware.htmlunit.javascript.host.XSLTemplate;
import com.gargoylesoftware.htmlunit.javascript.host.arrays.ArrayBuffer;
import com.gargoylesoftware.htmlunit.javascript.host.arrays.ArrayBufferView;
import com.gargoylesoftware.htmlunit.javascript.host.arrays.ArrayBufferViewBase;
import com.gargoylesoftware.htmlunit.javascript.host.arrays.DataView;
import com.gargoylesoftware.htmlunit.javascript.host.arrays.Float32Array;
import com.gargoylesoftware.htmlunit.javascript.host.arrays.Float64Array;
import com.gargoylesoftware.htmlunit.javascript.host.arrays.Int16Array;
import com.gargoylesoftware.htmlunit.javascript.host.arrays.Int32Array;
import com.gargoylesoftware.htmlunit.javascript.host.arrays.Int8Array;
import com.gargoylesoftware.htmlunit.javascript.host.arrays.Uint16Array;
import com.gargoylesoftware.htmlunit.javascript.host.arrays.Uint32Array;
import com.gargoylesoftware.htmlunit.javascript.host.arrays.Uint8Array;
import com.gargoylesoftware.htmlunit.javascript.host.arrays.Uint8ClampedArray;
import com.gargoylesoftware.htmlunit.javascript.host.canvas.CanvasRenderingContext2D;
import com.gargoylesoftware.htmlunit.javascript.host.css.CSSCharsetRule;
import com.gargoylesoftware.htmlunit.javascript.host.css.CSSFontFaceRule;
import com.gargoylesoftware.htmlunit.javascript.host.css.CSSImportRule;
import com.gargoylesoftware.htmlunit.javascript.host.css.CSSMediaRule;
import com.gargoylesoftware.htmlunit.javascript.host.css.CSSPrimitiveValue;
import com.gargoylesoftware.htmlunit.javascript.host.css.CSSRule;
import com.gargoylesoftware.htmlunit.javascript.host.css.CSSRuleList;
import com.gargoylesoftware.htmlunit.javascript.host.css.CSSStyleDeclaration;
import com.gargoylesoftware.htmlunit.javascript.host.css.CSSStyleRule;
import com.gargoylesoftware.htmlunit.javascript.host.css.CSSStyleSheet;
import com.gargoylesoftware.htmlunit.javascript.host.css.CSSValue;
import com.gargoylesoftware.htmlunit.javascript.host.css.ComputedCSSStyleDeclaration;
import com.gargoylesoftware.htmlunit.javascript.host.css.StyleSheetList;
import com.gargoylesoftware.htmlunit.javascript.host.geo.Coordinates;
import com.gargoylesoftware.htmlunit.javascript.host.geo.Geolocation;
import com.gargoylesoftware.htmlunit.javascript.host.geo.Position;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLAnchorElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLAppletElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLAreaElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLAudioElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLBRElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLBaseElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLBaseFontElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLBodyElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLButtonElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLCanvasElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLCollection;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLCollectionTags;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLDListElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLDelElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLDirectoryElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLDivElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLDocument;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLEmbedElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLFieldSetElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLFontElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLFormElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLFrameElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLFrameSetElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLHRElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLHeadElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLHeadingElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLHtmlElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLIFrameElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLImageElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLInputElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLInsElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLIsIndexElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLLIElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLLabelElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLLegendElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLLinkElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLListElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLMapElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLMediaElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLMenuElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLMetaElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLOListElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLObjectElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLOptGroupElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLOptionElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLOptionsCollection;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLParagraphElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLParamElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLPreElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLProgressElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLQuoteElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLScriptElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLSelectElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLSourceElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLSpacerElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLSpanElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLStyleElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLTableCaptionElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLTableCellElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLTableColElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLTableComponent;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLTableElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLTableRowElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLTableSectionElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLTextAreaElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLTitleElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLUListElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLUnknownElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLVideoElement;
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLWBRElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGAElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGAltGlyphElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGAnimateElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGAnimateMotionElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGAnimateTransformElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGCircleElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGClipPathElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGDefsElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGDescElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGEllipseElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEBlendElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEColorMatrixElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEComponentTransferElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFECompositeElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEConvolveMatrixElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEDiffuseLightingElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEDisplacementMapElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEDistantLightElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEFloodElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEFuncAElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEFuncBElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEFuncGElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEFuncRElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEGaussianBlurElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEImageElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEMergeElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEMergeNodeElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEMorphologyElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEOffsetElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFEPointLightElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFESpecularLightingElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFESpotLightElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFETileElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFETurbulenceElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGFilterElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGForeignObjectElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGGElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGImageElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGLineElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGLinearGradientElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGMarkerElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGMaskElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGMetadataElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGMpathElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGPathElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGPatternElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGPolygonElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGPolylineElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGRadialGradientElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGRectElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGSVGElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGScriptElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGSetElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGStopElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGStyleElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGSwitchElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGSymbolElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGTSpanElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGTextElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGTextPathElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGTitleElement;
import com.gargoylesoftware.htmlunit.javascript.host.svg.SVGUseElement;
import com.gargoylesoftware.htmlunit.javascript.host.xml.XMLAttr;
import com.gargoylesoftware.htmlunit.javascript.host.xml.XMLDOMParseError;
import com.gargoylesoftware.htmlunit.javascript.host.xml.XMLDocument;
import com.gargoylesoftware.htmlunit.javascript.host.xml.XMLHttpRequest;
import com.gargoylesoftware.htmlunit.javascript.host.xml.XMLSerializer;

/**
 * A container for all the JavaScript configuration information.
 *
 * @version $Revision: 7543 $
 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
 * @author Chris Erskine
 * @author Ahmed Ashour
 */
public final class JavaScriptConfiguration {

    private static final Log LOG = LogFactory.getLog(JavaScriptConfiguration.class);

    @SuppressWarnings("unchecked")
    static final Class<? extends SimpleScriptable>[] CLASSES_ = new Class[] { ArrayBuffer.class,
            ArrayBufferView.class, ArrayBufferViewBase.class, Attr.class, ActiveXObject.class, BoxObject.class,
            CDATASection.class, ClipboardData.class, CSSCharsetRule.class, CSSFontFaceRule.class,
            CSSImportRule.class, CSSMediaRule.class, CSSPrimitiveValue.class, CSSRule.class, CSSRuleList.class,
            CSSStyleDeclaration.class, CSSStyleRule.class, CSSStyleSheet.class, CSSValue.class,
            CanvasRenderingContext2D.class, CharacterDataImpl.class, ClientRect.class, Comment.class,
            ComputedCSSStyleDeclaration.class, Console.class, Coordinates.class, DataView.class, DOMException.class,
            DOMImplementation.class, DOMParser.class, DOMTokenList.class, Document.class, DocumentFragment.class,
            DocumentType.class, Element.class, Enumerator.class, Event.class, EventNode.class, External.class,
            Float32Array.class, Float64Array.class, FormChild.class, FormField.class, Geolocation.class,
            History.class, HTMLAnchorElement.class, HTMLAppletElement.class, HTMLAreaElement.class,
            HTMLAudioElement.class, HTMLBRElement.class, HTMLBaseElement.class, HTMLBaseFontElement.class,
            HTMLBodyElement.class, HTMLButtonElement.class, HTMLCanvasElement.class, HTMLCollection.class,
            HTMLCollectionTags.class, HTMLDListElement.class, HTMLDelElement.class, HTMLDirectoryElement.class,
            HTMLDivElement.class, HTMLDocument.class, HTMLElement.class, HTMLEmbedElement.class,
            HTMLFieldSetElement.class, HTMLFontElement.class, HTMLFormElement.class, HTMLFrameElement.class,
            HTMLFrameSetElement.class, HTMLHRElement.class, HTMLHeadElement.class, HTMLHeadingElement.class,
            HTMLHtmlElement.class, HTMLIFrameElement.class, HTMLImageElement.class, HTMLInputElement.class,
            HTMLInsElement.class, HTMLIsIndexElement.class, HTMLLIElement.class, HTMLLabelElement.class,
            HTMLLegendElement.class, HTMLLinkElement.class, HTMLListElement.class, HTMLMapElement.class,
            HTMLMediaElement.class, HTMLMenuElement.class, HTMLMetaElement.class, HTMLOListElement.class,
            HTMLObjectElement.class, HTMLOptGroupElement.class, HTMLOptionElement.class,
            HTMLOptionsCollection.class, HTMLParagraphElement.class, HTMLParamElement.class, HTMLPreElement.class,
            HTMLProgressElement.class, HTMLQuoteElement.class, HTMLScriptElement.class, HTMLSelectElement.class,
            HTMLSourceElement.class, HTMLSpacerElement.class, HTMLSpanElement.class, HTMLStyleElement.class,
            HTMLTableCaptionElement.class, HTMLTableCellElement.class, HTMLTableColElement.class,
            HTMLTableComponent.class, HTMLTableElement.class, HTMLTableRowElement.class,
            HTMLTableSectionElement.class, HTMLTextAreaElement.class, HTMLTitleElement.class,
            HTMLUListElement.class, HTMLUnknownElement.class, HTMLVideoElement.class, HTMLWBRElement.class,
            HashChangeEvent.class, History.class, Int16Array.class, Int32Array.class, Int8Array.class,
            KeyboardEvent.class, Location.class, MediaList.class, MessageEvent.class, MimeType.class,
            MimeTypeArray.class, MouseEvent.class, MutationEvent.class, NamedNodeMap.class, Namespace.class,
            NamespaceCollection.class, Navigator.class, Node.class, NodeFilter.class, NodeList.class,
            OfflineResourceList.class, Plugin.class, PluginArray.class, Popup.class, Position.class,
            ProcessingInstruction.class, Range.class, RowContainer.class, SVGAElement.class,
            SVGAltGlyphElement.class, SVGAnimateElement.class, SVGAnimateMotionElement.class,
            SVGAnimateTransformElement.class, SVGCircleElement.class, SVGClipPathElement.class,
            SVGDefsElement.class, SVGDescElement.class, SVGElement.class, SVGEllipseElement.class,
            SVGFEBlendElement.class, SVGFEColorMatrixElement.class, SVGFEComponentTransferElement.class,
            SVGFECompositeElement.class, SVGFEConvolveMatrixElement.class, SVGFEDiffuseLightingElement.class,
            SVGFEDisplacementMapElement.class, SVGFEDistantLightElement.class, SVGFEFloodElement.class,
            SVGFEFuncAElement.class, SVGFEFuncBElement.class, SVGFEFuncGElement.class, SVGFEFuncRElement.class,
            SVGFEGaussianBlurElement.class, SVGFEImageElement.class, SVGFEMergeElement.class,
            SVGFEMergeNodeElement.class, SVGFEMorphologyElement.class, SVGFEOffsetElement.class,
            SVGFEPointLightElement.class, SVGFESpecularLightingElement.class, SVGFESpotLightElement.class,
            SVGFETileElement.class, SVGFETurbulenceElement.class, SVGFilterElement.class,
            SVGForeignObjectElement.class, SVGGElement.class, SVGImageElement.class, SVGLineElement.class,
            SVGLinearGradientElement.class, SVGMarkerElement.class, SVGMaskElement.class, SVGMetadataElement.class,
            SVGMpathElement.class, SVGPathElement.class, SVGPatternElement.class, SVGPolygonElement.class,
            SVGPolylineElement.class, SVGRadialGradientElement.class, SVGRectElement.class, SVGSVGElement.class,
            SVGScriptElement.class, SVGSetElement.class, SVGStopElement.class, SVGStyleElement.class,
            SVGSwitchElement.class, SVGSymbolElement.class, SVGTSpanElement.class, SVGTextElement.class,
            SVGTextPathElement.class, SVGTitleElement.class, SVGUseElement.class, Screen.class, Selection.class,
            SimpleArray.class, StaticNodeList.class, Storage.class, StyleSheetList.class, Text.class,
            TextRange.class, TreeWalker.class, UIEvent.class, Uint16Array.class, Uint32Array.class,
            Uint8Array.class, Uint8ClampedArray.class, WebSocket.class, Window.class, XMLAttr.class,
            XMLDocument.class, XMLDOMParseError.class, XMLHttpRequest.class, XMLSerializer.class,
            XPathNSResolver.class, XPathResult.class, XSLTProcessor.class, XSLTemplate.class };

    /** Cache of browser versions and their corresponding JavaScript configurations. */
    private static final Map<BrowserVersion, JavaScriptConfiguration> ConfigurationMap_ = new WeakHashMap<BrowserVersion, JavaScriptConfiguration>();

    private static final Map<String, String> ClassnameMap_ = new HashMap<String, String>();

    private Map<Class<?>, Class<? extends SimpleScriptable>> domJavaScriptMap_;

    private final Map<String, ClassConfiguration> configuration_;

    /**
     * Constructor is only called from {@link #getInstance(BrowserVersion)} which is synchronized.
     * @param browser the browser version to use
     */
    private JavaScriptConfiguration(final BrowserVersion browser) {
        configuration_ = buildUsageMap(browser);
    }

    /**
     * Returns the instance that represents the configuration for the specified {@link BrowserVersion}.
     * This method is synchronized to allow multi-threaded access to the JavaScript configuration.
     * @param browserVersion the {@link BrowserVersion}
     * @return the instance for the specified {@link BrowserVersion}
     */
    public static synchronized JavaScriptConfiguration getInstance(final BrowserVersion browserVersion) {
        if (browserVersion == null) {
            throw new IllegalStateException("BrowserVersion must be defined");
        }
        JavaScriptConfiguration configuration = ConfigurationMap_.get(browserVersion);

        if (configuration == null) {
            configuration = new JavaScriptConfiguration(browserVersion);
            ConfigurationMap_.put(browserVersion, configuration);
        }
        return configuration;
    }

    /**
     * Returns the configuration that has all entries. No constraints are put on the returned entries.
     *
     * @return the instance containing all entries from the configuration file
     */
    static JavaScriptConfiguration getAllEntries() {
        final JavaScriptConfiguration configuration = new JavaScriptConfiguration(null);
        return configuration;
    }

    /**
     * Gets all the configurations.
     * @return the class configurations
     */
    public Iterable<ClassConfiguration> getAll() {
        return configuration_.values();
    }

    private Map<String, ClassConfiguration> buildUsageMap(final BrowserVersion browser) {
        final Map<String, ClassConfiguration> classMap = new HashMap<String, ClassConfiguration>(CLASSES_.length);

        for (final Class<? extends SimpleScriptable> klass : CLASSES_) {
            final ClassConfiguration config = processClass(klass, browser);
            if (config != null) {
                classMap.put(config.getHostClass().getSimpleName(), config);
            }
        }
        return Collections.unmodifiableMap(classMap);
    }

    private ClassConfiguration processClass(final Class<? extends SimpleScriptable> klass,
            final BrowserVersion browser) {
        if (browser != null) {
            final JsxClass jsxClass = klass.getAnnotation(JsxClass.class);
            final String expectedBrowserName;
            if (browser.isIE()) {
                expectedBrowserName = "IE";
            } else if (browser.isFirefox()) {
                expectedBrowserName = "FF";
            } else {
                expectedBrowserName = "CHROME";
            }
            final float browserVersionNumeric = browser.getBrowserVersionNumeric();
            if (jsxClass != null && isSupported(jsxClass.browsers(), expectedBrowserName, browserVersionNumeric)) {
                final String hostClassName = klass.getName();

                final Class<?>[] domClasses = jsxClass.domClasses();

                final boolean isJsObject = jsxClass.isJSObject();
                final ClassConfiguration classConfiguration = new ClassConfiguration(klass, domClasses, isJsObject);

                final String simpleClassName = hostClassName.substring(hostClassName.lastIndexOf('.') + 1);
                ClassnameMap_.put(hostClassName, simpleClassName);
                final Map<String, Method> allGetters = new HashMap<String, Method>();
                final Map<String, Method> allSetters = new HashMap<String, Method>();
                for (final Method method : classConfiguration.getHostClass().getDeclaredMethods()) {
                    for (final Annotation annotation : method.getAnnotations()) {
                        if (annotation instanceof JsxGetter) {
                            final JsxGetter jsxGetter = (JsxGetter) annotation;
                            if (isSupported(jsxGetter.value(), expectedBrowserName, browserVersionNumeric)) {
                                String property;
                                if (jsxGetter.propertyName().isEmpty()) {
                                    property = method.getName().substring(3);
                                    property = Character.toLowerCase(property.charAt(0)) + property.substring(1);
                                } else {
                                    property = jsxGetter.propertyName();
                                }
                                allGetters.put(property, method);
                            }
                        } else if (annotation instanceof JsxSetter) {
                            final JsxSetter jsxSetter = (JsxSetter) annotation;
                            if (isSupported(jsxSetter.value(), expectedBrowserName, browserVersionNumeric)) {
                                String property;
                                if (jsxSetter.propertyName().isEmpty()) {
                                    property = method.getName().substring(3);
                                    property = Character.toLowerCase(property.charAt(0)) + property.substring(1);
                                } else {
                                    property = jsxSetter.propertyName();
                                }
                                allSetters.put(property, method);
                            }
                        } else if (annotation instanceof JsxFunction) {
                            if (isSupported(((JsxFunction) annotation).value(), expectedBrowserName,
                                    browserVersionNumeric)) {
                                classConfiguration.addFunction(method);
                            }
                        } else if (annotation instanceof JsxConstructor) {
                            classConfiguration.setJSConstructor(method);
                        }
                    }
                }
                for (final Field field : classConfiguration.getHostClass().getDeclaredFields()) {
                    final JsxConstant jsxConstant = field.getAnnotation(JsxConstant.class);
                    if (jsxConstant != null
                            && isSupported(jsxConstant.value(), expectedBrowserName, browserVersionNumeric)) {
                        classConfiguration.addConstant(field.getName());
                    }
                }
                for (final Entry<String, Method> getterEntry : allGetters.entrySet()) {
                    final String property = getterEntry.getKey();
                    classConfiguration.addProperty(property, getterEntry.getValue(), allSetters.get(property));
                }
                return classConfiguration;
            }
        }
        return null;
    }

    private static boolean isSupported(final WebBrowser[] browsers, final String expectedBrowserName,
            final float expectedVersionNumeric) {
        for (final WebBrowser browser : browsers) {
            if (browser.value().name().equals(expectedBrowserName) && browser.minVersion() <= expectedVersionNumeric
                    && browser.maxVersion() >= expectedVersionNumeric) {
                return true;
            }
        }
        return false;
    }

    /**
     * Gets the class configuration for the supplied JavaScript class name.
     * @param hostClassName the js class name
     * @return the class configuration for the supplied JavaScript class name
     */
    public ClassConfiguration getClassConfiguration(final String hostClassName) {
        return configuration_.get(hostClassName);
    }

    /**
     * Returns the classname that the given class implements. If the class is
     * the input class, then the name is extracted from the type that the Input class
     * is masquerading as.
     * FIXME - Implement the Input class processing
     * @param clazz
     * @return the classname
     */
    String getClassnameForClass(final Class<?> clazz) {
        final String name = ClassnameMap_.get(clazz.getName());
        if (name == null) {
            throw new IllegalStateException(
                    "Did not find the mapping of the class to the classname for " + clazz.getName());
        }
        return name;
    }

    /**
     * Returns an immutable map containing the DOM to JavaScript mappings. Keys are
     * java classes for the various DOM classes (e.g. HtmlInput.class) and the values
     * are the JavaScript class names (e.g. "HTMLAnchorElement").
     * @return the mappings
     */
    public Map<Class<?>, Class<? extends SimpleScriptable>> getDomJavaScriptMapping() {
        if (domJavaScriptMap_ != null) {
            return domJavaScriptMap_;
        }

        final Map<Class<?>, Class<? extends SimpleScriptable>> map = new HashMap<Class<?>, Class<? extends SimpleScriptable>>();

        for (String hostClassName : configuration_.keySet()) {
            ClassConfiguration classConfig = getClassConfiguration(hostClassName);
            for (final Class<?> domClass : classConfig.getDomClasses()) {
                // preload and validate that the class exists
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Mapping " + domClass.getName() + " to " + hostClassName);
                }
                while (!classConfig.isJsObject()) {
                    hostClassName = classConfig.getExtendedClassName();
                    classConfig = getClassConfiguration(hostClassName);
                }
                map.put(domClass, classConfig.getHostClass());
            }
        }

        domJavaScriptMap_ = Collections.unmodifiableMap(map);

        return domJavaScriptMap_;
    }
}