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.overload.Overload; 19 import org.as2lib.env.except.IllegalArgumentException; 20 import org.as2lib.env.reflect.ReflectConfig; 21 import org.as2lib.env.reflect.ClassInfo; 22 import org.as2lib.env.reflect.PackageMemberInfo; 23 import org.as2lib.env.reflect.PackageMemberFilter; 24 import org.as2lib.env.reflect.algorithm.PackageAlgorithm; 25 import org.as2lib.env.reflect.algorithm.PackageMemberAlgorithm; 26 import org.as2lib.util.StringUtil; 27 28 /** 29 * {@code PackageInfo} represents a real package in the Flash environment. This class 30 * is used to get specific information about the package it represents. 31 * 32 * <p>You can use the static search methods {@link #forName} and {@link #forPackage} to 33 * get package infos for specific packages. 34 * 35 * <p>If you for example have a package you wanna get information about you first must 36 * retrieve the appropriate {@code PackageInfo} instance and you can then use its 37 * methods to get the wanted information. 38 * 39 * <code> 40 * var packageInfo:PackageInfo = PackageInfo.forPackage(org.as2lib.core); 41 * trace("Package full name: " + packageInfo.getFullName()); 42 * trace("Parent package name: " + packageInfo.getParent().getName()); 43 * trace("Member classes: " + packageInfo.getMemberClasses()); 44 * trace("Member packages: " + packageInfo.getMemberPackages()); 45 * </code> 46 * 47 * @author Simon Wacker 48 */ 49 class org.as2lib.env.reflect.PackageInfo extends BasicClass implements PackageMemberInfo { 50 51 /** The algorithm to find packages. */ 52 private static var packageAlgorithm:PackageAlgorithm; 53 54 /** The algorithm to find members of packages, that are classes and packages. */ 55 private static var packageMemberAlgorithm:PackageMemberAlgorithm; 56 57 /** Stores the root package of the package hierarchy. */ 58 private static var rootPackage:PackageInfo; 59 60 /** 61 * Returns the package info corresponding to the passed-in {@code packageName}. 62 * 63 * <p>The passed-in {@code packageName} must be composed of the preceding path and 64 * the actual package name, that means it must be fully qualified. For example 65 * {@code "org.as2lib.core"}. 66 * 67 * <p>This method first checks whether the package is already contained in the 68 * cache. 69 * 70 * @param packageName the fully qualified name of the package to find 71 * @return the package info corresponding to the passed-in {@code packageName} 72 * @throws IllegalArgumentException if the passed-in {@code packageName} is {@code null}, 73 * {@code undefined} or an empty string or if the object corresponding to the passed-in 74 * {@code packageName} is not of type {@code "object"} 75 * @throws PackageNotFoundException if a package with the passed-in {@code packageName} 76 * could not be found 77 */ 78 public static function forName(packageName:String):PackageInfo { 79 return getPackageAlgorithm().executeByName(packageName); 80 } 81 82 /** 83 * Returns the package info corresponding to the passed-in {@code package}. 84 * 85 * <p>This method first checks whether the package info is already contained in the 86 * cache. 87 * 88 * @param package the package you wanna get the package info for 89 * @return the package info corresponding to the passed-in {@code package} 90 * @throws IllegalArgumentException if the passed-in {@code package} is {@code null} 91 * or {@code undefined} 92 */ 93 public static function forPackage(package):PackageInfo { 94 // _global == null results in true, as well does _global == undefined because of that === is used 95 if (package === null || package === undefined) { 96 throw new IllegalArgumentException("Argument 'package' [" + package + "] must not be 'null' nor 'undefined'.", eval("th" + "is"), arguments); 97 } 98 var packageInfo:PackageInfo = ReflectConfig.getCache().getPackage(package); 99 if (packageInfo) return packageInfo; 100 return ReflectConfig.getCache().addPackage(new PackageInfo(package)); 101 } 102 103 /** 104 * Sets the algorithm used to find packages. 105 * 106 * <p>If {@code newPackageAlgorithm} is {@code null} or {@code undefined}, 107 * {@link #getPackageAlgorithm} will return the default package algorithm. 108 * 109 * @param newPackageAlgorithm the new algorithm to find packages 110 * @see #getPackageAlgorithm 111 */ 112 public static function setPackageAlgorithm(newPackageAlgorithm:PackageAlgorithm):Void { 113 packageAlgorithm = newPackageAlgorithm; 114 } 115 116 /** 117 * Returns the algorithm used to find packages. 118 * 119 * <p>Either the algorithm set via {@link #setPackageAlgorithm} method will be 120 * returned or the default one which is an instance of class {@link PackageAlgorithm}. 121 * 122 * @return the set or the default package algorithm 123 * @see #setPackageAlgorithm 124 */ 125 public static function getPackageAlgorithm(Void):PackageAlgorithm { 126 if (!packageAlgorithm) packageAlgorithm = new PackageAlgorithm(); 127 return packageAlgorithm; 128 } 129 130 /** 131 * Sets the algorithm used to find members of packages. 132 * 133 * <p>Members of packages are classes, interfaces and packages. 134 * 135 * <p>If {@code newPackageMemberAlgorithm} is {@code null} or {@code undefined}, 136 * {@link #getPackageMemberAlgorithm} will return the default package member 137 * algorithm. 138 * 139 * @param newPackageMemberAlgorithm the new algorithm to find members of packages 140 * @see #getPackageMemberAlgorithm 141 */ 142 public static function setPackageMemberAlgorithm(newPackageMemberAlgorithm:PackageMemberAlgorithm):Void { 143 packageMemberAlgorithm = newPackageMemberAlgorithm; 144 } 145 146 /** 147 * Returns the member algorithm used to find members of packages. 148 * 149 * <p>Either the algorithm set via {@link #setPackageMemberAlgorithm} will be 150 * returned or the default one which is an instance of class {@link PackageMemberAlgorithm}. 151 * 152 * @return the set or the default member algorithm 153 * @see #setPackageMemberAlgorithm 154 */ 155 public static function getPackageMemberAlgorithm(Void):PackageMemberAlgorithm { 156 if (!packageMemberAlgorithm) packageMemberAlgorithm = new PackageMemberAlgorithm(); 157 return packageMemberAlgorithm; 158 } 159 160 /** 161 * Returns the root package of the package hierarchy. 162 * 163 * <p>If you do not set a custom root package via the {@code #setRootPackage} 164 * method, the default root package is returned that refers to {@code _global}. 165 * 166 * @return the root package of the package hierarchy. 167 * @see #setRootPackage 168 */ 169 public static function getRootPackage(Void):PackageInfo { 170 if (!rootPackage) rootPackage = new PackageInfo(_global, "_global", null); 171 return rootPackage; 172 } 173 174 /** 175 * Sets the new root package of the package hierarchy. 176 * 177 * <p>If the passed-in {@code newRootPackage} argument is {@code null} or 178 * {@code undefined} the {@code #getRootPackage} method will return the default 179 * root package. 180 * 181 * @param newRootPackage the new root package of the package hierarchy 182 * @see #getRootPackage 183 */ 184 public static function setRootPackage(newRootPackage:PackageInfo):Void { 185 rootPackage = newRootPackage; 186 } 187 188 /** The name of this package. */ 189 private var name:String; 190 191 /** The fully qualified name of this package. */ 192 private var fullName:String; 193 194 /** The actual package this instance represents. */ 195 private var package; 196 197 /** The parent of this package. */ 198 private var parent:PackageInfo; 199 200 /** The members of this package. */ 201 private var members:Array; 202 203 /** 204 * Constructs a new {@code PackageInfo} instance. 205 * 206 * <p>Note that you do not have to pass-in the concrete {@code package}. But if you 207 * do not pass it in some methods cannot do their job correctly. 208 * 209 * <p>If you do not pass-in the {@code name} or the {@code parent} they are resolved 210 * lazily when requested using the passed-in {@code package}. 211 * 212 * @param package the actual package this instance represents 213 * @param name (optional) the name of the package 214 * @param parent (optional) the parent package 215 */ 216 public function PackageInfo(package, 217 name:String, 218 parent:PackageInfo) { 219 this.package = package; 220 this.name = name; 221 this.parent = parent; 222 } 223 224 /** 225 * Returns the name of the represented package. 226 * 227 * <p>This does not include the package's path/namespace. If this package info 228 * represented for example the {@code org.as2lib.core} package the returned 229 * name would be {@code "core"}. 230 * 231 * @return the name of the represented package 232 * @see #getFullName 233 */ 234 public function getName(Void):String { 235 if (name === undefined) initNameAndParent(); 236 return name; 237 } 238 239 /** 240 * Returns the fully qualified name of the represented package. This means the name 241 * of the package plus its package path/namespace. 242 * 243 * <p>The path is not included if: 244 * <ul> 245 * <li>The {@link #getParent} method returns {@code null} or {@code undefined}.</li> 246 * <li> 247 * The {@link #getParent} method returns the root package, that means its 248 * {@link #isRoot} method returns {@code true}. 249 * </li> 250 * </ul> 251 * 252 * @return the fully qualified name of the package 253 */ 254 public function getFullName(Void):String { 255 if (fullName === undefined) { 256 if (getParent().isRoot() || isRoot()) { 257 return (fullName = getName()); 258 } 259 fullName = getParent().getFullName() + "." + getName(); 260 } 261 return fullName; 262 } 263 264 /** 265 * Returns the actual package this instance represents. 266 * 267 * @return the actual package 268 */ 269 public function getPackage(Void) { 270 return package; 271 } 272 273 /** 274 * Returns the parent of the represented package. 275 * 276 * <p>The parent is the package the represented package is contained in / a member 277 * of. The parent of the package {@code org.as2lib.core} is {@code org.as2lib}. 278 * 279 * @return the parent of the represented package 280 */ 281 public function getParent(Void):PackageInfo { 282 if (parent === undefined) initNameAndParent(); 283 return parent; 284 } 285 286 /** 287 * Initializes the name and the parent of the represented package. 288 * 289 * <p>This is done using the result of an execution of the package algorithm 290 * returned by the static {@link #getPackageAlgorithm} method. 291 */ 292 private function initNameAndParent(Void):Void { 293 var info = getPackageAlgorithm().execute(getPackage()); 294 if (name === undefined) name = info.name == null ? null : info.name; 295 if (parent === undefined) parent = info.parent == null ? null : info.parent; 296 } 297 298 /** 299 * @overload #getMembersByFlag 300 * @overload #getMembersByFilter 301 */ 302 public function getMembers():Array { 303 var o:Overload = new Overload(this); 304 o.addHandler([], getMembersByFlag); 305 o.addHandler([Boolean], getMembersByFlag); 306 o.addHandler([PackageMemberFilter], getMembersByFilter); 307 return o.forward(arguments); 308 } 309 310 /** 311 * Returns an array containing {@link PackageMemberInfo} instances representing the 312 * members of the package and maybe the ones of the sub-packages. 313 * 314 * <p>The members of the package are all types and packages contained in the 315 * represented package. 316 * 317 * <p>If {@code filterSubPackages} is {@code null} or {@code undefined} it is 318 * interpreted as {@code true}, that means sub-packages' package members will be 319 * filtered/excluded from the result by default. 320 * 321 * <p>{@code null} will be returned if 322 * <ul> 323 * <li>The {@link #getPackage} method returns {@code null} or {@code undefined}.</li> 324 * <li> 325 * The {@code execute} method of the algorithm returned by 326 * {@link #getPackageMemberAlgorithm} returns {@code null} or {@code undefined}. 327 * </li> 328 * </ul> 329 * 330 * @param filterSubPackages (optional) determines whether to filter the sub-packages' 331 * members 332 * @return an array containing the members of the represented package 333 */ 334 public function getMembersByFlag(filterSubPackages:Boolean):Array { 335 // not just "== null" because "_global == null" evaluates to "true" 336 if (getPackage() === null || getPackage() === undefined) return null; 337 if (filterSubPackages == null) filterSubPackages = true; 338 if (members === undefined) { 339 members = getPackageMemberAlgorithm().execute(this); 340 } 341 var result:Array = members.concat(); 342 if (!filterSubPackages) { 343 var subPackages:Array = members["packages"]; 344 for (var i:Number = 0; i < subPackages.length; i++) { 345 result = result.concat(PackageInfo(subPackages[i]).getMembersByFlag(filterSubPackages)); 346 } 347 } 348 return result; 349 } 350 351 /** 352 * Returns an array containing {@link PackageMemberInfo} instances representing the 353 * members of the package and sub-packages that are not filtered/excluded. 354 * 355 * <p>The members of this package are all types and packages contained in the 356 * represented package. 357 * 358 * <p>The {@link PackageMemberFilter#filter} method of the passed-in {@code packageMemberFilter} 359 * is invoked for every package member to determine whether it shall be contained 360 * in the result. 361 * 362 * <p>If the passed-in {@code packageMemberFilter} is {@code null} or {@code undefined} 363 * the result of the invocation of {@link #getMembersByFlag} with argument {@code true} 364 * will be returned. 365 * 366 * <p>{@code null} will be returned if: 367 * <ul> 368 * <li>The {@link #getPackage} method returns {@code null} or {@code undefined}.</li> 369 * <li> 370 * The {@code execute} method of the algorithm returned by 371 * {@link #getPackageMemberAlgorithm} returns {@code null} or {@code undefined}. 372 * </li> 373 * </ul> 374 * 375 * @param packageMemberFilter the filter that filters unwanted package members out 376 * @return an array containing the remaining members of the represented package 377 */ 378 public function getMembersByFilter(packageMemberFilter:PackageMemberFilter):Array { 379 // not just "== null" because "_global == null" evaluates to "true" 380 if (getPackage() === null || getPackage() === undefined) return null; 381 if (!packageMemberFilter) return getMembersByFlag(true); 382 var result:Array = getMembersByFlag(packageMemberFilter.filterSubPackages()); 383 for (var i:Number = 0; i < result.length; i++) { 384 if (packageMemberFilter.filter(PackageMemberInfo(result[i]))) { 385 result.splice(i, 1); 386 i--; 387 } 388 } 389 return result; 390 } 391 392 /** 393 * @overload #getMemberClassesByFlag 394 * @overload #getMemberClassesByFilter 395 */ 396 public function getMemberClasses():Array { 397 var o:Overload = new Overload(this); 398 o.addHandler([], getMemberClassesByFlag); 399 o.addHandler([Boolean], getMemberClassesByFlag); 400 o.addHandler([PackageMemberFilter], getMemberClassesByFilter); 401 return o.forward(arguments); 402 } 403 404 /** 405 * Returns an array containing {@link ClassInfo} instances representing the member 406 * classes of the package and maybe the ones of the sub-packages. 407 * 408 * <p>If {@code filterSubPackages} is {@code null} or {@code undefined} it is 409 * interpreted as {@code true}, this means that sub-packages' classes are filtered 410 * by default. 411 * 412 * <p>{@code null} will be returned if: 413 * <ul> 414 * <li>The {@link #getPackage} method returns {@code null} or {@code undefined}.</li> 415 * <li> 416 * The {@code execute} method of the algorithm returned by 417 * {@link #getPackageMemberAlgorithm} returns {@code null} or {@code undefined}. 418 * </li> 419 * </ul> 420 * 421 * @param filterSubPackages (optional) determines whether to filter/exclude the 422 * sub-packages' member classes 423 * @return an array containing the member classes of the represented package 424 */ 425 public function getMemberClassesByFlag(filterSubPackages:Boolean):Array { 426 // not just "== null" because "_global == null" evaluates to "true" 427 if (getPackage() === null || getPackage() === undefined) return null; 428 if (filterSubPackages == null) filterSubPackages = true; 429 if (members === undefined) { 430 members = getPackageMemberAlgorithm().execute(this); 431 } 432 var result:Array = members["classes"].concat(); 433 if (!filterSubPackages) { 434 var subPackages:Array = members["packages"]; 435 for (var i:Number = 0; i < subPackages.length; i++) { 436 result = result.concat(PackageInfo(subPackages[i]).getMemberClassesByFlag(filterSubPackages)); 437 } 438 } 439 return result; 440 } 441 442 /** 443 * Returns an array containing {@link ClassInfo} instances representing the class 444 * members of the package and sub-packages that are not filtered/excluded. 445 * 446 * <p>The {@link PackageMemberFilter#filter} method of the passed-in {@code classFilter} 447 * is invoked for every member class to determine whether it shall be contained in 448 * the result. 449 * 450 * <p>If the passed-in {@code clasFilter} is {@code null} or {@code undefined} the 451 * result of an invocation of {@link #getMemberClassesByFlag} with argument {@code true} 452 * will be returned. 453 * 454 * <p>{@code null} will be returned if: 455 * <ul> 456 * <li>The {@link #getPackage} method returns {@code null} or {@code undefined}.</li> 457 * <li> 458 * The {@code execute} method of the algorithm returned by 459 * {@link #getPackageMemberAlgorithm} returns {@code null} or {@code undefined}. 460 * </li> 461 * </ul> 462 * 463 * @param classFilter the filter that filters unwanted member classes out 464 * @return an array containing the remaining member classes of the represented 465 * package 466 */ 467 public function getMemberClassesByFilter(classFilter:PackageMemberFilter):Array { 468 // not just "== null" because "_global == null" evaluates to "true" 469 if (getPackage() === null || getPackage() === undefined) return null; 470 if (!classFilter) return getMemberClassesByFlag(true); 471 var result:Array = getMemberClassesByFlag(classFilter.filterSubPackages()); 472 for (var i:Number = 0; i < result.length; i++) { 473 if (classFilter.filter(ClassInfo(result[i]))) { 474 result.splice(i, 1); 475 i--; 476 } 477 } 478 return result; 479 } 480 481 /** 482 * @overload #getMemberPackagesByFlag 483 * @overload #getMemberPackagesByFilter 484 */ 485 public function getMemberPackages():Array { 486 var o:Overload = new Overload(this); 487 o.addHandler([], getMemberPackagesByFlag); 488 o.addHandler([Boolean], getMemberPackagesByFlag); 489 o.addHandler([PackageMemberFilter], getMemberPackagesByFilter); 490 return o.forward(arguments); 491 } 492 493 /** 494 * Returns an array containing {@link PackageInfo} instances representing the member 495 * packages of the package and maybe the ones of the sub-packages. 496 * 497 * <p>If {@code filterSubPackages} is {@code null} or {@code undefined} it is 498 * interpreted as {@code true}, this means sub-packages' packages are filtered 499 * by default. 500 * 501 * <p>{@code null} will be returned if: 502 * <ul> 503 * <li>The {@link #getPackage} method returns {@code null} or {@code undefined}.</li> 504 * <li> 505 * The {@code execute} method of the algorithm returned by 506 * {@link #getPackageMemberAlgorithm} returns {@code null} or {@code undefined}. 507 * </li> 508 * </ul> 509 * 510 * @param filterSubPackages (optional) determines whether the sub-packages' member 511 * packages shall be filtered/excluded from or included in the result 512 * @return an array containing the member packages of the represented package 513 */ 514 public function getMemberPackagesByFlag(filterSubPackages:Boolean):Array { 515 // not just "== null" because "_global == null" evaluates to "true" 516 if (getPackage() === null || getPackage() === undefined) return null; 517 if (filterSubPackages == null) filterSubPackages = true; 518 if (members === undefined) { 519 members = getPackageMemberAlgorithm().execute(this); 520 } 521 var result:Array = members["packages"].concat(); 522 if (!filterSubPackages) { 523 var subPackages:Array = members["packages"]; 524 for (var i:Number = 0; i < subPackages.length; i++) { 525 result = result.concat(PackageInfo(subPackages[i]).getMemberPackagesByFlag(filterSubPackages)); 526 } 527 } 528 return result; 529 } 530 531 /** 532 * Returns an array containing {@link PackageInfo} instances representing the 533 * package members of the package and sub-packages that are not filtered/excluded. 534 * 535 * <p>The {@link PackageMemberFilter#filter} method of the passed-in {@code packageFilter} 536 * is invoked for every member package to determine whether it shall be contained 537 * in the result. 538 * 539 * <p>If the passed-in {@code packageFilter} is {@code null} or {@code undefined} 540 * the result of the invocation of {@link #getMemberPackagesByFlag} with argument 541 * {@code true} will be returned. 542 * 543 * <p>{@code null} will be returned if: 544 * <ul> 545 * <li>The {@link #getPackage} method returns {@code null} or {@code undefined}.</li> 546 * <li> 547 * The {@code execute} method of the algorithm returned by 548 * {@link #getPackageMemberAlgorithm} returns {@code null} or {@code undefined}. 549 * </li> 550 * </ul> 551 * 552 * @param packageFilter the filter that filters unwanted member packages out 553 * @return an array containing the remaining member packages of the represented 554 * package 555 */ 556 public function getMemberPackagesByFilter(packageFilter:PackageMemberFilter):Array { 557 // not just "== null" because "_global == null" evaluates to "true" 558 if (getPackage() === null || getPackage() === undefined) return null; 559 if (!packageFilter) return getMemberPackagesByFlag(true); 560 var result:Array = getMemberPackagesByFlag(packageFilter.filterSubPackages()); 561 for (var i:Number = 0; i < result.length; i++) { 562 if (packageFilter.filter(PackageInfo(result[i]))) { 563 result.splice(i, 1); 564 i--; 565 } 566 } 567 return result; 568 } 569 570 /** 571 * @overload #getMemberByName 572 * @overload #getMemberByMember 573 */ 574 public function getMember():PackageMemberInfo { 575 var o:Overload = new Overload(this); 576 o.addHandler([String], getMemberByName); 577 o.addHandler([Object], getMemberByMember); 578 return o.forward(arguments); 579 } 580 581 /** 582 * Returns the package member info corresponding to the passed-in {@code memberName}. 583 * 584 * <p>If the package member with the passed-in {@code memberName} cannot be found 585 * directly in the represented package its sub-packages are searched through. 586 * 587 * <p>{@code null} will be returned if: 588 * <ul> 589 * <li>The {@link #getMembers} method returns {@code null} or {@code undefined}.</li> 590 * <li>The passed-in {@code memberName} is {@code null} or {@code undefined}.</li> 591 * <li>There is no member with the passed-in {@code memberName}.</li> 592 * </ul> 593 * 594 * @param memberName the name of the member to return 595 * @return the member corresponding to the passed-in {@code memberName} 596 */ 597 public function getMemberByName(memberName:String):PackageMemberInfo { 598 if (memberName == null) return null; 599 if (getMembersByFlag(true)) { 600 if (members[memberName]) return members[memberName]; 601 var subPackages:Array = members["packages"]; 602 for (var i:Number = 0; i < subPackages.length; i++) { 603 var member:PackageMemberInfo = PackageInfo(subPackages[i]).getMemberByName(memberName); 604 if (member) return member; 605 } 606 } 607 return null; 608 } 609 610 /** 611 * Returns the package member info corresponding to the passed-in 612 * {@code concreteMember}. 613 * 614 * <p>If the package member corresponding to the passed-in {@code concreteMember} 615 * cannot be found directly in the represented package its sub-packages are 616 * searched through. 617 * 618 * <p>{@code null} will be returned if: 619 * <ul> 620 * <li>The {@link #getMembers} method returns {@code null} or {@code undefined}.</li> 621 * <li>The passed-in {@code concreteMember} is {@code null} or {@code undefined}.</li> 622 * <li>The member could not be found.</li> 623 * </ul> 624 * 625 * @param concreteMember the concrete member to find 626 * @return the package member info instance corresponding to the {@code concreteMember} 627 */ 628 public function getMemberByMember(concreteMember):PackageMemberInfo { 629 if (concreteMember == null) return null; 630 if (typeof(concreteMember) == "function") { 631 return getMemberClassByClass(concreteMember); 632 } else { 633 return getMemberPackageByPackage(concreteMember); 634 } 635 } 636 637 /** 638 * @overload #getMemberClassByName 639 * @overload #getMemberClassByClass 640 */ 641 public function getMemberClass(clazz):ClassInfo { 642 var o:Overload = new Overload(this); 643 o.addHandler([String], getMemberClassByName); 644 o.addHandler([Function], getMemberClassByClass); 645 return o.forward(arguments); 646 } 647 648 /** 649 * Returns the class info corresponding to the passed-in {@code className}. 650 * 651 * <p>If the member class with the passed-in {@code className} cannot be found 652 * directly in the represented package its sub-packages are searched through. 653 * 654 * <p>{@code null} will be returned if: 655 * <ul> 656 * <li>The passed-in {@code className} is {@code null} or {@code undefined}.</li> 657 * <li>There is no class with the passed-in {@code className}.</li> 658 * </ul> 659 * 660 * @param className the name of the class 661 * @return the class info corresponding to the passed-in {@code className} 662 */ 663 public function getMemberClassByName(className:String):ClassInfo { 664 if (className == null) return null; 665 if (getMemberClassesByFlag(true)) { 666 if (members["classes"][className]) return members["classes"][className]; 667 } 668 var subPackages:Array = getMemberPackagesByFlag(true); 669 if (subPackages) { 670 for (var i:Number = 0; i < subPackages.length; i++) { 671 var clazz:ClassInfo = PackageInfo(subPackages[i]).getMemberClassByName(className); 672 if (clazz) return clazz; 673 } 674 } 675 return null; 676 } 677 678 /** 679 * Returns the class info corresponding to the passed-in {@code concreteClass}. 680 * 681 * <p>If the member class corresponding to the passed-in {@code concreteClass} 682 * cannot be found directly in the represented package its sub-packages are 683 * searched through. 684 * 685 * <p>{@code null} will be returned if: 686 * <ul> 687 * <li>The passed-in {@code concreteClass} is {@code null} or {@code undefined}.</li> 688 * <li> 689 * There is no class matching the passed-in {@code concreteClass} in this 690 * package or any sub-packages.</li> 691 * </ul> 692 * 693 * @param concreteClass the concrete class a corresponding class info shall be 694 * returned 695 * @return the class info corresponding to the passed-in {@code concreteClass} 696 */ 697 public function getMemberClassByClass(concreteClass:Function):ClassInfo { 698 if (!concreteClass) return null; 699 var classes:Array = getMemberClassesByFlag(true); 700 if (classes) { 701 for (var i:Number = 0; i < classes.length; i++) { 702 var clazz:ClassInfo = classes[i]; 703 if (clazz.getType().valueOf() == concreteClass.valueOf()) { 704 return clazz; 705 } 706 } 707 } 708 var subPackages:Array = getMemberPackagesByFlag(true); 709 if (subPackages) { 710 for (var i:Number = 0; i < subPackages.length; i++) { 711 var clazz:ClassInfo = PackageInfo(subPackages[i]).getMemberClassByClass(concreteClass); 712 if (clazz) return clazz; 713 } 714 } 715 return null; 716 } 717 718 /** 719 * @overload #getMemberPackageByName 720 * @overload #getMemberPackageByPackage 721 */ 722 public function getMemberPackage(package):PackageInfo { 723 var o:Overload = new Overload(this); 724 o.addHandler([String], getMemberPackageByName); 725 o.addHandler([Object], getMemberPackageByPackage); 726 return o.forward(arguments); 727 } 728 729 /** 730 * Returns the package info corresponding to the passed-in {@code packageName}. 731 * 732 * <p>If the member package with the passed-in {@code packageName} cannot be found 733 * directly in the represented package its sub-packages are searched through. 734 * 735 * <p>{@code null} will be returned if: 736 * <ul> 737 * <li>The passed-in {@code packageName} is {@code null} or {@code undefined}.</li> 738 * <li>The {@link #getMemberPackages} method returns {@code null}.</li> 739 * <li>There is no package with the given {@code packageName}.</li> 740 * </ul> 741 * 742 * @param packageName the name of the package 743 * @return the package info corresponding to the passed-in {@code packageName} 744 */ 745 public function getMemberPackageByName(packageName:String):PackageInfo { 746 if (packageName == null) return null; 747 if (getMemberPackagesByFlag(true)) { 748 if (members["packages"][packageName]) return members["packages"][packageName]; 749 var subPackages:Array = members["packages"]; 750 for (var i:Number = 0; i < subPackages.length; i++) { 751 var package:PackageInfo = PackageInfo(subPackages[i]).getMemberPackageByName(packageName); 752 if (package) return package; 753 } 754 } 755 return null; 756 } 757 758 /** 759 * Returns the package info corresponding to the passed-in {@code concretePackage}. 760 * 761 * <p>If the member package corresponding to the passed-in {@code concretePackage} 762 * cannot be found directly in the represented package its sub-packages are 763 * searched through. 764 * 765 * <p>{@code null} will be returned if: 766 * <ul> 767 * <li>The passed-in {@code concretePackage} is {@code null} or {@code undefined}.</li> 768 * <li>The {@link #getMemberPackages} method returns {@code null}.</li> 769 * <li>A package matching the passed-in {@code concretePackage} could not be found.</li> 770 * </ul> 771 * 772 * @param concretePackage the concrete package the corresponding package info shall 773 * be returned for 774 * @return the package info corresponding to the passed-in {@code concretePackage} 775 */ 776 public function getMemberPackageByPackage(concretePackage):PackageInfo { 777 if (concretePackage == null) return null; 778 var packages:Array = getMemberPackagesByFlag(true); 779 if (packages) { 780 for (var i:Number = 0; i < packages.length; i++) { 781 var package:PackageInfo = packages[i]; 782 if (package.getPackage().valueOf() == concretePackage.valueOf()) { 783 return package; 784 } 785 } 786 for (var i:Number = 0; i < packages.length; i++) { 787 var package:PackageInfo = PackageInfo(packages[i]).getMemberPackageByPackage(concretePackage); 788 if (package) return package; 789 } 790 } 791 return null; 792 } 793 794 /** 795 * Returns whether this package is a root package. 796 * 797 * <p>It is supposed to be a root package when its parent is {@code null}. 798 * 799 * @return {@code true} if this package info represents a root package else {@code false} 800 */ 801 public function isRoot(Void):Boolean { 802 return !getParent(); 803 } 804 805 /** 806 * Returns {@code true} if this package is the parent package of the passed-in 807 * {@code package}. 808 * 809 * <p>{@code false} will be returned if: 810 * <ul> 811 * <li>The passed-in {@code package} is not a parent package of this package.</li> 812 * <li>The passed-in {@code package} is {@code null} or {@code undefined}.</li> 813 * <li>The passed-in {@code package} equals this {@code package}.</li> 814 * <li>The passed-in {@code package}'s {@code isRoot} method returns {@code true}.</li> 815 * </ul> 816 * 817 * @param package package this package may be a parent of 818 * @return {@code true} if this package is the parent of the passed-in {@code package} 819 */ 820 public function isParentPackage(package:PackageInfo):Boolean { 821 if (!package) return false; 822 if (package == this) return false; 823 while (package) { 824 if (package.isRoot()) return false; 825 package = package.getParent(); 826 if (package == this) return true; 827 } 828 return false; 829 } 830 831 /** 832 * Returns the string representation of this instance. 833 * 834 * <p>The string representation is constructed as follows: 835 * <pre> 836 * [reflection fullyQualifiedNameOfReflectedPackage] 837 * </pre> 838 * 839 * @param displayContent (optional) a {@code Boolean} that determines whether to 840 * render this package's content recursively {@code true} or not {@code false} 841 * @return this instance's string representation 842 */ 843 public function toString():String { 844 var result:String = "[reflection " + getFullName(); 845 if (arguments[0] == true) { 846 var members:Array = getMembers(); 847 for (var i:Number = 0; i < members.length; i++) { 848 result += "\n" + StringUtil.addSpaceIndent(members[i].toString(true), 2); 849 } 850 if (members.length > 0) { 851 result += "\n"; 852 } 853 } 854 855 return (result + "]"); 856 } 857 858 }