![]() | Using XMLink | ![]() ![]() ![]() ![]() |
This chapter describes how to write Java clients to call services in an Oracle Tuxedo application. Alternatively, you can use XML to exchange data as described in Chapter 5, "Using XML to Call Services."
For Java documentation of the XMLink interfaces, refer to the Javadoc portion of the online documentation.
The major topics in this chapter are:
The following diagram illustrates the process described in this chapter for using the CCI interface to execute a Tuxedo service which uses an FML buffer. There are additional record types corresponding to the Oracle Tuxedo buffer types. For more information on record types, refer to "Working with Record Objects."
Figure 4-1 Overview of the steps to create an FML record in XMLink
Getting an Oracle Tuxedo Connection | ![]() |
To get a connection to your Oracle Tuxedo application, you need to create an instance of ConnectionFactory
. This is the starting point for all interactions with XMLink. You then call the method getConnection
on your ConnectionFactory
instance, which returns an object of type Connection
.
Connection factories can have any JNDI binding name you choose. The JDNI binding name is specified when you created the connection factory and can be the same as the connection factory name.
In XMLink 2.0, the following example connects to a Java client and performs JNDI lookup:
// get an initial JNDI naming context
javax.naming.Context initctx = new javax.naming.InitialContext();
// do JNDI lookup to get connection factory
// lookup doesn't return a ConnectionFactory object,
// so a cast is needed
javax.resource.ConnectionFactory cxf =
(javax.resource.ConnectionFactory)
initctx.lookup("ConnectionFactoryName");
// where "ConnectionFactoryName" is the JNDI binding path of a
// predeployed connection factory
// get a connection
Connection cx = cxf.getConnection();
The following code shows the interface ConnectionFactory
. XMLink's implementation class for ConnectionFactory
is ConnectionFactoryImpl
.
public interface ConnectionFactory
extends java.io.Serializable, javax.resource.Referenceable
{
public Connection getConnection ()
throws ResourceException;
public Connection getConnection(ConnectionSpec properties)
throws ResourceException;
public RecordFactory getRecordFactory()
throws ResourceException;
public ResourceAdaptorMetadata getMetaData()
throws ResourceException;
}
Note that objects of class ConnectionFactory
support the basic Java interfaces Serializable
and Referenceable
. Refer to the Java SDK documentation for descriptions of those interfaces.
Calling getConnection
on an object of type ConnectionFactory
returns an object of class Connection
, which represents a connection to the Oracle Tuxedo application.
Calling getConnection
with the ConnectionSpec
parameter allows a client to provide log-in information needed to log in to Oracle Tuxedo. In XMLink, the implementation class for ConnectionSpec
is TuxConnectionSpec
, which provides set
and get
methods for the following properties:
UserName
The above properties correspond to members of Oracle Tuxedo's For container-managed sign-on, use The following code shows the interface Calling Calling The method The return values for these methods provide the name and version information for XMLink.
The Calling the TPINIT
data structure. Refer to Oracle Tuxedo documentation for tpinit(3c)
for more information.
getConnection
without any parameters. The authentication information in this case is supplied by your application server.
Connection
. XMLink's implementation class for Connection
is ConnectionImpl
.
public interface Connection
{
public Interaction createInteraction()
throws ResourceException;
public LocalTransaction getLocalTransaction()
throws ResourceException;
public ConnectionMetaData getMetaData()
throws ResourceException; public ResultSetInfo getResultSetInfo()
throws ResourceException;
public void close()
throws ResourceException;
}createInteraction
on a Connection
instance creates an Interaction
instance associated with the Connection
instance. A single Connection
instance can be associated with multiple Interaction
instances. An Interaction
instance is what is used to access Oracle Tuxedo services. For a description of the methods supported by Interaction
instances, refer to "Calling Oracle Tuxedo Services."
getMetaData
on a Connection
instance returns an object containing information about the Oracle Tuxedo connection represented by that Connection
instance. Such an object supports the following methods:
public String getEISProductName()
public String getEISProductVersion()
public String getUserName() Getting Information about XMLink
getMetaData
provides information about the XMLink product. Calling getMetaData
returns an object of class ResourceAdapterMetadata
. Such objects support the following methods:
public String getAdapterName()
public String getAdapterShortDescription()
public String getAdapterVendorName()
public String getAdapterVersion()
public String getSpecVersion()
public String getInteractionSpecsSupported()
public boolean supportsExecuteWithInputAndOutputRecord()
public boolean supportsExecuteWithInputRecordOnly()
public boolean supportsLocalTransactionDemarcation() Calling getRecordFactory
getRecordFactory
method of the ConnectionFactory
interface returns the RecordFactory
interface. This object can be used to generate Record
instances that, in turn, can be used to hold input data for Oracle Tuxedo services. For information about working with Record
instances, refer to "Working with Application Data."
Specifying Transaction Access
getLocalTransaction
method of the ConnectionFactory
interface returns an object that allows access to Oracle Tuxedo transaction management functions. Each Connection
instance can be associated with only a single LocalTransaction
instance. For a description of the methods supported by the LocalTransaction
interface, refer to "Managing Oracle Tuxedo Transactions."
Managing Oracle Tuxedo Transactions | ![]() |
Access to Oracle Tuxedo transaction demarcation functions is achieved through objects of type LocalTransaction
. You get such an object by calling the getLocalTransaction
method on a Connection
instance. A Connection
instance can only be associated with one LocalTransaction
instance at a time.
A LocalTransaction instance supports the following methods:
public void begin()
public void commit()
public void rollback()
The method begin
corresponds to the Oracle Tuxedo function tpbegin
. The method commit
corresponds to the Oracle Tuxedo function tpcommit
. The method rollback
corresponds to the Oracle Tuxedo function tpabort
.
Warning: Transaction support is available in Oracle Tuxedo version 7.1 and higher.
Calling Oracle Tuxedo Services | ![]() |
Access to Oracle Tuxedo services is provided by objects of type Interaction
. To create Interaction
instances, call the createInteraction
method on a Connection
instance. Each Interaction
instance retains an association with the Connection
instance it was created by.
The following code defines the Interaction
interface:
public interface Interaction
{
public void close() throws ResourceException;
public boolean execute(InteractionSpec ispec,
Record input,
Record output) throws ResourceException;
public Record execute(InteractionSpec ispec,
Record input) throws ResourceException;
}
The getConnection
method returns the Connection
that the Interaction instance is associated with.
The close
method terminates the Interaction
instance. Calling this method also frees all Tuxedo record buffers used during the interaction. However, the Java record still has a copy of the data, so it may in fact be used later for a different interaction.
There are two versions of the execute
method:
Record
instances as arguments: an input Record
and an output Record
. It feeds the data in the input Record
to Oracle Tuxedo and modifies the output Record
provided in the third argument to represent the return buffer from the Oracle Tuxedo service.
execute
method provides only an input Record
as an argument.
In either version of the For a code example, see "Example: Calling Services using Java."
For XMLink, a class called execute
method, the Oracle Tuxedo service being called is specified by the first parameter, which takes an object of type InteractionSpec
.
Understanding the TuxInteractionSpec Interface
TuxInteractionSpec
implements InteractionSpec
and supports the property set needed by XMLink. So in order to call an Oracle Tuxedo service, you must first create a TuxInteractionSpec
object, and then set its properties to determine which Oracle Tuxedo service it specifies.
TuxInteractionSpec
objects support the following properties:
FunctionName
—Specifies the name of the Oracle Tuxedo service.
SYNC_SEND
—Specify for asynchronous Oracle Tuxedo services (to be called with tpacall
and the TPNOREPLY
flag set).
ExecutionTimeout
—Not yet implemented.
The following methods work with these properties:
After creating a new public void setFunctionName(string name)
public string getFunctionName()
public void setInteractionVerb(int mode)
public int getInteractionVerb()
public void setExecutionTimeout(int milliseconds)
public int getExecutionTimeout()InteractionSpec
instance:
set
methods to identify it as representing a particular Oracle Tuxedo service.
For a code example, see "Example: Calling Services using Java."
Working with Application Data | ![]() |
Oracle Tuxedo applications send and receive data using typed buffers, which allows the Oracle Tuxedo platform to transfer data between different operating systems. XMLink automatically converts data provided to it in the form of a Java Record
instance to the appropriate Oracle Tuxedo buffer type for the service being called, and then converts the return data into a Java Record
instance.
XMLink defines four record classes corresponding to the Oracle Tuxedo buffer types and one class for Prolifics's Panther for JetNet buffer type.
XMLink record types | |
---|---|
Oracle Tuxedo buffer types |
|
|
|
|
|
|
|
|
|
Panther for JetNet buffer type |
|
JAMFLEX |
|
To call a Tuxedo service, you must create a Record
object of the type corresponding to the buffer type the service takes as its argument. You get Record
instances by calling the methods of a RecordFactory
interface.
Calling getRecordFactory
on a ConnectionFactoryImpl
instance returns an instance of RecordFactoryImpl
. RecordFactoryImpl
objects implement the RecordFactory
interface.
The following code defines the RecordFactory
interface:
public interface RecordFactory
public MappedRecord createMappedRecord(String recordName)
throws ResourceException;
public IndexedRecord createIndexedRecord(String recordName)
throws ResourceException;
XMLink's RecordFactoryImpl
class also supports another method:
public Record createRecord(String recordName)
throws ResourceException;
To create an FMLRecord
or FML32Record
instance, use the createMappedRecord
method of a RecordFactory
instance. The createMappedRecord
method takes a string argument used to identify what kind of record should be created. Use the strings "FML"
, "FML32"
or "JAMFLEX"
as the argument to the createMappedRecord
method to create an FMLRecord
, FML32Record
or JAMFLEXRecord
instance, respectively.
To create a StringRecord
or CArrayRecord
instance, use the createRecord
method of a RecordFactory
interface. As with the createMappedRecord
method, the method's string argument is used to determine which type of record to return. Use the strings "STRING"
and "CARRAY"
as the argument to the createRecord
method to create a StringRecord
or CArrayRecord
instance, respectively.
The createMappedRecord
method returns a MappedRecord
and the createRecord
returns a Record
. Since what you actually want are instances of FMLRecord
, FML32Record
, StringRecord
, CArrayRecord
or JAMFLEXRecord
, you will have to cast the return values from createMappedRecord
and createRecord
to the appropriate types.
For example:
// create an FML32Record instance, using a previously
// acquired RecordFactory instance called rcf
FML32Record fml32r = (FML32Record)
rcf.createMappedRecord("FML32");
// create a StringRecord instance
StringRecord strr = (StringRecord) rcf.createRecord("STRING");
XMLink client code will not typically need to use the createIndexedRecord
method. RecordFactoryImpl
objects do implement this method to create the ArrayRecord
objects returned by the getField
method of FMLRecord
and FML32Record
objects. For more information, see "FMLRecord and FML32Record Objects."
The following code defines the Record
interface:
public interface Record extends Cloneable
{
public String getRecordName();
public void setRecordName(String Name);
public void setRecordShortDescription(String description);
pubic String getRecordShortDescription();
public boolean equals(Object other);
public int hashcode();
Public Object clone() throws CloneNotSupportedException;
}
The Record
objects supported by XMLink, objects of class FMLRecord
, FML32Record
, CArrayRecord
, StringRecord
and JAMFLEXRecord
all support the methods listed above. In addition they also support methods specific to themselves, and client code that accesses them will primarily do so by means of those specific methods.
FMLRecord
and FML32Record
objects are instances of MappedRecord
, and therefore implement the methods of the Map
interface in addition to those of Record
. Specifically, these classes extend the standard Java class HashMap
.
However, underlying each instance of FMLRecord
or FML32Record
is a Tuxedo FML
buffer or FML32
buffer. FML
buffers are made up of "fields". Client code should NOT use the methods of the Map
interface to modify the contents of an FMLRecord
or an FML32Record
, because to do so will put the Record
out of sync with the Oracle Tuxedo FML
buffer that it represents. To update the contents of an FMLRecord
or an FML32Record
, use the following method, that is specific to these classes, and define interaction at the level of FML
fields:
public void addIn(String name, String value)
The addIn
method is used to populate the fields in an FML
buffer. The name
parameter is the name of the field to which a value is to be added. The value is added as a new occurrence to the field. To add multiple occurrences to a field, call addIn
repeatedly with a single field name.
Using the following addIn
method allows you to create embedded FML for Oracle Tuxedo versions 7.1+ which contain support for this feature:
public void addIn(String name, FML32Record value)
Note that the field values are all input as strings. The underlying FML
buffer will be populated with whatever data types are appropriate to the FML
file definition, based on the field names. If any conversion is needed, it is performed by Tuxedo.
The following sample illustrates one method of getting data after calling execute()
.
Warning:
The getField
method is for internal use only. Use this example as a basis for getting data from FML buffers.
//Call tuxedo service
rcout = (FMLRecord)iact.execute(tuxl,rc);
//Get the fields from the Record object.
Iterator it = rcout.entrySet().iterator();
while ( it.hasNext()) {
Map.Entry me = (Map.Entry)it.next();
String fieldName = (String)me.getKey();
IndexedRecord fieldValue = (IndexedRecord)me.getValue();
Iterator it2 = fieldValue.iterator();
System.out.println(fieldName);
while (it2.hasNext())
{
System.out.println(" " + it2.next());
}
}
Note:
In this example, if rcout
were an FML32Record
, it might contain embedded FML. In that case, it2.next()
might return an FML32Record
, rather than a string and different processing would be required.
In addition to the basic methods of the Record
interface, as listed above, CArrayRecord
and StringRecord
objects support the following methods:
public String getContents()
public void addIn (String name, String value)
The getContents
method returns the contents of the Record
.
The addIn
method takes two String arguments, the value of the second argument will be appended to the Record
's contents. The first argument is ignored. A Record
can be filled either by one single call to addIn
or by a series of such calls.
For CArrayRecord
, the output record used for InteractionImpl.execute()
must contain initial data. For example:
CArrayRecord out = (CArrayRecord)rcf.createRecord("CARRAY");
out.addIn("", "|");
Java strings are in Unicode. By default, XMLink passes to Tuxedo only the low order byte of each Unicode character. For characters in English and other European languages, this is sufficient since only the low order byte is significant.
Since other languages may need additional support, each of XMLink's Record
classes offers setEncoding()
and getEncoding()
methods. The default encoding is ISO-8859-1
, which is a single byte per character encoding. A multibyte encoding, such as UTF8,
can be used for foreign characters. The Tuxedo server must be able to support and decode/encode according to the specified encoding setting.
Example: Calling Services using Java | ![]() |
Here is an sample outline of client code combining the connection code from earlier in the chapter with an example of interacting with a Connection
instance to call a Tuxedo service:
// get an initial JNDI naming context
javax.naming.Context initctx = new javax.naming.InitialContext();
// do JNDI lookup to get connection factory
// lookup doesn't return a ConnectionFactory object,
// so a cast is needed
javax.resource.ConnectionFactory cxf =
(javax.resource.ConnectionFactory)
initctx.lookup("ConnectionFactoryName");
// where "ConnectionFactoryName" is the JNDI binding path of a
// predeployed connection factory
// get a connection
Connection cx = cxf.getConnection();
// cxf represents previously acquired ConnectionFactory instance
// first get a LocalTransaction instance
LocalTransaction ltx = cx.getLocalTransaction();
// mark the beginning of a Tuxedo transaction
ltx.begin();
// get an Interaction instance
Interaction iact = cx.createInteraction();
// create a new InteractionSpec object
TuxInteractionSpec tux1 = new TuxInteractionSpec;
// set the properties of the InteractionSpec instance
// note that InteractionVerb defaults to SYNC_SEND_RECEIVE,
// so the second line below isn't really necessary
tux1.setFunctionName("TUXServiceName");
tux1.setInteractionVerb(SYNC_SEND_RECEIVE);
tux1.setExecutionTimeout(1000)
// get a RecordFactory instance
RecordFactory rcf = cxf.getRecordFactory()
// create a Record Instance to hold input data
FMLRecord rc = (FMLRecord) rcf.createMappedRecord("FML");
// Populate Record instance with data
rc.addIn ("FirstField", "value1");
rc.addIn ("FirstField", "value2");
rc.addIn ("FirstField", "value3");
rc.addIn ("SecondField", "anothervalue");
// and so forth
// call the TUXEDO service
MappedRecord ret = iact.execute(tux1, rc);
// call other services in the transaction by creating
// new InteractionSpec instances and input records
// and calling execute as needed
// mark the end of the TUXEDO transaction
ltx.commit();
//close the InteractionInstance
iact.close();