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;
16  
17  import java.lang.reflect.Member;
18  import java.util.Arrays;
19  import java.util.LinkedHashSet;
20  import java.util.List;
21  import java.util.Set;
22  
23  import org.htmlunit.BrowserVersion;
24  import org.htmlunit.corejs.javascript.FunctionObject;
25  import org.htmlunit.corejs.javascript.Scriptable;
26  import org.htmlunit.corejs.javascript.ScriptableObject;
27  import org.htmlunit.javascript.configuration.ClassConfiguration;
28  import org.htmlunit.javascript.configuration.ClassConfiguration.ConstantInfo;
29  import org.htmlunit.javascript.configuration.JavaScriptConfiguration;
30  
31  /**
32   * A FunctionObject that returns IDs of this object and all its parent classes.
33   *
34   * @author Ahmed Ashour
35   * @author Ronald Brill
36   */
37  public class RecursiveFunctionObject extends FunctionObject {
38  
39      private final BrowserVersion browserVersion_;
40  
41      /**
42       * The constructor.
43       * @param name the name of the function
44       * @param methodOrConstructor a {@link Member} that defines the object
45       * @param scope the enclosing scope of function
46       * @param browserVersion the browserVersion
47       */
48      public RecursiveFunctionObject(final String name, final Member methodOrConstructor,
49              final Scriptable scope, final BrowserVersion browserVersion) {
50          super(name, methodOrConstructor, scope);
51          browserVersion_ = browserVersion;
52      }
53  
54      /**
55       * {@inheritDoc}
56       */
57      @Override
58      public boolean has(final String name, final Scriptable start) {
59          if (super.has(name, start)) {
60              return true;
61          }
62          for (Class<?> c = getMethodOrConstructor().getDeclaringClass().getSuperclass();
63                  c != null; c = c.getSuperclass()) {
64              final Object scripatble = getParentScope().get(c.getSimpleName(), this);
65              if (scripatble instanceof Scriptable && ((Scriptable) scripatble).has(name, start)) {
66                  return true;
67              }
68          }
69          return false;
70      }
71  
72      /**
73       * {@inheritDoc}
74       */
75      @Override
76      public Object[] getIds() {
77          final Set<Object> objects = new LinkedHashSet<>();
78          objects.addAll(Arrays.asList(super.getIds()));
79  
80          for (Class<?> c = getMethodOrConstructor().getDeclaringClass().getSuperclass();
81                  c != null; c = c.getSuperclass()) {
82              final Object scripatble = getParentScope().get(c.getSimpleName(), this);
83              if (scripatble instanceof Scriptable) {
84                  objects.addAll(Arrays.asList(((Scriptable) scripatble).getIds()));
85              }
86          }
87          return objects.toArray(new Object[0]);
88      }
89  
90      /**
91       * {@inheritDoc}
92       */
93      @Override
94      public Object get(final String name, final Scriptable start) {
95          Object value = super.get(name, start);
96          if (value != NOT_FOUND) {
97              return value;
98          }
99  
100         Class<?> klass = getPrototypeProperty().getClass();
101 
102         while (value == NOT_FOUND && HtmlUnitScriptable.class.isAssignableFrom(klass)) {
103             final ClassConfiguration config = JavaScriptConfiguration.getInstance(browserVersion_)
104                     .getClassConfiguration(klass.getSimpleName());
105             if (config != null) {
106                 final List<ConstantInfo> constants = config.getConstants();
107                 if (constants != null) {
108                     for (final ConstantInfo constantInfo : constants) {
109                         if (constantInfo.getName().equals(name)) {
110                             value = ScriptableObject.getProperty((Scriptable) getPrototypeProperty(), name);
111                             break;
112                         }
113                     }
114                 }
115             }
116             klass = klass.getSuperclass();
117         }
118         return value;
119     }
120 
121     /**
122      * Make this public.
123      */
124     @Override
125     public Scriptable getClassPrototype() {
126         return super.getClassPrototype();
127     }
128 }