//////////////////////////////////////////////////////////////////////////////// // // Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to You under the Apache License, Version 2.0 // (the "License"); you may not use this file except in compliance with // the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// package mx.automation { import flash.display.DisplayObject; import flash.events.Event; import flash.events.KeyboardEvent; import flash.system.ApplicationDomain; import flash.utils.describeType; import flash.utils.getQualifiedClassName; import mx.core.mx_internal; import mx.managers.ISystemManager; import mx.managers.SystemManagerProxy; import mx.utils.ObjectUtil; use namespace mx_internal; /** * Provides serializable class information for external automation tools. * Some classes are represented as the same AutomationClass (HSlider and VSlider, forinstance). * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public class AutomationClass implements IAutomationClass2 { //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- public function AutomationClass(name:String, superClassName:String = null) { super(); _name = name; _superClassName = superClassName; } //-------------------------------------------------------------------------- // // Variables // //-------------------------------------------------------------------------- /** * @private */ private var _implementationClassNames:Array = []; /** * @private */ private var _properties:Array = []; /** * @private */ private var _verificationProperties:Array = []; /** * @private */ private var _descriptionProperties:Array = []; /** * @private */ private var _event2descriptor:Object = {}; /** * @private */ private var _method2descriptor:Object = {}; /** * @private */ private var _propertyASTypesInitialized:Boolean = false; //-------------------------------------------------------------------------- // // Properties // //-------------------------------------------------------------------------- //---------------------------------- // name //---------------------------------- /** * @private */ private var _name:String; /** * the class name * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get name():String { return _name; } //---------------------------------- // superClassName //---------------------------------- /** * @private */ private var _superClassName:String; /** * The name of the class's superclass. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get superClassName():String { return _superClassName; } //---------------------------------- // previousVersionClassNames //---------------------------------- /** * @private */ private var _previousVersionClassNames:Array = []; /** * An array of names of the classes that are compatible with current class. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 4 */ public function get previousVersionClassNames():Array { return _previousVersionClassNames; } /** * @private */ public function set previousVersionClassNames(value:Array):void { _previousVersionClassNames = value; } /** * @private */ private var _implementationVersion:int = 0; /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 4 */ public function get implementationVersion():int { return _implementationVersion; } /** * @private */ public function set implementationVersion(value:int):void { _implementationVersion = value; } /** * @private * A map of property name to property descriptor. * Useful in getting the descriptor based on property names. */ private var _propertyNameMap:Object = {}; //-------------------------------------------------------------------------- // // Methods // //-------------------------------------------------------------------------- /** * Add Flex class names which match this class description. * * @param className the name of the Flex class * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function addImplementationClassName(className:String):void { _implementationClassNames.push(className); } /** * @private * Add a property descriptor to the class object */ public function addPropertyDescriptor(p:IAutomationPropertyDescriptor):void { _properties.push(p); if (p.forVerification) _verificationProperties.push(p); if (p.forDescription) _descriptionProperties.push(p); _propertyNameMap[p.name] = p; } /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function getPropertyDescriptors(objForInitialization:Object = null, forVerification:Boolean = true, forDescription:Boolean = true):Array { // This is for nested app support. Since a component may not be loaded // until the sub-app is loaded, we need to delay accessing any // Class or describeType info until we have an instance who's loaderInfo // we can use. This assumes that objForInitialization is the type we need if (!_propertyASTypesInitialized && objForInitialization != null) { _propertyASTypesInitialized = true; var dt:XML = describeType(objForInitialization); //dt shouldn't be null when it gets here fillInASTypesFromProperties(dt, _properties); } var result:Array = []; if (forVerification && forDescription) result = _properties; else if (forVerification) result = _verificationProperties; else if (forDescription) result = _descriptionProperties; return result; } /** * @private */ public function addMethod(m:IAutomationMethodDescriptor):void { var hash:String = m.name; _method2descriptor[hash] = m; } /** * @private */ public function addEvent(m:IAutomationEventDescriptor):void { var hash:String = hash(m.eventClassName, m.eventType); _event2descriptor[hash] = m; } /** * Translates between component event and Automation method descriptor * * @param event The event object for which a method descrptor is required. * * @return The method descriptor for the event passed if one is available. * Otherwise null. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function getDescriptorForEvent( event:Event):IAutomationEventDescriptor { var eventType:String = event.type; if (event is KeyboardEvent) eventType = "keyPress"; var eventClassName:String = getClassName(event); var hash:String = hash(eventClassName, eventType); return hash in _event2descriptor ? _event2descriptor[hash] : null; } /** * Returns a full methodDescriptor from its name * * @param methodName The method name for which the descriptor is required. * * @return The method descriptor for the name passed if one is available. * Otherwise null. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function getDescriptorForMethodByName( methodName:String):IAutomationMethodDescriptor { for (var i:Object in _method2descriptor) { if (_method2descriptor[i].name == methodName) return _method2descriptor[i]; } return null; } public function getDescriptorForEventByName( eventName:String):IAutomationEventDescriptor { for (var i:Object in _event2descriptor) { if (_event2descriptor[i].name == eventName) return _event2descriptor[i]; } return null; } /** * Returns the fully qualified name of the class to which the object belongs. * * @param obj The object whose class name is desired * * @return Fully qualified name of the class * * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static function getClassName(obj:Object):String { return getQualifiedClassName(obj).replace("::", "."); } /** * Returns the major from current version number * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 4 */ public static function getMajorVersion():String { return AutomationManager.VERSION.charAt(0); } private static function getRootForThePopupObject(obj:DisplayObject):ISystemManager { var requiredSystemManager:ISystemManager = null; if(obj) { var objFound:Boolean = false; while((!objFound) && (obj.parent)) { if(obj.parent is SystemManagerProxy) { requiredSystemManager = obj.parent.hasOwnProperty("systemManager")?obj.parent["systemManager"]:null; objFound = true; } obj = obj.parent; } } return requiredSystemManager; } /** * Utility function that returns the class definition from the domain of a * object instance * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static function getDefinitionFromObjectDomain(obj:Object, className:String):Class { var eventClass:Class ; try { var dispObj:DisplayObject = obj as DisplayObject; // if the object is related to Popup's we need to get the application domain // from where the object is created. the root of the object here will corresponds to // the main application hence we getting the defintion from the main appl will not be correct var systemmanager:ISystemManager = getRootForThePopupObject(dispObj); if(systemmanager != null) eventClass = Class(systemmanager.loaderInfo.applicationDomain.getDefinition(className)); else eventClass = Class(dispObj.root.loaderInfo.applicationDomain.getDefinition(className)); } catch(e:Error) { // we can get a reference or security exception // in which case we try to access the objects own domain try { eventClass = Class(ApplicationDomain.currentDomain.getDefinition(className)); } catch(e:Error) { // we can get a reference or security exception // In this case we assume that the class definition is not available // as the class has not been referenced in the app and it has // not been linked in. } } return eventClass; } /** * Fills in the AS types for the provided propertyDescriptors based * on the information provided in the describeType XML. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static function fillInASTypesFromProperties( dtForClass:XML, propertyDescriptors:Array):void { // If DT was on a Class, we need to go to the factory node instead var isFactory:Boolean = dtForClass.hasOwnProperty("factory"); var dtListForClass:XML = isFactory ? dtForClass.factory[0] : dtForClass; for (var propNo:int = 0; propNo < propertyDescriptors.length; ++propNo) { // First try a property. var propASTypeXML:XMLList = dtListForClass.variable.(@name == propertyDescriptors[propNo].name); // If not there try an accessor. if (propASTypeXML.length() == 0) propASTypeXML = dtListForClass.accessor. (@name == propertyDescriptors[propNo].name); propertyDescriptors[propNo].asType = propASTypeXML.length() > 0 ? propASTypeXML[0].@type.toString() : null; } } /** * Fills in the AS types for the provided propertyDescriptors based * on the information provided in the describeType XML. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static function fillInASTypesFromMethods(dtForClass:XML, methodName:String, argDescriptors:Array):void { // If DT was on a Class, we need to go to the factory node instead var isFactory:Boolean = dtForClass.hasOwnProperty("factory"); var dtListForClass:XML = isFactory ? dtForClass.factory[0] : dtForClass; var propMethodXML:XMLList = dtListForClass.method.(@name == methodName); if (propMethodXML != null) { for (var argNo:int = 0; argNo < argDescriptors.length; ++argNo) { argDescriptors[argNo].asType = propMethodXML[0].parameter[argNo].@type.toString(); } } } /** * @private */ private static function getASTypeForMethodArgument(dtForClass:XML, methodName:String, argName:String):String { var propASType:String = null; // If DT was done a class, we need to go to the factory node instead. var isFactory:Boolean = dtForClass.hasOwnProperty("factory"); var dtListForClass:XML = isFactory ? dtForClass.factory[0] : dtForClass; var propASTypeXML:XMLList = dtListForClass.variable.(@name==argName); if (propASTypeXML.length() == 0) propASTypeXML = dtListForClass.accessor.(@name==argName); propASType = propASTypeXML.length() > 0 ? propASTypeXML[0].@type.toString() : null; return propASType; } /** * Puts an event in string form for hashing * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ private static function hash(eventClassName:String, eventType:String):String { return eventClassName.replace("::", ".") + "|" + eventType; } /** * private * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get propertyNameMap():Object { return _propertyNameMap; } /** * @return name, superClassName, and event/method mappings. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function toString():String { return "name: " + _name + "\n" + "superClassName: " + _superClassName + "\n" + "event2descriptor: " + ObjectUtil.toString(_event2descriptor); } } }