KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > gargoylesoftware > htmlunit > javascript > JavaScriptConfiguration


1 /*
2  * Copyright (c) 2002, 2005 Gargoyle Software Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice,
8  * this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12  * 3. The end-user documentation included with the redistribution, if any, must
13  * include the following acknowledgment:
14  *
15  * "This product includes software developed by Gargoyle Software Inc.
16  * (http://www.GargoyleSoftware.com/)."
17  *
18  * Alternately, this acknowledgment may appear in the software itself, if
19  * and wherever such third-party acknowledgments normally appear.
20  * 4. The name "Gargoyle Software" must not be used to endorse or promote
21  * products derived from this software without prior written permission.
22  * For written permission, please contact info@GargoyleSoftware.com.
23  * 5. Products derived from this software may not be called "HtmlUnit", nor may
24  * "HtmlUnit" appear in their name, without prior written permission of
25  * Gargoyle Software Inc.
26  *
27  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
28  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
29  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
30  * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
33  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
36  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  */

38 package com.gargoylesoftware.htmlunit.javascript;
39
40 import com.gargoylesoftware.htmlunit.Assert;
41 import com.gargoylesoftware.htmlunit.BrowserVersion;
42 import java.io.InputStream;
43 import java.util.HashMap;
44 import java.util.Map;
45 import javax.xml.parsers.DocumentBuilder;
46 import javax.xml.parsers.DocumentBuilderFactory;
47 import org.apache.commons.logging.Log;
48 import org.apache.commons.logging.LogFactory;
49 import org.xml.sax.InputSource;
50 import org.xml.sax.SAXParseException;
51 import org.w3c.dom.Element;
52 import org.w3c.dom.Node;
53
54 /**
55  * A container for all the javascript configuration information.
56  *
57  * @version $Revision: 1.21 $
58  * @author <a HREF="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
59  */

