In the first part of this series about back-end integration with VoiceObjects we have seen an overview of the different approaches that are available with VoiceObjects 9.1. Now, in this second part, we will take a closer look at the Java Connector.
Basics
The basic idea of the Java Connector is that you implement a Java class for back-end integration. This Java class is instantiated directly by the VoiceObjects Server instance (i.e. it is running in the same Java Virtual Machine as the VoiceObjects Server instance), and the VoiceObjects Connector object of your VoiceObjects dialog implementation directly uses instances of your custom Java class.

Your Java class has to follow some conventions to allow the VoiceObjects Server to use it (your class does not have to implement any specific interface or extend any specific super-class).
- It has to be a Java Bean that provides public set methods for your input parameters and public get methods for your return parameters.
- All parameters (input and return parameters) have to be of type String (java.lang.String).
- Your Java Bean also needs to have one public business method – a method that performs the actual back-end access. The business method typically uses the Bean properties containing the input parameters (the ones that have been set using the set methods) and it populates the Bean properties containing the return parameters (the ones that will be read using the get methods).
- The business method must not have any parameters (it solely operates on the parameters that are set using the set methods).
For error handling, you can implement two additional get methods (in addition to the methods for your return parameters) – getErrorCode and getErrorMessage. Both methods have to return a String – the return value of getErrorCode is actually a number in wrapped in a String. The error codes “0″ (Zero) and below 0 indicate that no error occurred. Values above 0 indicate an error and will trigger an Error-Connector in VoiceObjects. In the VoiecObjects application the results of getErrorCode and getErrorMessage can be accessed using the Expression functions ERRORCODE and ERRORMESSAGE. It is important to catch all Exceptions that might occur in your Java code. It is not recommended to propagate any Exceptions from your Java code to the VoiceObjects Server instance. For error handling, please use error code and error message as explained above.
So a very basic implementation can look like this.

The basic idea is, that first the VoiceObjects Server (based on the definition of the Connector object in your VoiceObjects application) will call the set methods of your class to set the input parameters for your back-end access. Then the VoiceObjects Server will call your business method. And lastly it will call the get methods to retrieve the return values (as well as error code and error message).

How it works
Now, let’s take a look at how you can pass parameters from your VoiceObjects application to your Java class, call your business method, and retrieve the return values for further processing in your VoiceObjects application.
First, you need to compile your Java class and create a jar file containing your class (and all your other custom classes that might be needed by your business method).
Now, you create a Connector object in your VoiceObjects application that will use your Java class. The following figure shows an example based on the basic Java sample code above.

Here are the key things you need in your Connector object (also see the documentation of the Connector object the VoiceObjects Object Reference Guide):
- Location: a Resource Locator pointing at the location of your jar file (HTTP or file URL)
- File: the filename of your jar (if you need more than just one jar, you can provide a comma-separated list of filenames – only use comma as a separator – no spaces)
- Class/Port: the fully qualified class name of your Java Bean
- Method: the name of the business method in your Java Bean
- Parameter Set: the list of parameters you want to exchange with your Java Bean. In the Alias/Property field you have to specify the name of the Java Bean property (following the Java Bean conventions). Example: If your get method is called getAResultValue(), in the Alias/Property field you have to specify aResultValue. To pass parameters to your Java code using set methods, you can use Variables, Collections, Expressions, Layers, Scripts, Resource Locators, or constants. In either case you will receive a String on the Java side. Return parameters from your Java code (retrieved using the get methods) can be assigned to Variables, Layers, or Collections. In either case the get method has to return a String (i.e. to return a Collection your get method needs to return the Collection’s XML representation in a String).
When the VoiceObjects Connector object is executed, the VoiceObjects Server performs the following steps:
- Iterate over all parameters in the parameter set and check for each parameter if the Java Bean provides a set method. If so, the set method is called and the value of the parameter field is passed as an argument of type String.
- Call the business method of the Java Bean.
- Iterate over all parameters in the parameter set and check for each parameter if the Java Bean provides a get method. If so, the get method is called and the return value is stored in the corresponding Variable, Layer, or Collection object.
So in our example, this is what happens:

This assumes your Java Bean object has already been instantiated. So the question is: when is it instantiated and is it shared between sessions? The answer is simple: It’s up to you. This can be controlled using the Class persistence level field of the Connector object. Your options are:
- None: A new object is created every time the Connector object is executed.
- Dialog: A new object is created the first time in each dialog session the Connector object is executed. Subsequent connector executions in this session (i.e. in the same dialog) will re-use the existing instance.
- Service: A new object is created the first time the Connector object is executed for your service. Subsequent connector executions for this service will re-use the existing instance (i.e. it will be shared by all sessions for this service).
- Server Instance: A new object is created the first time the Connector object is executed for your VoiceObjects server instance. All subsequent executions of this connector on this server instance will re-use the existing instance (i.e. it will be shared by all sessions for all services on this server instance).
If you are using class persistent level Service or Server Instance you have to make sure that your Java code is thread-safe, as multiple threads will be using the same instance of your Java class in parallel.
A Simple Sample Implementation
Now, let’s take a look at a first sample application. Our sample application is going to ask for a company name and will present us the latest stock quote for this company. Here is our simple dialog structure (the export of the VoiceObjects application can be found in the resources section at the end of this article).

The application is pretty simple – we ask for a company name, retrieve the stock quote using a Connector and say the stock quote.
Our Java Bean provides the following methods for retrieval of the stock quotes (the full source code can be found in the resources section at the end of this article):

So there is one input parameter – companyName – the name (i.e. the stock symbol) of the company, and there is only one return parameter – stockQuote – the last stock quote for the given company name. Out business method is called execute and we also have the usual methods for accessing error code and error message. The Java code of this sample implementation will not connect to a real back-end system. Instead it reads the stock quotes from a properties file on the local disk. To be able to use this connector code, we compile the Java code and create a jar file called sample_java_connector.jar. In our sample implementation the jar file also contains the properties file with the stock quotes (the jar file can also be found in the resources section below).
Based on our Java Bean, this is our Connector object definition:

We just have to make sure that our jar file is available at the location that is defined in Connector Locator. When the Connector object is executed, the setCompanyName method is called (this is the only set method that is called, our Java Bean does not define a set method for stockQuote). Then our business method execute is called, and finally the getStockQuote method is called retrieve the stock quote and assign it to the corresponding Variable object.
This sample implementation only uses data types that do not require any parsing or special processing (i.e. no Collections are used). In the next example we will take a look at how you can work with Collections in your Java connector.
A Sample Implementation using Collections
To illustrate the usage of Collections in a Java connector, we will extend our sample application a bit. It will now fetch multiple stock quotes at once which will then be presented using a List object. Here is our dialog structure (the export of the VoiceObjects application can be found in the resources section at the end of this article):

The basic idea is that it works based on a Collection of stock quotes. The Collection has the following format:
<root>
<row>
<col name=”name”>cmp1</col>
<col name=”fullname”>company1</col>
<col name=”price”>12.34</col>
</row>
<row>
<col name=”name”>cmp2</col>
<col name=”fullname”>company2</col>
<col name=”price”>9.12</col>
</row>
<row>
<col name=”name”>cmp3</col>
<col name=”fullname”>company3</col>
<col name=”price”>543.23</col>
</row>
</root>
There is one row per company containing three columns – the name (i.e. the stock symbol), the full company name, and the stock price.
So for this application, we create a Java Bean that provides the following methods for the retrieval of stock quotes:

