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  }