60 public final class JavaScriptConfiguration {
61     private static org.w3c.dom.Document XmlDocument_;
62     private static final Object INITIALIZATION_LOCK = new Object();
63
64     /** Constant indicating that this function/property is used by the specified browser version */
65     public static final int ENABLED = 1;
66
67     /** Constant indicating that this function/property is not used by the specified browser version */
68     public static final int DISABLED = 2;
69
70     /** Constant indicating that this function/property is not defined in the configuration file */
71     public static final int NOT_FOUND = 3;
72
73     private static Map ConfigurationMap_ = new HashMap(11);
74
75
76     private JavaScriptConfiguration() {
77         synchronized(INITIALIZATION_LOCK) {
78             if( XmlDocument_ == null ) {
79                 XmlDocument_ = loadConfiguration();
80             }
81         }
82
83         if( XmlDocument_ == null ) {
84             throw new IllegalStateException("Configuration was not initialized - see log for details");
85         }
86     }
87
88
89     private org.w3c.dom.Document loadConfiguration() {
90         try {
91             final InputStream inputStream = getConfigurationFileAsStream();
92             if( inputStream == null ) {
93                 getLog().error("Unable to load JavaScriptConfiguration.xml");
94                 return null;
95             }
96             final InputSource inputSource = new InputSource(inputStream);
97
98             final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
99             factory.setNamespaceAware( true );
100             factory.setValidating( false );
101
102             final DocumentBuilder documentBuilder = factory.newDocumentBuilder();
103             documentBuilder.setErrorHandler( new StrictErrorHandler() );
104
105             return documentBuilder.parse( inputSource );
106         }
107         catch( final SAXParseException parseException ) {
108             getLog().error( "line=[" + parseException.getLineNumber()
109                     + "] columnNumber=[" + parseException.getColumnNumber()
110                     + "] systemId=[" + parseException.getSystemId()
111                     + "] publicId=[" + parseException.getPublicId() + "]", parseException );
112         }
113         catch( final Exception e ) {
114             getLog().error("Error when loading JavascriptConfiguration.xml", e);
115         }
116
117         return null;
118     }
119
120
121     /**
122      * Return the instance that represents the configuration for the specified {@link BrowserVersion}.
123      * @param browserVersion The {@link BrowserVersion}
124      * @return The instance for the specified {@link BrowserVersion}
125      */

126     public static JavaScriptConfiguration getInstance( final BrowserVersion browserVersion ) {
127         JavaScriptConfiguration configuration
128             = (JavaScriptConfiguration)ConfigurationMap_.get(browserVersion);
129
130         if( configuration == null ) {
131             configuration = new JavaScriptConfiguration();
132             ConfigurationMap_.put( browserVersion, configuration );
133         }
134         return configuration;
135     }
136
137
138     private Log getLog() {
139         return LogFactory.getLog(getClass());
140     }
141
142
143     private int getState(
144             final Class hostClass,
145             final String type,
146             final String typeName,
147             final String booleanAttributeName ) {
148
149         Assert.notNull("hostClass", hostClass);
150         Assert.notNull("typeName", typeName);
151
152         Element classElement = getClassElement(getClassName(hostClass));
153         while( classElement != null ) {
154
155             final Element functionElement = getElementByTypeAndName(classElement, type, typeName);
156             if( functionElement != null ) {
157                 if( booleanAttributeName == null ) {
158                     return ENABLED;
159                 }
160                 else if( getBooleanAttribute(functionElement,booleanAttributeName ) ) {
161                     return ENABLED;
162                 }
163                 else {
164                     return DISABLED;
165                 }
166             }
167
168             final String superClassName = classElement.getAttribute("extends");
169             classElement = null;
170             if( superClassName != null && superClassName.length() != 0 ) {
171                 classElement = getClassElement(superClassName);
172             }
173         }
174
175         return NOT_FOUND;
176     }
177
178
179     /**
180      * Return the state of the specified readable property.
181      *
182      * @param hostClass The class for which this property is defined.
183      * @param name The name of the property.
184      * @return {@link #ENABLED}, {@link #DISABLED} or {@link #NOT_FOUND}
185      */

186     public int getReadablePropertyNameState( final Class hostClass, final String name ) {
187         return getState(hostClass, "property", name, "readable");
188     }
189
190
191     /**
192      * Return the state of the specified writable property.
193      *
194      * @param hostClass The class for which this property is defined.
195      * @param name The name of the property.
196      * @return {@link #ENABLED}, {@link #DISABLED} or {@link #NOT_FOUND}
197      */

198     public int getWritablePropertyNameState( final Class hostClass, final String name ) {
199         return getState(hostClass, "property", name, "writable");
200     }
201
202
203     /**
204      * Return the state of the specified function.
205      *
206      * @param hostClass The class for which this function is defined.
207      * @param name The name of the property.
208      * @return {@link #ENABLED}, {@link #DISABLED} or {@link #NOT_FOUND}
209      */

210     public int getFunctionNameState( final Class hostClass, final String name ) {
211         return getState(hostClass, "function", name, null);
212     }
213
214
215     private boolean getBooleanAttribute( final Element classElement, final String attributeName ) {
216         Assert.notNull("classElement", classElement);
217         Assert.notNull("attributeName", attributeName);
218
219         final String value = classElement.getAttribute(attributeName);
220         if( "true".equals(value) ) {
221             return true;
222         }
223         else if( "false".equals(value) ) {
224             return false;
225         }
226         else {
227             throw new IllegalStateException("Unexpected value for attribute ["
228                 +attributeName+"] on element ["+classElement+"] value=["+value+"]");
229         }
230     }
231
232
233     private InputStream getConfigurationFileAsStream() {
234         return getClass().getResourceAsStream("JavaScriptConfiguration.xml");
235     }
236
237
238     private String getClassName( final Class hostClass ) {
239         Assert.notNull("hostClass", hostClass);
240
241         final String className = hostClass.getName();
242         final int index = className.lastIndexOf(".");
243         if( index == -1 ) {
244             throw new IllegalArgumentException("hostClass does not contain a dot ["+className+"]");
245         }
246
247         return className.substring( index + 1 );
248     }
249
250
251     private Element getClassElement( final String className ) {
252         Node node = XmlDocument_.getDocumentElement().getFirstChild();
253         while( node != null ) {
254             if( node instanceof Element ) {
255                 final Element element = (Element)node;
256                 if( element.getTagName().equals("class") && className.equals(element.getAttribute("name") )) {
257                     return element;
258                 }
259             }
260             node = node.getNextSibling();
261         }
262         getLog().warn("Unexpected class ["+className+"]");
263         return null;
264     }
265
266
267     private Element getElementByTypeAndName( final Element root, final String type, final String name ) {
268         Assert.notNull("type", type);
269         Assert.notNull("name", name);
270
271         Node node = root.getFirstChild();
272         while( node != null ) {
273             if( node instanceof Element ) {
274                 final Element element = (Element)node;
275                 if( element.getTagName().equals(type) && name.equals(element.getAttribute("name") ) ) {
276                     return element;
277                 }
278             }
279             node = node.getNextSibling();
280         }
281         return null;
282     }
283 }
284
Popular Tags