The Collection (with empty values for the price column) is set as an input parameter using the method setStockList (just like a Variable or any other VoiceObjects type, on the Java side it appears as a String). The execute method will iterate over all rows of the Collection, determine the latest stock quote (again based on a simple look-up in the properties file) and will fill in the stock quotes into the price column. The method getStockList will return a String containing the Collection’s XML.
To implement the processing of the Collection on the Java side (parsing the XML, manipulating cell contents, generating XML), you can use a utility class that is part of your VoiceObjects installation. The jar file is called ConnectorUtil.jar and resides in the directory Platform/Resources/CGIConnector/WEB-INF/lib/ of your VoiceObjects installation. The class that is relevant here is com.voiceobjects.connector.util.VOCollection. A JavaDoc documentation can be found at Platform /Resources/CGIConnector/doc/. This is the relevant part of the sample code that processes the Collection:

As you can see, the VOCollection class encapsulates the XML processing and allows easy access and manipulation of the Collection.
Here is the VoiceObjects Connector object definition for out sample applicaiton that retrieves multiple stock quotes:

In this case there is only one single parameter – the Collection StockList - that is used as input and output parameter. This is also an example for the usage of more than one jar file (as our code relies on ConnectorUtil.jar). So we have to make sure both jars are available at the location that Connector Locator is pointing to.
Class Loading and Versioning
As your custom Java classes are executed inside the same Java Virtual Machine as the VoiceObjects Server instance, changing your jar files requires a restart of your VoiceObjects Server instances. There is a way to monitor the jar files and to dynamically reload them when they were changed (see VoiceObjects Object Reference Guide). However, this is not recommended in production environments, as it will impact performance.
To avoid the need for restarting, you can use names for jar files and for java packages that reflect the versioning of your Java Connectors. Example:
The jar file could be called sample_java_connector.v1.jar and the package contained in this file could be called com.voxeo.connector.sample.v1. So if you make changes to your Java implementation, you increment the version numbers in your jar file as well as in your package name. You adapt the definition of the VoiceObjects Connector object accordingly and you can deploy a new version of your application without restarting the server instances. The old classes will still be loaded, but they won’t be used anymore.
Pros and Cons of the Java Connector
Here is a quick overview of the Pros and Cons of the Java Connector to help you assess if the Java Connector is the adequate connector type for your use-case (for a direct comparison with the other connector types, please see VoiceObjects Back-End Integration – Part I: Overview).
Pros
- No communication overhead: As the Java Bean is executed in the same JVM as the VoiceObjects Server instance, the communication between these components are plain Java method invocations. There is no additional communication overhead like HTTP requests, assembling and parsing XML, etc. This allows high performance and low latency implementations.
- Simple architecture: The Java Connector does not require any additional components (e.g. application servers, middleware, etc) for back-end integration. This results in a simple 2-tier architecture.
Cons
- Impact on VoiceObjects Server instance: As the Java Bean is executed in the same JVM as the VoiceObjects Server instance, the performance of the custom Java code can have a negative impact on the VoiceObjects Server. This holds for memory consumption (if your Java code requires a significant amount of main memory, you have to take this into account in the memory configuration of your VO Server), impact on garbage collection (if your Java code creates a lot of objects, this might lead to increased garbage collection, which might have a negative impact on the response times of the VO Server), CPU load, and code stability (unstable code might negatively impact the stability of the VoiceObjects Server).
- Class loading for new versions: If your Java code changes frequently, you will either have to restart your VoiceObjects Server instances from time to time to load the new classes or you have to follow the naming convention that includes version numbers in jar and package names to avoid restarting.
Is the Java Connector the right Thing for me?
It is, if
- you want to avoid any communication overhead
- HTTP(S) communication for back-end integration is not allowed
- you want to implement your back-end integration in Java
- you don’t want to have a 3-tier architecture with a dedicated data-access layer
It is not, if
- Java programming is not an option
- your integration code requires a significant amount of main memory, creates a large number of objects, or uses a large number of threads
- your integration code depends on a large number of external jar files
- you are concerned about the quality of your integration code (as bad integration code in a Java Connector can have negative effects on the stability of your VO Server)
- your integration code is not under your control (e.g. if you are building a hosting platform and your clients will write their own back-end integration code)
- your integration code changes frequently
Resources