SAFS Distilled --- 9 April 2015 to 16 April 2015
In the org.safs.model, the class Component stores:
- information of this component's name
- reference of its parent, also a component
1 2 | private String _name; private Component _parent; |
It provides interface to return its name, its parent's name and its parent's comopnent reference:
1 2 3 4 5 | public String getName(); public Component getParent(); public String getParentName(); |
In package org.safs.model, the Utils class provides various functions used by other classes. For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /** * Wrap the provided val String in double-quotes. * @param val String to wrap in double-quotes * @return val wrapped in quotes or a double-quoted empty string if * val was null. */ static public String quote(String val) { if (val == null ) return "\"\"" ; return "\"" + val + "\"" ; } public static String concat(String string1, String string2) { return string1 + "&" + string2; } |
Retrieve SAFSVARS
Let's first talk about the process of retrieving SAFS variables stored in SAFSVARS. This process will show many mechanisms routining in SAFS. We need to open up the packages of SAFS to know some basic classes structure.
In package org.safs.model.tools, class EmbeddedHookDriverRunner is an access point to a minimalist EmbeddedHookDriver Driver API. EmbeddedHookDriver allows custom JSAFS test development and execution inside a Java-based SAFS Engine.
As the constructor is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /** * Create the Runner that instantiates the particular EmbeddedHookDriver subclass * pass in to the Constructor. */ public EmbeddedHookDriverRunner(Class clazz){ super (); if (driver == null ){ try { driver = new EmbeddedHookDriverDriver(clazz); } catch (Exception x){ x.printStackTrace(); throw new Error( "Cannot instantiate required Drivers!" ); } } } |
It'll create specific subclass of EmbeddedHookDriver for doing the work. Also from the code, we can know that EmbeddedHookDriverDriver is just a wrapper of EmbeddedHookDriver for providing minimalist interface.
Java-based SAFS Engines would need to implement an engine-specific subclass of this EmbededHookDriver using a EmbeddedHookSTAFHelper to take advantage of this feature. For example:
1 | EmbeddedHookDriverSubclass hook = new EmbeddedHookDriverSubclass( "UniqueName" ); |
Generic JavaHook for tool-independent SAFS Engines. This abstract class provides the implementation for the initialization and event handling of all Java-based SAFS Engines that will be controlled via our SAFS protocols.
1 2 3 4 5 | // Set the process name for this hook for an instance of created from an empty constructor. protected void setProcessName(String process_name); // Insert this SAFS Engine hook into the STAF system. void start(); |
JSAFSDriver Structure and Utility:
- AbstractDriver: the root, abstract implementation of tool-independent driver.
- DefaultDriver: root, yet abstract, implementation of tool-independent driver, final concrete implementation must implement AbstractDriver#processTest().
- JSAFSDriver: provides easy access to SAFS functionality for non-SAFS programs and frameworks.
Combine the two parts, we get:
In order to retrieve the value of a SAFS variable stored in SAFSVARS, SAFS uses a embeddedHookDriverRunner to finish the work.
1 | return Runner.jsafs().getVariable(variableName); |
The steps are:
- return a EmbeddedHookDriver by using EmbeddedHookDriverDriver called by EmbeddedHookDriverRunner.
- use this embeddedHookDriver to return a JSAFSDriver.
- use the JSAFSDriver to retrieve the value of a SAFS variable stored in SAFSVARS.
Then, let's focus on the retrieving method of JSAFSDriver.
The method getVariable()
1 2 3 | public String getVariable(String varname){ return getVarsInterface().getValue(varname); } |
is from the superclass AbstractDriver. It'll return the VarsInterface:
In the interface SimpleVarsInterface, it will return the current value of variable var.
That's the whole process of retrieving the variables stored in SAFSVARS.
The obvious next question is: when are the values of variables stored in SAFSVARS loaded into program?
Well, in fact this will be another long story we will expand below.
In order to know when SAFS load the configuration information, we'll focus on the following class structure:
In the AbstractDriver class, it offers lots of variables to store the driver interface information:
1 2 3 4 5 6 7 8 | // Driver Interface Information protected InputInterface input = null ; protected MapsInterface maps = null ; protected VarsInterface vars = null ; protected LogsInterface logs = null ; protected CoreInterface core = null ; protected CountersInterface counts = null ; protected DebugInterface debug = new DebugInfo(); |
Here, we may focus just one variable maps (which) as our example for explanation.
The JSAFSDriver offers a method run() for initializing the embedded dirvers and engines to start running if it is not already running. It ensures the drivers are initialized before trying to use them. Following this run() method, a series of calling will happen:
- driver.run()
- preloadAppMapExpressions()
- preloadAppMap()
The first part, driver.run(), will initialize configuration with default paramters. The process is below:
Thus, the validateRootConfigureParameters() method will configurate paramters with defalut paramters.
-
In DefaultDriver class, method validateRootConfigureParameters() gets the configuration information.
-
In org.safs.tools.drivers.ConfigureFile.java, class ConfigureFile implements ConfigureInterface, and its method getNamedValue() will retrieve the values in the configuration sources.
-
In org.safs.tools.drivers.ConfigureInterface.java, the method getNamedValue() of interface ConfigureInterface is used to retrieve an item that may be in the configuration sources. An item is identified by a parent key or section name, like in an INI file "section", and the name of the item in that section.
After loading of configuration information, in the DefaultDriver class, the function initializeRuntimeInterface() will initialize these interface variables:
1 2 3 4 5 6 7 8 9 10 | protected void initializeRuntimeInterface(){ // ... try { // first one in, if initializing STAF, must be last one to shutdown. maps = (MapsInterface) getGenericInterface(DriverConstant.SECTION_SAFS_MAPS, DriverConstant.DEFAULT_MAPS_INTERFACE); // ... } // ... } |
Inside the getGenericInterface() method, it'll use the configuration information, stored in variable configInfo, to initialize the corresponding interface information, i.e. maps here:
1 2 3 4 5 6 7 8 9 | protected GenericToolsInterface getGenericInterface (String configSection, String defaultInterface) throws ClassNotFoundException, IllegalAccessException, InstantiationException { String iName = configInfo.getNamedValue(configSection, "Item" ); if (iName == null ) iName = defaultInterface; iName = StringUtilities.TWhitespace(iName); iName = StringUtilities.removeDoubleQuotes(iName); return ((GenericToolsInterface) (Class.forName(iName).newInstance())); } |
The third part, preloadAppMap(), will locate the directory of MAP file, and using file read function to assign corresponding interface variables:
That's the brief explanation of loading MAP files.
Open a Browser
In the SeleniumPlus class, the command() method executes a driver command by a EmbeddedDriverRunner, Runner:
1 2 3 | public static EmbeddedHookDriverRunner Runner = new EmbeddedHookDriverRunner(EmbeddedSeleniumHookDriver. class ); // ... prevResults = Runner.command(command, params); |
Process of calling functions:
In order to startup a service, it needs to use the interface of a driver's wrapper, i.e. the Runner. Then, by using the method of wrapper, it uses JSAFSDriver to call corresponding method. It's obvious that all the other service calling will get through this process. Summary above, we get:
- Use an access point of a driver's wrapper, Runner.
- Use the wrapper, driver of EmbeddedHookDriver which is the field of Runner, driver.
- Use this driver to get a Java SAFS Driver, jsafs.
- Use jsafs to call process command methods.
Following above steps, by using jsafs to startup command methods, it needs to call abstract driver method. After the initial parameters processing, it will use a Process variable, proc, to call the concrete driver methods.
The RemoteDriver class handle a SeleniumRMIAgent, if enabled, to communicate with a remote SAFS Selenium RMI Server.
Log In
The log in process involves the click action, which is a little different than the process of command.
Process of calling structure:
In ComponentFunction class, the componentProcess() method includes the process generic actions on a component.
Set Text Value
The process of "set text value":
How to generate Map.class file:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)