View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.configuration;
16  
17  import java.lang.reflect.Member;
18  import java.lang.reflect.Method;
19  import java.util.AbstractMap;
20  import java.util.ArrayList;
21  import java.util.HashMap;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.htmlunit.corejs.javascript.ScriptableObject;
26  import org.htmlunit.corejs.javascript.Symbol;
27  import org.htmlunit.javascript.HtmlUnitScriptable;
28  
29  /**
30   * A container for all the JavaScript configuration information for one class.
31   *
32   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
33   * @author Chris Erskine
34   * @author Ahmed Ashour
35   * @author Ronald Brill
36   */
37  public final class ClassConfiguration {
38      private Map<String, PropertyInfo> propertyMap_;
39      private Map<Symbol, Method> symbolMap_;
40      private Map<Symbol, String> symbolConstantMap_;
41      private Map<String, Method> functionMap_;
42      private Map<String, PropertyInfo> staticPropertyMap_;
43      private Map<String, Method> staticFunctionMap_;
44      private List<ConstantInfo> constants_;
45      private final String extendedClassName_;
46      private final Class<? extends HtmlUnitScriptable> hostClass_;
47      private final String hostClassSimpleName_;
48  
49      /**
50       * The constructor method in the {@link #hostClass_}
51       */
52      private Map.Entry<String, Member> jsConstructor_;
53      private String jsConstructorAlias_;
54      private final Class<?>[] domClasses_;
55      private final boolean jsObject_;
56      private final String className_;
57  
58      /**
59       * Constructor.
60       *
61       * @param hostClass - the class implementing this functionality
62       * @param domClasses the DOM classes that this object supports
63       * @param jsObject boolean flag for if this object is a JavaScript object
64       * @param className the class name, can be null
65       * @param extendedClassName the extended class name
66       */
67      public ClassConfiguration(final Class<? extends HtmlUnitScriptable> hostClass, final Class<?>[] domClasses,
68              final boolean jsObject, final String className, final String extendedClassName) {
69          hostClass_ = hostClass;
70          hostClassSimpleName_ = hostClass_.getSimpleName();
71          jsObject_ = jsObject;
72          domClasses_ = domClasses;
73          if (className == null) {
74              className_ = getHostClass().getSimpleName();
75          }
76          else {
77              className_ = className;
78          }
79          extendedClassName_ = extendedClassName;
80      }
81  
82      void setJSConstructor(final String name, final Member jsConstructor) {
83          if (jsConstructor_ != null) {
84              throw new IllegalStateException("Can not have two constructors for "
85                      + jsConstructor_.getValue().getDeclaringClass().getName());
86          }
87          jsConstructor_ = new AbstractMap.SimpleImmutableEntry<>(name, jsConstructor);
88      }
89  
90      void setJSConstructorAlias(final String alias) {
91          if (jsConstructor_ == null) {
92              throw new IllegalStateException("Can not define the constructor alias '"
93                      + alias + "' for scriptable class -'"
94                      + hostClass_.getName()
95                      + "' because there is no JsxConstructor defined");
96          }
97          jsConstructorAlias_ = alias;
98      }
99  
100     /**
101      * Add the property to the configuration.
102      * @param name name of the property
103      * @param getter the getter method
104      * @param setter the setter method
105      */
106     public void addProperty(final String name, final Method getter, final Method setter) {
107         final PropertyInfo info = new PropertyInfo(getter, setter);
108         if (propertyMap_ == null) {
109             propertyMap_ = new HashMap<>();
110         }
111         propertyMap_.put(name, info);
112     }
113 
114     /**
115      * Add the static property to the configuration.
116      * @param name name of the static property
117      * @param getter the static getter method
118      * @param setter the static setter method
119      */
120     public void addStaticProperty(final String name, final Method getter, final Method setter) {
121         final PropertyInfo info = new PropertyInfo(getter, setter);
122         if (staticPropertyMap_ == null) {
123             staticPropertyMap_ = new HashMap<>();
124         }
125         staticPropertyMap_.put(name, info);
126     }
127 
128     /**
129      * Add the constant to the configuration.
130      * @param name Name of the constant
131      * @param value Value of the constant
132      */
133     public void addConstant(final String name, final Object value) {
134         if (constants_ == null) {
135             constants_ = new ArrayList<>();
136         }
137         int flag = ScriptableObject.READONLY | ScriptableObject.PERMANENT;
138         // https://code.google.com/p/chromium/issues/detail?id=500633
139         if (getClassName().endsWith("Array")) {
140             flag |= ScriptableObject.DONTENUM;
141         }
142         constants_.add(new ConstantInfo(name, value, flag));
143     }
144 
145     /**
146      * Returns the Map of entries for the defined properties.
147      * @return the map
148      */
149     public Map<String, PropertyInfo> getPropertyMap() {
150         return propertyMap_;
151     }
152 
153     /**
154      * Returns the Map of entries for the defined symbols.
155      * @return the map
156      */
157     public Map<Symbol, Method> getSymbolMap() {
158         return symbolMap_;
159     }
160 
161     /**
162      * Returns the Map of entries for the defined symbols.
163      * @return the map
164      */
165     public Map<Symbol, String> getSymbolConstantMap() {
166         return symbolConstantMap_;
167     }
168 
169     /**
170      * Returns the set of entries for the defined static properties.
171      * @return a set
172      */
173     public Map<String, PropertyInfo> getStaticPropertyMap() {
174         return staticPropertyMap_;
175     }
176 
177     /**
178      * Returns the set of entries for the defined functions.
179      * @return a set
180      */
181     public Map<String, Method> getFunctionMap() {
182         return functionMap_;
183     }
184 
185     /**
186      * Returns the set of entries for the defined static functions.
187      * @return a set
188      */
189     public Map<String, Method> getStaticFunctionMap() {
190         return staticFunctionMap_;
191     }
192 
193     /**
194      * Returns the constant list.
195      * @return a list
196      */
197     public List<ConstantInfo> getConstants() {
198         return constants_;
199     }
200 
201     /**
202      * Add the symbol to the configuration.
203      * @param symbol the symbol
204      * @param method the method
205      */
206     public void addSymbol(final Symbol symbol, final Method method) {
207         if (symbolMap_ == null) {
208             symbolMap_ = new HashMap<>();
209         }
210         symbolMap_.put(symbol, method);
211     }
212 
213     /**
214      * Add the symbol to the configuration.
215      * @param symbol the symbol
216      * @param value the method
217      */
218     public void addSymbolConstant(final Symbol symbol, final String value) {
219         if (symbolConstantMap_ == null) {
220             symbolConstantMap_ = new HashMap<>();
221         }
222         symbolConstantMap_.put(symbol, value);
223     }
224 
225     /**
226      * Add the function to the configuration.
227      * @param name the method name
228      * @param method the method
229      */
230     public void addFunction(final String name, final Method method) {
231         if (functionMap_ == null) {
232             functionMap_ = new HashMap<>();
233         }
234         functionMap_.put(name, method);
235     }
236 
237     /**
238      * Add the static function to the configuration.
239      * @param name the function name
240      * @param method the method
241      */
242     public void addStaticFunction(final String name, final Method method) {
243         if (staticFunctionMap_ == null) {
244             staticFunctionMap_ = new HashMap<>();
245         }
246         staticFunctionMap_.put(name, method);
247     }
248 
249     /**
250      * @return the extendedClass
251      */
252     public String getExtendedClassName() {
253         return extendedClassName_;
254     }
255 
256     /**
257      * Gets the class of the JavaScript host object.
258      * @return the class of the JavaScript host object
259      */
260     public Class<? extends HtmlUnitScriptable> getHostClass() {
261         return hostClass_;
262     }
263 
264     /**
265      * @return the hostClassSimpleName
266      */
267     public String getHostClassSimpleName() {
268         return hostClassSimpleName_;
269     }
270 
271     /**
272      * Gets the JavaScript constructor method in {@link #getHostClass()}.
273      * @return the JavaScript constructor method in {@link #getHostClass()}
274      */
275     public Map.Entry<String, Member> getJsConstructor() {
276         return jsConstructor_;
277     }
278 
279     /**
280      * @return the JavaScript constructor method alias
281      *         or null if there is nothing.
282      */
283     public String getJsConstructorAlias() {
284         return jsConstructorAlias_;
285     }
286 
287     /**
288      * Returns the DOM classes.
289      *
290      * @return the DOM classes
291      */
292     public Class<?>[] getDomClasses() {
293         return domClasses_;
294     }
295 
296     /**
297      * @return the jsObject
298      */
299     public boolean isJsObject() {
300         return jsObject_;
301     }
302 
303     /**
304      * Returns the class name.
305      * @return the class name
306      */
307     public String getClassName() {
308         return className_;
309     }
310 
311     /**
312      * Class used to contain the property information if the property is readable, writable and the
313      * methods that implement the get and set functions.
314      */
315     public static class PropertyInfo {
316         private final Method readMethod_;
317         private final Method writeMethod_;
318 
319         /**
320          * Constructor.
321          *
322          * @param readMethod the readMethod
323          * @param writeMethod the writeMethod
324          */
325         public PropertyInfo(final Method readMethod, final Method writeMethod) {
326             readMethod_ = readMethod;
327             writeMethod_ = writeMethod;
328         }
329 
330         /**
331          * @return the readMethod
332          */
333         public Method getReadMethod() {
334             return readMethod_;
335         }
336 
337         /**
338          * @return the writeMethod
339          */
340         public Method getWriteMethod() {
341             return writeMethod_;
342         }
343     }
344 
345     /**
346      * Class used to contain the constant information name, value and flag.
347      */
348     public static class ConstantInfo {
349         private final String name_;
350         private final Object value_;
351         private final int flag_;
352 
353         /**
354          * Constructor.
355          *
356          * @param name the name
357          * @param value the value
358          * @param flag the flag
359          */
360         public ConstantInfo(final String name, final Object value, final int flag) {
361             name_ = name;
362             value_ = value;
363             flag_ = flag;
364         }
365 
366         /**
367          * @return the name
368          */
369         public String getName() {
370             return name_;
371         }
372 
373         /**
374          * @return the value
375          */
376         public Object getValue() {
377             return value_;
378         }
379 
380         /**
381          * @return the flag
382          */
383         public int getFlag() {
384             return flag_;
385         }
386     }
387 }