blob: 2270872b829950d63d1fb128a371cdd3d1ae7f49 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// 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.tool
{
import mx.automation.AutomationClass;
import mx.automation.IAutomationClass;
import mx.automation.IAutomationClass2;
import mx.automation.IAutomationEnvironment;
import mx.automation.IAutomationEventDescriptor;
import mx.automation.IAutomationMethodDescriptor;
import mx.automation.IAutomationObject;
import mx.resources.IResourceManager;
import mx.resources.ResourceManager;
[ResourceBundle("automation_agent")]
/**
* @private
*/
public class ToolEnvironment implements IAutomationEnvironment
{
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* @private
*/
public function ToolEnvironment(source:XML)
{
super();
for (var i:Object in source.ClassInfo)
{
// populate the class/automationClass map
var classInfoXML:XML = source.ClassInfo[i];
var automationClassName:String = classInfoXML.@Name.toString();
var superClassName:String =
classInfoXML.@Extends && classInfoXML.@Extends.length != 0 ?
classInfoXML.@Extends.toString() :
null;
var automationClass:ToolAutomationClass =
new ToolAutomationClass(automationClassName, superClassName);
automationClassName2automationClass[automationClassName] =
automationClass;
for (var j:Object in classInfoXML.Implementation)
{
var implementationXML:XML = classInfoXML.Implementation[j];
var realClassName:String =
implementationXML.@Class.toString().replace("::", ".");
var versionObj:Object = implementationXML.@Version;
var versionNum:String = versionObj.toString();
if(versionNum!= "")
{
realClassName = realClassName+"_"+versionNum;
automationClass.implementationVersion = int(versionNum);
}
else
{
automationClass.implementationVersion = 0;
}
className2automationClass[realClassName] = automationClass;
automationClass.addImplementationClassName(realClassName);
}
// for each method
for (var k:Object in classInfoXML.TypeInfo.Operation)
{
var operationXML:XML = classInfoXML.TypeInfo.Operation[k];
var automationMethodName:String = operationXML.@Name.toString();
var eventClassName:String =
operationXML.Implementation.@Class.toString();
eventClassName = eventClassName.replace("::", ".");
var eventType:String =
operationXML.Implementation.@Type.toString();
if (eventType)
{
var args:Array = [];
for (var m:Object in operationXML.Argument)
{
var argXML:XML = operationXML.Argument[m];
var argName:String = argXML.@Name.toString();
var argType:String =
argXML.Type.@VariantType.toString().toLowerCase();
var argCodec:String = argXML.Type.@Codec.toString();
var defaultValue:String =
argXML.@DefaultValue.length() > 0 ?
argXML.@DefaultValue.toString() :
null;
var pd:ToolPropertyDescriptor =
new ToolPropertyDescriptor(
argName, true, true, argType,
(argCodec == null || argCodec.length == 0 ?
"object" :
argCodec), defaultValue);
args.push(pd);
}
var returnType:String =
operationXML.ReturnValueType.Type.@VariantType.toString();
var codecName:String =
operationXML.ReturnValueType.Type.@Codec.toString();
if(eventClassName)
{
var ed:IAutomationEventDescriptor = new ToolEventDescriptor(
automationMethodName, eventClassName,
eventType, args);
automationClass.addEvent(ed);
}
else
{
var md:IAutomationMethodDescriptor = new ToolMethodDescriptor(
automationMethodName, eventType, returnType,
codecName, args);
automationClass.addMethod(md);
}
}
}
for (var p:Object in classInfoXML.Properties.Property)
{
var propertyXML:XML = classInfoXML.Properties.Property[p];
var propName:String = propertyXML.@Name.toString();
var propType:String =
propertyXML.Type.@VariantType.toString().toLowerCase();
var propCodec:String = propertyXML.Type.@Codec.toString();
var pd1:ToolPropertyDescriptor =
new ToolPropertyDescriptor(
propName,
propertyXML.@ForDescription.toString() == "true",
propertyXML.@ForVerification.toString() == "true",
propType,
(propCodec == null || propCodec.length == 0 ?
"object" :
propCodec));
automationClass.addPropertyDescriptor(pd1);
}
}
}
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* @private
*/
private var className2automationClass:Object = {};
/**
* @private
*/
private var automationClassName2automationClass:Object = {};
/**
* @private
* Used for accessing localized Error messages.
*/
private var resourceManager:IResourceManager =
ResourceManager.getInstance();
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* @private
*/
public function getAutomationClassByInstance(
obj:IAutomationObject):IAutomationClass
{
var result:IAutomationClass = findClosestAncestor(obj);
if (! result)
{
var message:String = resourceManager.getString(
"automation_agent", "autClassNotFound",
[AutomationClass.getClassName(obj), obj]);
throw new Error(message);
}
return result;
}
/**
* @private
*/
public function getAutomationClassByName(
automationClass:String):IAutomationClass
{
return ToolAutomationClass(
automationClassName2automationClass[automationClass]);
}
/**
* Finds the closest ancestor to this object about which information was
* passed in the environment XML.
* @private
*/
private function findClosestAncestor(obj:Object):IAutomationClass
{
var className:String = AutomationClass.getClassName(obj).concat('_').concat(AutomationClass.getMajorVersion());
var version:int = int(className.substr(className.length-1));
className = className.substring(0, className.length - 2);
for(var i:int = version; i > 0; i--){
var classNameWithVersion:String = className.concat('_').concat(i);
if (classNameWithVersion in className2automationClass)
return className2automationClass[classNameWithVersion];
}
if (className in className2automationClass)
return className2automationClass[className];
var ancestors:Array = findAllAncestors(obj);
if (ancestors.length != 0)
{
className2automationClass[className] = getClosestVersionAncestor(ancestors);
return className2automationClass[className];
}
else
{
return null;
}
}
/**
* @private
*/
private function getClosestVersionAncestor(ancestors:Array):IAutomationClass
{
//There can be many ancestors of same class but with different versions
//We need to find the ancestor which is closer in version to current version
var closeAncestors:Array = [];
closeAncestors.push(ancestors[0]);
var n:int = ancestors.length;
var isAncestor:Boolean = false;
for( var i:int = 1; i < n; i++ )
{
var firstSuperClass:String = ancestors[0].superClassName;
var secondAncestor:IAutomationClass = ancestors[i];
while( firstSuperClass )
{
if( firstSuperClass == secondAncestor.name )
{
isAncestor = true;
break;
}
else
{
firstSuperClass = getAutomationClassByName(firstSuperClass).superClassName;
}
}
if( !isAncestor )
{
var temp:Array = [];
temp.push(ancestors[i]);
closeAncestors = temp.concat(closeAncestors);
}
else
{
break;
}
}
var currentVersion:int = int(AutomationClass.getMajorVersion());
var closestAncestor:IAutomationClass = closeAncestors[0];
if(closeAncestors[0] is IAutomationClass2)
{
var currentAncestorVersion:int = IAutomationClass2(closeAncestors[0]).implementationVersion;
n = closeAncestors.length;
for (i = 1; i < n; i++)
{
var nextAncestorVersion:int = IAutomationClass2(closeAncestors[i]).implementationVersion;
if( currentAncestorVersion > currentVersion )
currentAncestorVersion = nextAncestorVersion;
if( nextAncestorVersion <= currentVersion && nextAncestorVersion >= currentAncestorVersion )
{
closestAncestor = closeAncestors[i];
currentAncestorVersion = nextAncestorVersion;
}
}
}
return closestAncestor;
}
/**
* @private
*/
private function findAllAncestors(obj:Object):Array
{
var result:Array = [];
for (var i:String in className2automationClass)
{
var temp:String = i;
if(temp.indexOf("_") != -1)
temp = temp.substring(0, i.lastIndexOf("_"));
var realClass:Class =
AutomationClass.getDefinitionFromObjectDomain(obj,temp);
if (realClass && obj is realClass)
result.push(className2automationClass[i]);
}
result.sort(sortAncestors);
return result;
}
/**
* @private
*/
private function sortAncestors(a:IAutomationClass, b:IAutomationClass):int
{
var superClass:IAutomationClass;
var x:String = a.superClassName;
while (x)
{
if (x == b.name)
return -1;
superClass = getAutomationClassByName(x);
x = superClass.superClassName;
}
x = b.superClassName;
while (x)
{
if (x == a.name)
return 1;
superClass = getAutomationClassByName(x);
x = superClass.superClassName;
}
// Bad things will happen if we return 0... maybe throw an error?
return 0;
}
}
}