Etch is a cross-platform, network messaging system which includes a service description language, a compiler, and runtime for a variety of programming languages. Etch is transport independent, which allows for a variety of transports to be used depending upon need and circumstance.
The Etch project was started because we wanted to have a way to write a concise, formal description of the message exchange between a client and a server, with a hefty set of requirements, including: the messaging technology should support two-way, real-time communication, have high performance and scalability, support clients and servers written in differing languages, support client / server running in wide range of contexts (such as thin web client, PC application, or server), and must support anyone (Cisco or not) adding new language bindings and new transports if the set provided by the Cisco Unified Application Environment team is not sufficient.
Existing competing systems were either too slow, hard to use, bloated, and / or proprietary. In any case, none fit this matrix of requirements perfectly. So, Etch is designed to be easy to use, fast, and small; while still being flexible enough to satisfy the above requirements.
SOAP / REST Web Services offer an interesting comparison by contrast. While Web Services are generally accepted as the de facto standard for cross-platform communication due to strong adoption across many tools and languages, the unfortunate reality is that Web Services have serious deficiencies which make them completely unusable for real-time communications. Specifically, Web Services have no effective way to communicate asynchronously from server to client due to a reliance on HTTP and have very high parsing overhead due to XML and SOAP message bodies. In some deployments server to client communication would be blocked by a firewall. Finally, any particular language usually does not support every aspect of Web Services, so it is completely possible to create a Web Service that is not, in fact, cross-platform.
The Etch service description language allows the messages of the service to be described using a concise, high-level programming language syntax. The NSDL describes messages; direction of the messages, message inputs and outputs, response timeouts, sender and receiver thread models, and authentication. The NSDL also allows for the specification of structured data, enumerated values, named constants, and exceptions. Comments written into the NSDL are copied into the generated native language files so that they are available to the programmers.
Etch supports language independence by compiling language appropriate interfaces supported by libraries to send and receive the messages. External data types are defined and mapped to appropriate language specific runtime objects, supported by native serialization code.
Etch service message descriptions and data are compiled into data structures which are used by the transport layer to format the messages for transport. All the information of the message is available to the transport layer. Transport is subdivided into message formatting, security, and protocol. Message formats include a compressed binary tagged format as well as XML. Security includes stream ciphers such as SSL / TLS and block ciphers such as DES or AES. Protocols include TCP, UDP (unicast, multicast, broadcast), and various SOAP formats. Other formats, security, and protocols are easily added.
A message is defined as a standard function call:
It has a name and a list of typed fields. It may return a value and it may throw an exception. However, as Etch is a client / server network messaging technology – not purely in-memory code – network considerations must be made. So in addition there are attributes, or tags, that can further qualify messages for optimal performance and encourage correct programming paradigms. For instance, a message that has no need of a response (fire-and-forget) may be decorated as 'one-way':
With a client & server, the direction of the message is of course important. By default, a message is assumed client-initiated; server-initiated messages (callbacks) must be decorated appropriately:
Another important message attribute is authorization. For example, if a message should not be allowed unless a certain requirement is met, then the message is tagged with that requirement. In this way the requirement is made plain, and the programmers implementing the service cannot forget:
There are more attributes that can be used to further qualify the service messages.
The Etch system is designed so that service descriptions may be extended or revised in ways that don't invalidate existing clients or servers. The rule is that changes following reasonable design disciplines do not invalidate the existing clients and servers.
Etch does not formally define service versioning because versioning is too often idiomatic to a service or organization. At the same time, versioning is too blunt a tool and artificially increases the difficulty of deploying compatible system upgrades. The best practice is to be disciplined about changes to the service description and to provide interfaces to query feature availability (a la ODBC / JDBC, SMTP, POP, etc.)
Etch includes support for the fundamental data types which appear in many processor architectures and databases: boolean, byte, short, int, long, float, double, and string. The integral values are all signed, with size from 1 to 8 bytes. The floating point values are all typically IEEE compatible, with size from 4 to 8 bytes. The string value is Unicode, with no specified length limit.
Etch also supports arrays of any supported data type. The arrays may have one or more dimensions. The arrays conform to the Java style or jagged arrays.
In addition, Etch supports the object data type which is used to model a parameter or result where the actual type is determined at runtime. An object type specification my be used anywhere a native data type is allowed except when declaring constants.
Etch supports the definition of enumerated types. The enumerations are mapped by name, not by any particular value or order.
Etch also supports the definition of structs and exceptions, which are very similar to message definitions (name, list of typed fields), although of course structs and exceptions do not have return values and cannot themselves throw exceptions.
Etch allows native language data types to be imported and used within the service definition. All that is needed is to give the type a name in the service description, then for each desired target language to nominate a type which carries the same semantics (java.util.Date in Java, System.DateTime in C#, Time in Ruby). A specific class which will perform the work of serializing and de-serializing the object must also be implemented per target language.
Etch allows the definition of named constants of the fundamental data types. These do not appear in the protocol per se, but are copied into the generated files and are available to all target programming languages.
The Etch compiler generates for each target language meta-data defining the types and fields of your service, interface files which define the messages, structs, enums, exceptions, external data, constants, and other NSDL elements, and then code to support turning method (or, function) calls into message sends (the remote implementation) and code to support turning messages received back into method calls (the stub implementation).
The compiler is implemented in Java and uses Velocity templates to generate the code. Thus the compiler is available to use on any Java enabled platform, although of course Java is not needed once the NSDL is compiled unless your application is written in Java. Once compiled, all your application need do is to link with the small Etch runtime written (more than likely) in the target programming language.
The current Etch system includes a production-ready, compressed binary tagged message format with TCP and UDP transports, and a non-production ready XML transport in Java as an example. The binary transport includes a tag for every data element which describes the size and type (i.e., 4 byte integer stored as 1 byte). Struct types and fields are encoded as a 32-bit hash of the name. This saves space in the wire format over sending the complete names. The maximum size of the add message defined above is 49 bytes, including an 8 byte packet header and 8 byte message ID (but not IP / TCP header).
The Java implementation of the Etch runtime needed to support a service using the compressed binary tagged message format over TCP without encryption is 288k (compressed jar file).
Performance numbers are always tricky and subjective because so much depends upon the context of the test. That said, we have gone through the exercise of contrasting various messaging technologies against one another. In this test, we implemented the add function shown above in Etch (Java language binding), Apache Axis2 SOAP web service, JAX SOAP web services, Thrift (Java), and CORBA (Java):
We plan to build a language binding for web services such than an Etch NSDL may be accessed and / or deployed as a web service. This would allow easy migration of clients and / or servers to use Etch natively while maintaining backwards compatibility with existing systems.