Dataworks Enterprise - Choose Your Language

Dataworks Enterprise can support a lot of different development environments and a lot of different languages. This document describes how Dataworks Enterprise integrates into these different language environments and discusses the criteria upon which a choice betwen languages might be made.

Dataworks Enterprise API is a COM API. This means that the API is accessible from any automation aware language environment. Choosing the particular language for a project is as much a matter of the programmer as it is the project. Dataworks Enterprise facilitates this by maximising the available choice.

Where to get Help for Dataworks Enterprise API

The Online Help is the central resource for detailed information on Dataworks Enterprise APIs. From the Start menu, select Run and type "rtcache.hlp". Aletrnatively, if you are in VB select the Client or Server icon in the toolbox and Press F1. You should see a page of help appear with an overview of the RTClient control.

In addition to the usual buttons for methods, properties and events, there is a ‘Members’ button. Click on the Members button and a new window will appear listing all the properties, methods and events in a convenient browser window. Clicking on a Green member name displays the description of the member in the main window. The browser window stays on the screen allowing you to quickly move from one member to the next.

Returning to the main help window, select ‘Index’ from the menu. This provides a quick lookup of a known topic. Dismiss the popup window and select ‘Contents’. The ‘Contents’ window will appear. It displays a hierarchical view of the programmable objects exposed by the Cache. Double clicking on a little booklet opens the tree. Double clicking on a page (containing a question mark) goes to the appropriate entry in the help.

The online help contains a wealth of information that is worth exploring at length.

Dataworks Enterprise, Visual Basic and VBA

Microsoft Visual Basic (and its variants VBA and VBScript) is becoming the language of choice for rapid development of application functionality. The syntax of each dialect is similar enough for programmers to move from one to another with ease, although they are not identical. Many of the differences between VBA and VB relate to the libraries of objects and underlying functions supported in the run-time system.

Visual Basic is useful where the customer requires full-blown applications and/or controls. VBA is employed as a scripting language in Office applications such as Excel as well as in third party applications. Both suppport similar functionality and have a standard integrated debugger, object browser, forms package, etc.

VBScript is used where a lightweight scripting language is required, typically on Web pages, Active Server Pages and so on. VBScript unlike the others has no integrated debugging/programming system and has been mainly used in Web Authoring environments.

Visual Basic dialects are intrinsically ‘COM aware’. The Real-Time Cache controls can be dropped straight onto VB forms. It should be noted that the Cache controls could also be embedded straight onto spreadsheets using the VBA Tools dialog. The object tree can be explored from the standard VB object explorers.

Using the RTClient Control

The easiest way to understand Dataworks Enterprise object model is to use it directly from Visual Basic. The Programmers Guide provides a step-by-step guide for Visual Basic novices to illustrate how quickly connections can be made to the Cache components and data requested from the distribution system.

Error Handling

Users are strongly advised to use the keywords ‘Option Explicit’ at the head of all Visual Basic modules. This forces the user to declare all variables prior to their use. By default, Visual Basic will auto-create variables on first use giving rise to a large number of potential typographic bugs.

In addition, programmers should be careful when using On Error… instructions. The Real-Time Cache objects have a large number of parameter and other checks they perform. When errors are returned, the errors are accompanied by a meaningful description of the cause of the error where this can be deduced. This information can be lost as a result of an On Error statement.

Dataworks Enterprise and C++

C++ is the language of choice where a solution requires greater performance than can be provided within the Visual Basic environment.

Microsoft Visual C++

