ElementaryBlock Element/en

Aus expecco Wiki (Version 2.x)
(Weitergeleitet von ElementaryBlock Element)
Wechseln zu: Navigation, Suche

Introduction

Elementary blocks provide the basic low-level functionality of an expecco testsuite. They are used for operations which are not broken down into more elementary subactivities, and which are therefore not representable as an activity diagram ("Compound action"). Typically, operations described as elementary action block are numeric calculations, low level string, stream or collection operations, interfaces to protocols or to external devices. Especially domain specific low-level interfaces to local or remote processes, document converters, databases and hardware devices are implemented as eleemntary block.

Also, elementary actions are typically executed much faster than compound (diagram) actions. Therefore, performance critical operations are sometimes written as elementary blocks.

The behavior of an elementary block is defined by one of the following:

  • a piece of textual program code, which executes inside expecco, and is written in one of the directly supported and builtin programming languages (currently: Smalltalk or a JavaScript dialect)
  • a piece of code, written in Groovy, which executes in a Java Virtual Machine (JVM) on the local system, a remote system or inside the system under test (SUT) itself (requires extra Java plugin)
  • a piece of code, written in Python (IronPathon), which executes in a .NET Virtual Machine (CLR) on the local system, a remote system or inside the system under test (SUT) itself (requires extra DotNET plugin)
  • a piece of code, written in C# (CSharp), which executes in a .NET Virtual Machine (CLR) on the local system, a remote system or inside the system under test (SUT) itself (requires extra DotNET plugin)
  • a piece of code, written in VisualBasic Script, which executes in a separate script interpreter process (requires extra VB plugin)
  • a piece of code, which is executed by an external scripting language interpreter (shell, batch, ruby script or any other scripting language)
  • a call to a DLL (shared library) function (which is often, but not required to be) written in C or C++
  • a call to an external program
  • a remote procedure or service call (SOAP, REST, XML-RPC, SunRPC)

Expecco provides built in language interpreters and compilers for two scripting languages: the builtin Smalltalk and a builtin JavaScript-like scripting language. When such an elementary block is executed, the script code runs inside the expecco process. These support high level symbolic debugging including single-step, breakpoints or inspection of variables. The debugger even allows for code changes to be done to the running program (for example, while the program is stopped at a breakpoint). These internal scripts are transparently and automatically compiled into machine code when first executed ("hot swap" and "Just in Time" (JIT) compilation). Changed code will be executed when the function/block is called the next time; thus, there is a limitation, in that a suspended function's code has to either proceed and return or be aborted for the new code to become effective (but only that particular function/elementary block - not the whole execution).

Additional builtin scripting languages (Ruby and Scheme) are being prepared and planned for future releases.

Other scripting languages (Ruby, Perl, TCL, Python, etc.) can be called via external script interpreters. It is also possible to call existing command line scripts (Shell under Unix or Windows+cygwin, Batch under Windows).

With the Java Bridge extension plugin, elementary blocks can also be written in Groovy, which is a scripting language with a syntax similar to Java, and which is transparently (and dynamically) compiled to Java bytecode, and executed inside the SUT or on the expecco host or on any other such configured machine in the local network. Groovy blocks are very useful to define Java callbacks, subclasses of existing Java classes or to create and manipulate complicated Java objects inside a tested Java application. When such a block is executed, the script code runs inside a Java-VM, which can be either a local one, dedicated to script execution, or on the target system (even inside the SUT, if it is written in Java). More detail is found in the Expecco API Documentation.

With the DotNET Bridge extension plugin, elementary blocks can also be written in IronPython or C#. Similar to the above Groovy code, this is transparently (and dynamically) compiled, and executed inside the SUT or on the expecco host or on any other such configured machine in the local network. DotNET blocks are useful to access internals of the SUT or to interface to systems for which DotNET bindings (libraries) are available. More detail is found in the Expecco API Documentation.

