1 /* 2 * Copyright the original author or authors. 3 * 4 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (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 * 8 * http://www.mozilla.org/MPL/MPL-1.1.html 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import org.as2lib.core.BasicClass; 18 import org.as2lib.env.reflect.PackageInfo; 19 import org.as2lib.env.reflect.ClassInfo; 20 import org.as2lib.env.reflect.Cache; 21 import org.as2lib.env.reflect.ReflectConfig; 22 23 /** 24 * {@code PackageMemberAlgorithm} searches for members, that means types and packages, 25 * of a specific package. Sub-packages are not searched through. 26 * 27 * <p>This class is mostly used internally. If you wanna obtain the members of a 28 * package you need its representing {@code PackageInfo}. You can then also use the 29 * {@link PackageInfo#getMembers}, {@link PackageInfo#getMemberClasses} and 30 * {@link PackageInfo#getMemberPackages} methods directly and do not have to make 31 * the detour over this method. The PackageInfo's methods are also easier to use and 32 * offer some extra functionalities. 33 * 34 * <p>If you nevertheless want to use this class here is how it works. 35 * 36 * <code> 37 * var packageInfo:PackageInfo = PackageInfo.forPackage(org.as2lib.core); 38 * var packageMemberAlgorithm:PackageMemberAlgorithm = new PackageMemberAlgorithm(); 39 * var members:Array = packageMemberAlgorithm.execute(packageInfo); 40 * </code> 41 * 42 * <p>Refer to the {@link #execute} method for details on how to get data from the 43 * members array appropriately. 44 * 45 * @author Simon Wacker 46 */ 47 class org.as2lib.env.reflect.algorithm.PackageMemberAlgorithm extends BasicClass { 48 49 /** The cache. */ 50 private var c:Cache; 51 52 /** 53 * Constructs a new {@code PackageMemberAlgorithm} instance. 54 */ 55 public function PackageMemberAlgorithm(Void) { 56 } 57 58 /** 59 * Sets the cache that is used by the {@link #execute} method to look whether the 60 * member package or class is already stored and to get the root package to start the 61 * search if not. 62 * 63 * @param cache the new cache 64 */ 65 public function setCache(cache:Cache):Void { 66 c = cache; 67 } 68 69 /** 70 * Returns the cache set via the {@link #setCache} method or the default cache that 71 * is returned by the {@link ReflectConfig#getCache} method. 72 * 73 * @return the currently used cache 74 */ 75 public function getCache(Void):Cache { 76 if (!c) c = ReflectConfig.getCache(); 77 return c; 78 } 79 80 /** 81 * Executes the search for the members, that means member types and packages, in 82 * the passed-in package {@code p}. 83 * 84 * <p>The resulting array contains instances of type {@link PackageMemberInfo}, that 85 * is either of type {@link ClassInfo} or {@link PackageInfo}. 86 * 87 * <p>The specific members can be either referenced by index or by name. 88 * <dl> 89 * <dt>Reference member by index; can be class or package.</dt> 90 * <dd><code>myMembers[0];</code></dd> 91 * <dt>Reference class by index.</dt> 92 * <dd><code>myMembers.classes[0];</code></dd> 93 * <dt>Reference package by index.</dt> 94 * <dd><code>myMembers.packages[0];</code></dd> 95 * <dt>Reference member by index; can be class or package.</dt> 96 * <dd><code>myMembers.MyClass;</code> or <code>myMembers.mypackage</code></dd> 97 * <dt>Reference class by name; use only the name of the class, excluding the namespace.</dt> 98 * <dd><code>myMembers.classes.MyClass;</code></dd> 99 * <dt>Reference package by name; use only the package name, excluding the namespace.</dt> 100 * <dd><code>myMembers.packages.mypackage;</code></dd> 101 * </dl> 102 * 103 * <p>{@code null} will be returned if: 104 * <ul> 105 * <li>The passed-in package {@code p} is {@code null} or {@code undefined}.</li> 106 * <li>The {@code getPackage} method of the passed-in package returns {@code null}.</li> 107 * </ul> 108 * 109 * <p>Only the passed-in package {@code p} will be searched through, no sub-packages. 110 * 111 * <p>In case the cache already contains a specific member class or package the 112 * contained info it will be added to the resulting members array. 113 * 114 * @param g the package info instance representing the package to search through 115 * @return the members of the package, an empty array or {@code null} 116 */ 117 public function execute(p:PackageInfo):Array { 118 if (p == null) return null; 119 var t:Object = p.getPackage(); 120 if (!t) return null; 121 // must set access permissions because by default all package members in _global are hidden 122 _global.ASSetPropFlags(t, null, 0, true); 123 _global.ASSetPropFlags(t, ["__proto__", "constructor", "__constructor__", "prototype"], 1, true); 124 getCache(); 125 var r:Array = new Array(); 126 var n:Array = new Array(); 127 r["classes"] = n; 128 var m:Array = new Array(); 129 r["packages"] = m; 130 var i:String; 131 for (i in t) { 132 // The last two checks are made to exclude methods from _global like "ASnative". 133 // The last two checks must be made with strict eval because there are types with prototypes whose "valueOf" 134 // method returns "null" or "undefined", for example "Date", "Boolean" and "Number". But if you do a strict 135 // eval check between these prototypes and "null" or "undefined", "false" is be returned. 136 if (typeof(t[i]) == "function" && t[i].prototype !== undefined && t[i].prototype !== null) { 137 // flex stores every class in _global and in its actual package 138 // e.g. org.as2lib.core.BasicClass is stored in _global with name org_as2lib_core_BasicClass 139 // this if-clause excludes these extra stored classes 140 if (!eval("_global." + i.split("_").join(".")) || i.indexOf("_") < 0) { 141 var b:ClassInfo = c.getClassByClass(t[i]); 142 if (!b) { 143 b = c.addClass(new ClassInfo(t[i], i, p)); 144 } 145 r[r.length] = b; 146 r[i] = b; 147 n[n.length] = b; 148 n[i] = b; 149 } 150 } else if (typeof(t[i]) == "object") { 151 var a:PackageInfo = c.getPackage(t[i]); 152 if (!a) { 153 a = c.addPackage(new PackageInfo(t[i], i, p)); 154 } 155 r[r.length] = a; 156 r[i] = a; 157 m[m.length] = a; 158 m[i] = a; 159 } 160 } 161 return r; 162 } 163 164 }