Interfacing to the Real-Time Cache in C++ is normally achieved using the supplied interface header toscapi.h and the related type library toscapi.tlb. toscapi.h defines a set of C++ wrapper classes to the objects defined in the library. This performs two functions:

  • It reduces the need for C++ programmers to perform OLE based conversion of parameters and return values into more C++-suitable types.
  • It provides extensions to the basic methods provided by the COM objects to make a more natural interface for the C++ programmer.

    The C++ wrappers are implemented as classes derived from standard #import smart pointer wrappers. This means that a single property may be available in a number of forms. Thus the use of the header file is dependent upon using Microsoft Visual C++ compiler version 5 or above.

    The header file begins by importing the type library (provided in the lib directory) using the standard #import and then derives classes from the smart pointers that are generated.

    Lifetime

    The _com_ptr (smart pointer) base classes manage lifetime issues. This process allows the programmer maximum choice about which set of interfaces to support at quite low cost.

    Methods and Properties

    Methods and properties are added (conventionally starting with a lower case character) that operate on the COM objects using ‘most base’ inputs and ‘most derived’ outputs. For instance, a string property is defined in Automation as a BSTR. In these wrappers, the get and set would be:

    CString getThing(void) const;
    void    putThing(LPCTSTR val);

    Most C++ programmers will find these easier to use as they hide the details of COM and Automation types.

    Connection Points

    There are a number of classes in the library that are controls. However, they have been designed in such a way that they can be ‘contained’ without the need for a control site. Therefore, they can be instantiated directly.

    Connections to objects are performed automatically for those classes that support them. For each class, there is a ClassInterface that handles the incoming events. The objects are derived from this interface which routes events through protected virtual methods. The intention is that C++ programmers simply derive from the object and override as required. The use of the class wrapper also removes the need for constantly having to explicitly refer to the base smart pointer as in:

    (*this)->Method();

    This is used to force the operator->() overload to get the underlying COM interface. Alternatively, the constructor allows the user to pass in a ClassInterface allowing the object to be a member of a user-supplied class.

    Return Values

    Values returned from methods are typically objects rather than object references, since this allows us to automatically maintain object lifetime. There is little performance impact as a result of returning an object rather than a reference since each object is a wrapper and therefore only occupies 4 bytes of storage space (may be returned in a register).

    Object Comparison

    It should be noted that an object is only equal to another object in terms of its base pointer. It is possible to have two separate wrapper objects that refer to the same underlying pointer. As a result, evaluating equivalence is more complex than usual. For instance, when is a field ‘equal to’ another field? This could be true if:

    Therefore, we have only defined operator== to compare content for a few classes where the meaning is fairly clear e.g. CRTDataRef.

    Collection Classes

    It would be most natural for a C++ programmer to perceive a collection in the same manner as a SCL vector or map template with a collection of underlying elements.

    In addition, the collections should have an iteration and lookup mechanism that is efficient for the class. RT objects are defined to have an efficient lookup using the standard get_Item() property and an efficient iterator using get__NewEnum in order to make VB implementations as efficient as possible. Therefore we will delegate these to the objects themselves and then wrap them to make it look like SCL. Each collection wrapper has:

    size() the number of elements in the collection
    empty() returns true if there are no elements in the collection
    iterator() returns an efficient iterator for the collection

    If the collection is editable by the user, it also has:

    clear() removes all elements from the collection
    add() adds an element to the collection
    remove() removes an element from the collection

    The iterator class is instantiated from the template CollectionOfTIterator. The class is instantiated as:

    typedef class CollectionOfTIterator<CRTDataRef> CRTDataRefIt;

    The iterator of the DRTDataRefs collection is implemented as:

    CRTDataRefIt iterator(void) {
    	return RTDataRefIt((*this)->get__NewEnum());
    	}
    

    The resulting iterator is used as:

    CRTDataRefIt *it = object.iterator();
    	while(it.more())
    	{
    		CRTDataRef ref = it.next();

    ... }

    Exception Handling

    All the objects in this set use _com_error as an exception class along the lines of:

    if(FAILED(hr))
    		_com_issue_errorex(hr, this, __uuidof(this));
    

    i.e. in the same manner as the smart pointers. This is helpful when trying to catch exceptions. Any member function might produce an exception (exceptions are generated as a result of errors being returned by the core library). In most cases the error description will contain the reasons for the failure of the call. Thus, most code will be wrapped in a try…catch block.

    Other Compiler Vendors

    It is also possible to program using C++ (and C) compilers from other vendors. However, application programmers will need to write code that directly interfaces with the Cache (or via the standard automation Dispatch mechanism).

    Dataworks Enterprise and The Web

    Dataworks Enterprise is designed to integrate Web-based distribution with that of real-time market data distribution systems. As stated above, the Real-Time Cache component exposes its functionality using standard COM technology. This eases the use of the Cache within Web-Based systems and, consequently, allows those systems to be integrated with standard market data distribution systems. Industry standard browsers and servers such as Internet Explorer and IIS allow direct access to ActiveX (COM) interfaces directly from their respective scripting languages making the full range of market data services available to the Web distribution system.

    Examples of the use of Dataworks Enterprise within the context of client and server side scripting can be found in the Examples area of the distribution CD.

    Object Safety and Web Browsers

    All objects in the Cache support standard Object Safety mechanisms allowing them to be directly inserted into Web pages and other environments that check IObjectSafety interfaces. None of the objects in the Cache directly access machine resources such as files, sockets, screen or other hardware devices. The configuration system that underpins the Cache does attempt to open (for read access) its configuration files, if available. For these reasons, the objects are marked “safe for scripting” and, consequently, do not cause a browser to request that the user accepts their use within Web pages.

    Dataworks Enterprise and The Browser

    Dataworks Enterprise programmable components, as exposed by the Real-Time Cache, can be directly accessed from client-side scripting in MSIE. The examples on the CD use VBScript as this provides similar syntax and capabilities to standard Visual Basic and, therefore, is more likely to be familiar to end users. However, both VBScript and JScript can access ActiveX components using standard built-in functions of the ActiveX scripting host.

    Currently, access to COM objects is limited to Microsoft browser offerings. At the time of writing, Netscape and other browsers do not provide the necessary hooks to allow COM objects to be accessed from JavaScript.

    When the Cache components are employed in the client-side, the entire interaction with the distribution system is isolated to the client workstation. This means that interfaces to the market data distribution system need to be installed on that client. Dataworks Enterprise allows the data content to be integrated at the client host with Web content from a Web server. This type of environment would be employed where either the client already has the software installed or it is important that clients or web applications need real-time update capability. Dataworks Enterprise extends the web browser to perform some functions of the fat client application whilst maintaining the application content (embedded in web pages) at the server, which improves management and administration costs.

    To use the Cache components from the browser, some portions of Dataworks Enterprise software must be installed. From the installation program, a minimal installation can be provided using the Subscriber option that simply installs the Cache components and the distribution system plug-in.

    Most of the examples were created using Visual Interdev v1.0. However, it should be equally possible to create Web Pages in other editors, including NOTEPAD.

    The client-side scripts using the OBJECT tag to create an instance of the RTClient object called RTClient1:

    <object classid="clsid:3EAA52E7-39D6-11D2-8DF5-00400546FFC3"
    	data="data:application/x-oleobject;base64,51KqPtY50hGN9QBABUb/wwADAAC5AwAAuQMAAA=="
    	height="36" id="RTClient1" name="RTClient1" style="LEFT: 0px; TOP: 0px"
    	width="36" border="0"></object>
    

    Creating an object in this way allows the events for the object to be ‘hooked’ up. Scripts are declared using the SCRIPT tag.

    <script language="VBScript"><!—
    		… script goes here
    	--></script>
    

    Typically, code outside the context of subroutines or functions within the script is executed as it is encountered. This can make life awkward. For instance, if the client object has not been encountered at the time the script is run, then the variable name will not yet be valid. As a result, it is usual to place scripts in subroutines with a single subroutine to initialise the scripting, which is invoked once the page has been fully read by the browser. When the page is fully loaded, the browser invokes the onload handler as specified in the Body tag: <body onload="MyInitSub()">

    Within the scripts the events are declared as ObjectName_EventName subroutines. E.g.

    sub RTClient1_ImageFields(Record, Fields)
    		…
    	end sub

    Events can only be associated with objects contained within the page area (as specified by the object tag above). Additional standard objects (those which do not need events) can be created using the CreateObject() function, e.g.

    set docrefs = createobject("RT.RTDataRefs.1")

    Note that all Dataworks Enterprise objects are contained in the RT library.

    Dataworks Enterprise and The Web Server

    Dataworks Enterprise components can also be employed in the context of web server scripts, in this case using IIS and Active Server Pages (ASPs). An Active Server Page is a page of HTML, some proportion of which contains server side scripts. ASPs are run in the context of a client session. As with the browser, support for server side scripting is currently limited to Microsoft web server offerings using the same ActiveX Scripting Host as used in the browser.

    Server-side scripting is very similar to that of the client side. At the top of the ASP is the statement:

    <%@ Language=VBScript %>
    

    This indicates to the web server the default language in use.

    In this case scripts are identified using the server-side script tags:

    <% … script goes here %>

    A key difference between server and client-side scripts relates to the lifetime of the script itself. In a client side script, the lifetime of the script is the same as that for a page. Objects can be created, events responded and so on. In a server-side script, the script must run to completion so that the server can send the results to the client. The standard Real-Time Cache object model is essentially asynchronous. Therefore, if we are making requests for real-time data, we need a mechanism to wait for the results of a real-time request. This is achieved with the Wait() method.

    Since we have no need for events, we can create the client object using the CreateObject function:

    Set client = CreateObject("TOSC.RTClient")

    A typical script would request the data required and then enter a loop waiting for an event and checking whether the data request had completed. When all requests complete, the output data would be formatted and returned to the client. However, to simplify Web development, Dataworks Enterprise Client object provides an automatic Blocking function. This switches the Client into synchronous mode. The mode is selected using:

    Client.Blocking = True

    In blocking mode, the issuing of requests is performed asynchronously and the results collected in the cache. However, any access to record information from the client, including its fields, status information and permissions will cause the client to “block” until the specific data is available. Using this mode, the client can make a number of request asynchronously (getting best performance from the cache) and then block on the results of those requests.

    Consequently, scripts tend to appear as:

    Dim client
    	Set client = CreateObject("RT.RTClient")
    	client.Blocking = true
    
    	Dim Records
    	Set Records = MakeRequests()
    	WriteResultsToHTML

    If you want to tell the client to re-request the data from the server after a fixed period of time use the meta tag refresh, as follows:

    <% Response.AddHeader "Refresh", "10" %>

    This informs the client that the data needs refresh approximately every 10 seconds.

    Dataworks Enterprise and Java

    Java is rapidly becoming the language of choice in Web (and some distributed) application environments. Java is at once both a language and a development environment.

    Java source code is superficially similar to C++. The source code is compiled using a Java compiler into “byte code”, which is deployed on the target machine. The byte code is interpreted using a native Java virtual machine. Some byte code may be compiled into native code on the fly using a JIT compiler. This is to improve performance of the system. The VM operates a “sandbox” security environment making the system somewhat more secure than many other environments.

    Java code is, typically, written to run in one of two environments, the application of the applet. In the application environment, a “stub application” is used to load the virtual machine and execute the byte code in that machine. Applications may be either windowed or console programs. Java code also runs in the applet environment. This is typically used in Web page, where the Java occupies an embedded window in the Web page. The Web browser loads the virtual machine and passes downloaded Java class files to that machine for execution.

    Portability and Java

    The deployed byte code is, in theory, standard and therefore portable across platforms. However, the degree of portability is determined by the degree to which the language features available are common to those platforms and the availability of common libraries between the platforms. In practice, there are a wide range of virtual machines (including version of the same VM) and Java/native code libraries in use.

    The Java application communicates with native machine resources through a combination of standard libraries and specialised native code interfaces supported by the virtual machine. The standard libraries tend to portable but, typically, operate in a lowest common denominator fashion in order to maintain this portability. For instance, the standard windowing interface, called AWT, is functionally primitive but very portable.

    The Java VM usually also provides native code interfaces that allow a Java application to access non-portable code modules such as windowing, file system resources and standard non-Java application level code.

    As stated above, the Real-Time Cache component maximises its range of potential application development environments by exposing its functionality using standard COM technology. COM technology is available on the most common platforms in use. However, the use of COM mandates that Java programs need to communicate with COM native code and this has to be achieved using a native code interface.

    The Microsoft Java VM provides the support to call (and be called by) native code COM objects. The Visual J++ package (the standard Microsoft Java development environment) provides the support to automatically generate Java native interfaces from COM object descriptions. This is the environment described in this document.

    To use Java distributions from other vendors requires that a JNI module be developed to act as an interface layer between the Cache system and the Java language.

    Using Dataworks Enterprise in Visual J++

    To use the cache in Visual J++, create a project and import the cache native interfaces. This is achieved by generating a COM wrapper for the real-time cache module. To generate a COM wrapper, select Project/COM Wrapper… and select the TOSC Real-Time Cache module. This process makes the real-time cache object tree available for programming in the Java environment. To indicate that the cache is being imported into the project, place the following instruction near the head of your Java files:

    import rtcache.*;

    One common problem with using the native interface is its treatment of object deletion. Java operates a garbage collection service within the VM. This means that the point at which an object is deleted may be deferred by the virtual machine. The real-time cache operates the principle that an element will be deleted as soon as it is no longer required. This means that the moment you release an object, say by setting its reference to null, you should force a garbage collection to occur using System.gc() to ensure that the object is actually deleted. This only needs to be done on objects that you create where there deletion should be notified to other parties such as deleting a client, a server or a source.

    Examples of the use of Dataworks Enterprise with the Java language can be found in the Examples area of the distribution CD.