With the VisualBasic Plugin, elementary blocks can be written in the VisualBasic Script syntax and are executed in an external VisualBasic interpreter. This may run on the local host (the one on which expecco runs) or optionally on a remote host. The host on which the script engine executes must be a Windows host. For expecco users working under Unix/Linux or OSX, this means that at least a virtual (or real) machine with a Windows system must be setup and reachable in the network, and that the Windows machine serves as a script execution server for the Unix machine.

The source code is usually edited in the code editor. It is interpreted according to the used language’s syntax at runtime. For the builtin languages Smalltalk and JavaScript, it is possible to switch the syntax pattern for already implemented blocks, causing the code to be automatically converted to that particular syntax style. The values of data pins can be directly accessed (read and write) in the code using getters/setters on the pin's name. The external interface of an elementary block (e.g. number of pins) is defined in the schema editor.

Notice that the standard library as delivered already contains a number of useful elementary blocks for a wide range of applications. So that the need to define your own elementary blocks is often limited to special interfacing or specialized processing of data. Depending on the testing domain (technical/business/UI-testing), many expecco users even do not need to write any elementary actions and can realize their tests using diagrams only - this is especially the case in the area of UI testing. On the other side, others may depend heavily on the ability to interact directly with deep internals of the SUT, for example to call Java functions with complex object interfaces. Expecco tries hard to provide a convenient framework for both ends of this spectrum, by integerating elementary code development seamless into the test development process.

Smalltalk and JavaScript Blocks

The following examples are meant as tutorial and introductionary examples. They are written to be easy to understand, not to use the full power of the underlying languages (eg. some could be written much shorter, by using more sophisticated existing library functions).

Don't worry: you will not need to go down to that low level programming to get started with expecco. All of the functionality presented below is already present in the Standard Library and can be used "out of the box". However, it may be good to know, that there are virtually no limitations in what you can do in expecco, and that whenever you need an additional function which the Standard Library did not foresee, it can be added in a few seconds.

Simple String Processing Example

The first example simply takes a string and cuts off some characters at either side, and returns some middle part of it. To make the example more interesting, the parts to be cut off shall be the first 5 characters at the left, and everything after the last separator (blank character or tab). We first define the external interface of that action block to consist of an input-pin named "inString" and an output-pin named "outString". Both pins are declared as being of "String"-datatype, this ensures, that when placed into a diagram, only other String-typed pins can be connected to it. The so called "schema" definition of the action block is therefore:

Datei:String example elementaryBlock.png

Then, write the code, either in Smalltalk as:

execute
    |inStringValue|

    "/ fetch the data value from the pin
    inStringValue := inString value. 

    "/ find the last separator in the string
    indexOfLastSeparator := inStringValue lastIndexOfSeparator.

    "/ extract the middle part
    middlePart := inStringValue copyFrom:6 to:(indexOfLastSeparator-1). 

    "/ write to the output pin
    outString value: middlePart

The same operation written in JavaScript as:

execute() {
    var inStringValue;

    // fetch the data value from the pin
    inStringValue = inString.value();

    // find the last separator in the string
    indexOfLastSeparator = inStringValue.lastIndexOfSeparator() + 1; // see below

    // extract the middle part
    middlePart = inStringValue.copyFrom_to(6, indexOfLastSeparator-1);

    // write to the output pin
    outString.value(middlePart);

There is one possible pitfall, when using JavaScript: JavaScript array-indexing is 0-based, whereas Smalltalk uses 1-based indices. This applies to all standard JavaScript functions (of which "indexOf" is one). However, when Smalltalk functions are called from JavaScript (as is the case with "copyFrom_to" above), we have to adjust the index.


You should always provide a little test and demo of your elementary actions in the Test/Demo page. There, place at least one instance of the block as a step, give it its required inputs and execute it there. For example:

Datei:String example elementaryBlock test.png

Number Reading Example

The next example takes a string and reads three numbers from it, which it returns as a 3 element vector (tuple). This could be useful as part of a reader for test data, or to process user input. The three numbers will be separated by spaces or tabs. It has a String-typed input pin named "inString" and an Array-typed output pin named "numberVector". It will report an error if not exactly 3 numbers are contained in the string:

execute
    |inStringValue inStream n1 n2 n3|

    "/ fetch the string from the pin
    inStringValue := inString value. 

    "/ get a read-stream on the string's characters
    inStream := ReadStream on:inStringValue.

    "/ read the first number
    n1 := Number readFrom:inStream onError:[ self error:'error reading the first number'].

    "/ and so on...
    n2 := Number readFrom:inStream onError:[ self error:'error reading the second number'].
    n3 := Number readFrom:inStream onError:[ self error:'error reading the third number'].

    "/ check, if the end of the stream has been reached (eg. nothing more is there)
    "/ but allow additional spaces
    inStream skipSeparators.
    inStream atEnd ifFalse:[
        self error:'garbage after the third number'
    ].

    "/ create a vector and write it to the output pin
    outString value: { n1 . n2 . n3 }

The same operation written in JavaScript as:

execute() {
    var inStringValue, inStream, n1, n2, n3;

    // fetch the data value from the pin
    inStringValue = inString.value();

    // get a read-stream on the string's characters
    inStream = ReadStream.on(inStringValue);

    // read the numbers
    n1 = Number.readFrom_onError(inStream, function() { this.error("error reading the first number");});

    n2 = Number.readFrom_onError(inStream, function() { this.error("error reading the second number");});

    n3 = Number.readFrom_onError(inStream, function() { this.error("error reading the third number");});

    // check, if the end of the stream has been reached (eg. nothing more is there)
    // but allow additional spaces
    inStream.skipSeparators();
    if (! inStream.atEnd) {
        this.error("garbage after the third number");
    }

    // create a vector and write it to the output pin
    outString.value( [ n1 , n2 , n3 ] );

Please notice the inner function argument in the above code, which is the error call back argument to the "Number readFrom_onError" call. In Smalltalk, this is simply written as a block "[...]", whereas in Javascript the ugly "function() {...}" syntax is needed. This is one of the examples, where Smalltalk code is much easier to write and understand (at least to those who have not been conditioned to C/Java style language syntax).

Minimum and Maximum of an arbitrary Function

Here is a block to compute the minimum and maximum values of a mathematical function over a range of x-values. It is especially flexible, as the name of the function can be passed as an argument (for example: 'sin', 'cos' or 'arcTan'). The block's definition is:

Min max elementaryBlock.jpg

and its code could be written in Smalltalk as:

execute
    |fn minY maxY y|

    fn := functionName value asSymbol.

    (x0 value) to:(x1 value) by:(dX value) do:[:x |
        y := x perform:fn.
        minY := minY isNil ifTrue:[y] ifFalse:[ minY min:y ].
        maxY := maxY isNil ifTrue:[y] ifFalse:[ maxY max:y ].
    ].

    min value:minY.
    max value:maxY.

or in JavaScript as:

execute() {
    var fn, minY, maxY, x, y;

    fn = functionName.value().asSymbol();
    for (x = x0.value(); x <= x1.value(); x += dX.value()) {
        y = x.perform(fn);
        minY = (minY.isNil()) ? y : minY.min(y);
        maxY = (maxY.isNil()) ? y : maxY.max(y);
    }
    min.value(minY);
    max.value(maxY);
 }

(notice the use of the "perform"-function, to call a function by name)


Of course, as usual, there are multiple ways to write the same function; an experienced Smalltalker would write:

execute
    |fn minMax|

    fn := functionName value asSymbol.

    minMax := ((x0 value) to:(x1 value) by:(dX value))
                  collect:[:x | x perform:fn])
                      minMax.
    min value:minMax first.
    max value:minMax second.

and a JavaScript programmer might prefer:

execute() {
    var fn, minY, maxY, x, y;

    fn = functionName.value;
    for (x = x0.value; x <= x1.value; x += dX.value) {
        y = x.perform(fn.asSymbol());
        minY = (minY == null) ? y : Math.min(minY,y);
        maxY = (maxY == null) ? y : Math.max(maxY,y);
    }
    min.value(minY);
    max.value(maxY);
 }


The block could be used to calculate the min/max of the sine function in the range 0..1 as follows:

Min max in use with sine.jpg

Multi-Setter with Variable Number of Input Pins

The following defines a block to set multiple key-value associations in a dictionary object. In the schema, the last two input pins were defined as a variable-pin-group (using the second to last pin's "special attribute" menu). Therefore, the last two pins can be replicated an arbitrary number of times in a step. The block's elementary code must of course be prepared for this, and loop over the step's number of input pin values.
The block's definition is:

MultiSetter elementaryBlock.png

and its code could be written in Smalltalk as:

execute
    |dictionary|

    dictionary := dictionaryInPin value.
    1 to: keyPin size do:[:index |
        |eachKey eachValue|

        eachKey := keyPin valueAt:index.
        eachValue := valuePin valueAt:index.
        dictionary at:eachKey put:eachValue.
    ].
    dictionaryOutPin value:dictionary.

or in JavaScript as:

execute() {
    var dictionary;

    dictionary = dictionaryInPin.value;
    for (var index = 1; index <= keyPin.size; index++) {
        var eachKey, eachValue;

        eachKey = keyPin.valueAt(index);
        eachValue = valuePin.valueAt(index);
        dictionary[eachKey] = eachValue;
    }
    dictionaryOutPin.value( dictionary );
}

A step to set 5 key-value pairs would look as follows (input pin group replicated 4 more times):

MultiSetter use with 5 groups.png

Groovy Blocks

A Groovy block's code is executed in a Java Virtual Machine (JVM), either locally, on a remote system or inside the system under test (SUT). It is described in more detail in the Expecco API documentation on Groovy .

VisualBasic Blocks

A VisualBasic Script block's code is executed by a scripting host (see Microsoft documentation on Visual Basic). It is described in more detail in the Expecco API documentation on VisualBasic and the VisualBasic Plugin documentation.

Shell Script Blocks

Under Unix operating systems (incl. Linux, Solaris, OSX etc.) or Windows with Cygwin installed (or any similar shell implementation which is bash/ksh compatible), you can also execute shell-script blocks. For example, here is a script to read its input, filter all lines beginning with some pattern, sort them, and pass them on as output:

grep "^xx" | sort

of course, arbitrary commands can be called (even programs with their own GUI). Under Windows, make sure that you have installed an appropriate shell emulator, and that it is either found along the PATH, or that you have specified the sh-path in the expecco-settings dialog (in "External Tools" - "Shell Path"). You can also define an environment variable named "SHELL", containing the path to a shell interpreter. This is convenient, if the shell path is to be determined dynamically, or if another language interpreter is to be used (for example, by defining a local environment variable, and setting it to "/bin/perl", the script will be passed to a perl language interpreter).

Shell Script blocks provide the standard output and standard error at their output pins as text, so you may have to read and analyze that further.

Notice, that these output pins are buffered by default. This has the consequence, that expecco waits for the command to finish, and only writes those pins if the exit status is 0 (i.e. "No Error"). This may be inconvenient in two situations:

  • if the called program/script interpreter returns an invalid exit status
  • if you are interested in the output, either during the execution, or in the error case.

Then, you should change the "Buffered" attribute of those pins to "Unbuffered".

In addition, the settings dialog contains a "Log Stdout/Stderr on Transcript" flag setting in the "Execution-Logging" section. If this flag is set, all output from shell, batch and other external script execution is also shown in the Transcript window (in 2.10.1, there is an additional flag named "Log Executed Commands", which if set only logs the command, but not its output).

By default, the scripting interpreter is executing in the "current directory", which may be inappropriate, if expecco is started via a click from the desktop (depending on the Operating System, this may be the expecco-installation directory, the users home directory or any other). Therefore, you may want to make sure, that the execution is performed in a definite directory, especially if the script needs to refer to other files from you project or system. For this, either provide an execution directory via the block's input pin, or specify it in the editor (which is effectively defining the directory as a freeze value).

The defined execution directory may contain placeholders in the form "$(xxx)", where "xxx" is either a shell environment variable, or one of the special builtin placeholder variables:

  • $(AttachmentsDirectory) - the directory, where all attachments of the suite are located
  • $(ExpeccoInstallationDirectory) - the directory, where expecco was installed
  • $(ExecutionDirectory) - a temporary directory, which vanishes after the execution
  • $(HomeDirectory) - the user's home directory
  • $(TmpDirectory) - a temporary directory (subfolder of the system's tmp directory)

Especially $(AttachmentsDirectory) is useful, if your script refers to other scripts which are attached to the test suite (eg. if you have an attachment named "foo.sh", a shell script can call this with "sh foo.sh" iff the excution directory was specified as "$(AttachmentsDirectory)".

Variables are searched in any block-local environment, the test-suite environment, or the shell environment. Thus, you can also refer to shell variables such as "HOME" via "$(HOME)".

Batch Script Blocks

These are similar to shell scripts, but use the Windows-batch file syntax. These cannot be executed on Unix systems, so your tests become OS-dependent, if you use them. The example code below would check out some source code from a cvs repository and start a build:

REM
REM batch file script (windows only)
REM
echo Checking out...
cvs co myProgram
cd myProgram
echo Building...
make

Batch Script blocks provide the standard output and standard error at their output pins as text, so you may have to read and analyze that further. Please read the paragraph on buffering the output and definition of the execution directory in the above "shell" section.

Ruby Script Blocks

These are similar to shell scripts, but the script is executed by a ruby interpreter, instead of the sh (or bash). You have to ensure that an appropriate ruby interpreter is installed on the machine (it is not part of the expecco delivery package).

Similar to shell scripts, the ruby interpreter path can be either be left unspecified, or specified in the expecco settings (external tools), or via an expecco environment variable named "RUBY_SHELL"). The environment variable can be the global project environment, or the global test suite environment. If left unspecified, or without an absolute path, the ruby interpreter should be found along the PATH.

Ruby Script blocks provide the standard output and standard error at their output pins as text, so you may have to read and analyze that further. Please read the paragraph on buffering the output and definition of the execution directory in the above "shell" section.

Python Script Blocks (2.10.1 and up)

These are similar to shell scripts, but the script is executed by a python interpreter, instead of the sh (or bash). You have to ensure that an appropriate python interpreter is installed on the machine (it is not part of the expecco delivery package).

Similar to shell scripts, the python interpreter path can be either be left unspecified, or specified in the expecco settings ("external tools"), or via an expecco environment variable named "PYTHON_SHELL"). The environment variable can be the global project environment, or the global test suite environment. If left unspecified, or without an absolute path, the python interpreter should be found along the PATH.

Python Script blocks provide the standard output and standard error at their output pins as text, so you may have to read and analyze that further. Please read the paragraph on buffering the output and definition of the execution directory in the above "shell" section.

Python, Ruby or Other Scripts via Shell Blocks

Any external interpreter for any scripting language can be called via a regular shell/batch block. For this, either place your scripts into a well defined folder or add them as attachments to the suite. Then define corresponding compound blocks, which consist of a simple shell/batch call to the interpreter, and passing the script file's name plus additional parameters as command-line arguments.

A concrete example to call an external python script is found in the demo suite "d43_Call_Python_Script_via_Shell.ets", which looks like:

CallPythonViaShellExample.png  

and a python script (in the "test.py" attachment):

print( "Hello World from a python script (1)" )

DLL-Calls

DLL-call blocks define an interface to a function which is contained inside a DLL (Dynamic Link Library). Typically, these are C or C++ functions. For a dll-call to be possible, the functions attributes have to be entered into the dll-call editor. These are:

  • name of the dll (for example: "user32.dll"). If the DLL-name has no extension (".dll"/".so"), an OS-specific extension is added by expecco. For portability of your suite, it is better to only provide the base name here and let expecco choose the extension.
  • the name of the function within the dll
  • the calltype (WINAPI or C-Call).
  • the number and types of the arguments
  • the type of the return value.

In addition, it is possible to specifiy that the dll-call is to be executed by a separate API-call thread. This avoids a blocking of the expecco user interface and other executing activities, for long running dll-calls, or called functions which stay in a blocking wait or a busy polling loop.

If your testsuite is planned to be portable across operating systems (i.e. it should run under both Windows- and Unix test machines), you will need both a windows DLL ("foo.dll") and a unix shared library object ("foo.so" or "foo.dylib"). Because the filename extensions are OS-specific, it is recommended to enter the basename without suffix into the "DLL name" field. Expecco will fill in the extension as used by the OS (however, if your dll uses a non-standard extension, you will have to provide it).

Calling Conventions

The term "calling convention" refers to the way arguments and the return value are passed to/from the called function. For most function calls, the default (C-API) is to be used. However, for historic reasons, functions in Windows32 may be defined in two flavours: WINAPI and CDECL (C-API)

The WINAPI (or API-) calltype specifies that a different argument passing scheme is to be used. This is specific to MS-Windows 32bit DLLs, and even there, only to a subset of all libraries.

Unless you have the C-header file parser plugin/extension installed, expecco has no builtin mechanism to figure out, which call convention is to be used for a particular DLL function. On Windows, if you do not have the source code of your called function at hand, consult the C header file, where the called function's declaration is found. There, look for a "WINAPI" or "API" prefix. In general, the WINAPI interface is a historic leftover from ancient times, when Windows was written in Pascal. However, they are still used (for backward compatibility) in many system DLLs - especially in the Kernel, User and GDI dlls.

On Unix- and 64bit Windows systems, the calltype is ignored and the C-calling convention is used. Thus, unless the name or parameter types are diferent, the same DLL-call action can be used for both architectures (given that corresponding DLLs are available).

C++ Name Mangling

If the called function is a C++ function or C++ wrapper function, the compiler may have arbitrarily mangled the functin's name (-> wikipedia: "name mangling"); usually a prefix or suffix, or both are added to the plain function's name. As this name mangling is very OS and compiler-specific, no automatic name generation can be done by expecco, and you will have to find out the name yourself, and paste it into the "C++ Name" field. Use any of your system's symbol-table listing tool ("nm", "dllWalker" etc.) to find out that name.

DLL Mapping

Expecco (actually Smalltalk) maintains a DLL-name mapping feature, which translates DLL-library names on an individual per-DLL basis. Thus, it is possible to control which DLL is actually used by DLL call blocks. The mapping is very useful, if multiple versions of a DLL are present (e.g. use "foo" in the DLL call block, and define a mapping of "foo" to "foo.vsnX") or to control from which location a library is to be loaded (e.g. define a mapping from "foo" to "/mylibs/libraries/foo.so").

This mapping can be defined in the "Settings" -> "Project Management" -> "DLL Mapping" dialog, and is stored in your local user settings.

In addition, the StandardLibrary contains a block "Define DLL Mapping", which can be used to modify this mapping table dynamically by the suite itself. However, DLL-mapping is an issue depending on the underlying execution machine - not of the test suite. In order to get portable suites, it is recommended to define the mapping in the user-preferences of the execution machien, and leave any dependencies on pathes or DLL-file names out of the suite.  

SOAP-Calls

These blocks define a remote procedure call via the SOAP protocol. SOAP blocks are normally generated automatically, by importing a wsdl service description. For more information, please refer to the WSDL Import Plugin description.  

REST-Calls

These blocks define a remote procedure call via the REST protocol. REST blocks are created in the navigation tree, via the "New Action"-"Services"-"REST Action" menu item. They are to be configured with a service endpoint (i.e. URL) and a sub-path, to address/identify the object under that endpoint.

REST actions have a predefined scheme, which lookes like:

REST scheme sample.png

part of its parameters are given dynamically by input pins, whereas others are predefined in the declaration tab:

REST declaration sample.png

The final http-URL is constructed by concatenating those the path components (endpoint URL and object locator sub-path), of which either may be empty (i.e. it is possible to specify the resulting full path completely statically via the declaration and leave the pin unconnected), or to specify it completely dynamical, by leaving the declaration empty).
However, usually, the service endpoint will be provided by an environment variable (the target host), whereas the either object-path remains fix and comes from the possibly frozen input pin, or is generated by an enumerator and comes from another action block. But that is a matter of your concrete setup and/or personal preferences.

The "__decode__" input specifies if the responseText should be decoded (as JSON- or XML-Dom object) and provided at the responseObject output pin. If the REST service does provide one of them as answer, it is convenient to get the object already decoded at this output. Otherwise, you will have to fetch the value from the "responseText" output pin, and decode the value yourself (in this case, it will usually be text).

The "httpBody" input should receive a string to be sent with the request, if the REST-service requires so. Typically, this is a JSON- or XML-encoded object to be stored or passed as argument (eg. in a PUT/POST request). However, there are also REST calls, which do not require any input data. The value passed to this pin should be a string and thus already encoded from whatever object is to be sent. If reuired, use on of the JSON-encode or XML-generate action blocks. Or generate the string using one of the String-format or String-concatenation blocks.

The "encodeUTF8" and "decodeUTF8" flags are new with expecco 2.10.1. In previous releases, the given httpBody and returned responseData where transmitted unchanged (i.e. you had to encode/decode them explicitly, by using one of the EncodeUTF/DecodeUTF actions. Now, this can be done automatically for you, by checking one of those flags. For backward compatibility, the default is "false"; if your suite already provides utf8-encoded data (or there is no need to do so, because it only contains ascii text), it will run unchanged in 2.10.1.

When structured objects are returned (as JSON or XML), it is recommended to create another compound action, which performs the required decoding and isolates the details from the rest of the suite. For example, if a XML-Dom is returned, a wrapper action may extract relevant fields and look like: REST wrapper sample.png


Take a look at the examples in the "w09_RESTcallDemo.ets" file, which is found in the examples folder.  

XML-RPC-Calls

These blocks define XML-RPC remote procedure calls. XML-RPC is a very light-weight and low-overhead XML-based protocol, which is supported by many service oriented applications (among them, expecco and expeccoNET themself). For an XML-RPC call, the following information is mandatory:

There are 3 alternative ways, to specify the URL:

  • hardwired as a string in the blocks specification (not recommended)
  • via an environment variable
  • via a pin value (freeze or dynamic)
Hardwired Service URL

Because this is very unflexible, it should be only used for very constant URLs, or while exploring a service interface. For this, type the URL into the block's specification form.

Specifying the Service URL via an Environment Variable

Use a macro-replacement pattern such as "%(RPC_HOST)" in the URL field (as above). This will be replaced by a corresponding variable name from the reachable environment variable named accordingly. You can either specify a full URL (i.e. host, port and path) or a partial URL using this mechanism. For example, you can also provide the URL via 3 separate environment variables, by entering: "%(RPC_HOST):%(RPC_PORT)/%(RPC_PATH)". A runtime error will be reported, if the variable expansion leads to an invalid URL. However, if a missing expansion leads to a valid URL, no error is reported. This allows for optional fields to be added to the URL, for example as in: "%(JIRA_HOST)%(OPTIONAL_RPC_PORT)/jira/rpc/xmlrpc".

Providing the URL via an Input Pin

Add an input pin with the (obligatory) name "url", and deliver it a string value. This is the most flexible way, as the URL value can be dynamically generated by any other block, or be provided via a pin-freeze value. If a url-pin is present, but not connected, it is ignored and the above variable mechanism is used. Otherwise, the pin-value takes precedence over any value in the specification.


See Also

For a list of already existing blocks, see Standard Library
For the programmer API for the built in languages see: Expecco API
For information on the functions avaliable in the built-in classes, please refer to the [Smalltalk/X Online Documentation] and especially the [Class Reference]. For example, some of the mathematical functions are described [here] and String processing functions are found [here] and [here].



Copyright © 2014-2016 eXept Software AG