Using advanced queueing v42.7.3.1

New Feature

Advanced queueing is available in JDBC 42.3.2.1 and later.

EDB Postgres Advanced Server advanced queueing provides message queueing and message processing for the EDB Postgres Advanced Server database. User-defined messages are stored in a queue, and a collection of queues is stored in a queue table. You must first create a queue table before creating a queue that depends on it.

On the server side, procedures in the DBMS_AQADM package create and manage message queues and queue tables. Use the DBMS_AQ package to add or remove messages from a queue or register or unregister a PL/SQL callback procedure. For more information about DBMS_AQ and DBMS_AQADM, see the DBMS_AQ.

On the client side, the application uses EDB-JDBC driver's JMS API to enqueue and dequeue message.

Enqueueing or dequeueing a message

For more information about using EDB Postgres Advanced Server's advanced queueing functionality, see Built-in packages.

Server-side setup

To use advanced queueing functionality on your JMS-based Java application perform following steps in EDB-PSQL or EDB-JDBC:

  1. Create a user-defined message type, which may be one of the standard JMS message types. However, EDB JDBC also supports any user-defined types. These types will be covered in detail in the upcoming sections.
  2. Create a queue table specifying the payload type. This type will typically be the one created in step 1.
  3. Create a queue using the queue table created in the previous step.
  4. Start the queue on the database server.
  5. You have the option to use either EDB-PSQL or EDB-JDBC JMS API in your Java application.

Using EDB-PSQL

Invoke EDB-PSQL and connect to the EDB Postgres Advanced Server host database. Use the following SPL commands at the command line.

Creating a user-defined type

To specify a RAW data type, create a user-defined type. This example creates a user-defined type named as mytype.

CREATE OR REPLACE TYPE mytype AS (code INT, project TEXT, manager VARCHAR(10));

Create the queue table

A queue table can hold multiple queues with the same payload type. This example creates a table named MSG_QUEUE_TABLE.

EXEC DBMS_AQADM.CREATE_QUEUE_TABLE
      (queue_table => 'MSG_QUEUE_TABLE',
       queue_payload_type => 'mytype',
       comment => 'Message queue table');
END;

Create the queue

This example creates a queue named MSG_QUEUE in the table MSG_QUEUE_TABLE.

EXEC DBMS_AQADM.CREATE_QUEUE 
      (queue_name => 'MSG_QUEUE', 
       queue_table => 'MSG_QUEUE_TABLE', 
       comment => 'This queue contains pending messages.');

Start the queue

Once the queue is created, invoke the following SPL code at the command line to start a queue in the EDB database.

EXEC DBMS_AQADM.START_QUEUE(queue_name => 'MSG_QUEUE');
commit;

Using EDB-JDBC JMS API

Tip

The following sequence of steps is required only if you want to create message types, queue table and queue programmatically. If the message types, queue table, and queue are created using EDB-PSQL then you can use the standard JMS API.

The following JMS API calls perform the same steps performed using EDB-PSQL to:

  • Connect to the EDB Postgres Advanced Server database
  • Create the user-defined type
  • Create the queue table and queue
  • Start the queue
edbJmsFact = new EDBJmsConnectionFactory("localhost", 5444, "edb", "edb", "edb");

conn = (EDBJmsQueueConnection) edbJmsFact.createQueueConnection();
                        
session = (EDBJmsQueueSession) conn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE);            
            
String sql = "CREATE OR REPLACE TYPE mytype AS (code int, project TEXT);";
UDTType udtType = new UDTType(conn.getConn(), sql, "mytype");
Operation operation = new UDTTypeOperation(udtType);
operation.execute();

queueTable = session.createQueueTable(conn.getConn(), "MSG_QUEUE_TABLE", "mytype", "Message queue table");
            
Queue queue1 = new Queue(conn.getConn(), "MSG_QUEUE", "MSG_QUEUE_TABLE", "Message Queue");
operation = new QueueOperation(queue1);
operation.execute();

queue = (EDBJmsQueue) session.createQueue("MSG_QUEUE");
queue.setEdbQueueTbl(queueTable);
            
queue.start();

Setting up JMS application

After creating the queue table and queue for the message types and starting the queue, you can follow these steps to set up your JMS Application:

  1. Create a Connection Factory.
  2. Create a Connection using the connection factory.
  3. Create a Session using the connection.
  4. Get the Queue from the session.
  5. Create a message producer using the session and queue.
    1. Send messages.
  6. Create a message consumer using the session and queue.
    1. Receive messages.

Connection factory

The Connection Factory is used to create connections. EDBJmsConnectionFactory is an implementation of ConnectionFactory and QueueConnectionFactory, used to create Connection and QueueConnection. A connection factory can be created using one of the constructors of the EDBJmsConnectionFactory class. All three constructors can be used to create either a ConnectionFactory or QueueConnectionFactory.

//Constructor with connection related properties.
public EDBJmsConnectionFactory(String host, int port, String database, 
     String username, String password);
//Constructor with connection string, user name and password.
public EDBJmsConnectionFactory(String connectionString, 
     String username, String password);
//Constructor with SQL Connection.
public EDBJmsConnectionFactory(java.sql.Connection connection);

This example shows how to create a ConnectionFactory using an existing java.sql.Connection:

javax.jms.ConnectionFactory connFactory = new EDBJmsConnectionFactory(connection);

This example shows how to create a QueueConnectionFactory using a connection string, username, and password:

javax.jms.QueueConnectionFactory connFactory = new EDBJmsConnectionFactory
   ("jdbc:edb//localhost:5444/edb", "enterprisedb", "edb");

Connection

A Connection is a client's active connection that can be created from the ConnectionFactory and used to create sessions. EDBJmsConnection is an implementation of Connection, while EDBJmsQueueConnection is an implementation of QueueConnection and extends EDBJmsConnection. A Connection can be created using ConnectionFactory, while QueueConnection can be created from QueueConnectionFactory.

This example shows how to create a Connection and a QueueConnection:

//Connection from ConnectionFactory. Assuming connFactory is ConnectionFactory.
javax.jms.Connection connection = connFactory.createConnection();

////Connection from QueueConnectionFactory. Assuming connFactory is QueueConnectionFactory.
javax.jms.QueueConnection queueConnection = connFactory.createQueueConnection();

A connection must be started in order for the consumer to receive messages. On the other hand, a producer can send messages without starting the connection. To start a connection, use the following code:

queueConnection.start();

A connection can be stopped at any time to cease receiving messages, and can be restarted when needed. However, a closed connection cannot be restarted.

To stop and close the connection, use the following code:

queueConnection.stop();
queueConnection.close();

Session

The Session in EDBJms is used for creating producers and consumers, and for sending and receiving messages. EDBJmsSession implements the basic Session functionality, while EDBJmsQueueSession extends EDBJmsSession and implements QueueSession. A session can be created from a Connection.

This example shows how to create a Session and a QueueSession:

// Session
javax.jms.Session session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
// QueueSession
javax.jms.QueueSession session = queueConnection.createQueueSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);

A Session or QueueSession is also used to create queues. It's important to note that in this context, "creating a queue" does not refer to physically creating the queue. As discussed earlier, the queue needs to be created and started as part of the server-side setup. In this context, creating a queue means getting the queue, related queue table, and payload type that have already been created.

This example shows how to create a queue:

javax.jms.Queue queue = session.createQueue("MSG_QUEUE");

Message producer

A message producer is responsible for creating and sending messages. It is created using a session and queue. EDBJmsMessageProducer is an implementation of MessageProducer, but in most cases, you will be using the standard MessageProducer.

This example shows how to create a message producer, create a message, and send it. Creating messages of different types will be discussed in the following sections.

javax.jms.MessageProducer messageProducer = session.createProducer(queue);

javax.jms.Message msg = session.createMessage();
msg.setStringProperty("myprop1", "test value 1");

messageProducer.send(msg);

Message consumer

A Message consumer is used to receive messages. It is created using a session and a queue. EDBJmsMessageConsumer is an implementation of MessageConsumer, but you will most often use the standard MessageConsumer.

This example shows how to create a message consumer and receive a message:

javax.jms.MessageConsumer messageConsumer = session.createConsumer(queue);
      
javax.jms.Message message = messageConsumer.receive();

Message acknowledgement

Acknowledgement of messages is controlled by the two arguments to the createSession() and createQueueSession() methods:

EDBJmsConnection.createSession(boolean transacted, int acknowledgeMode)

EDBJmsQueueConnection.createQueueSession(boolean transacted, int acknowledgeMode)

If the first argument is true, it indicates that the session mode is transacted, and the second argument is ignored. However, if the first argument is false, then the second argument comes into play, and the client can specify different acknowledgment modes. These acknowledgment modes include,

  • Session.AUTO_ACKNOWLEDGE
  • Session.CLIENT_ACKNOWLEDGE
  • Session.DUPS_OK_ACKNOWLEDGE

The following sections describe different modes of acknowledgement:

Transacted session

In transacted sessions, messages are both sent and received during a transaction. These messages are acknowledged by making an explicit call to commit(). If rollback() is called, all received messages will be marked as not acknowledged.

A transacted session always has an active transaction. When a client calls the commit() or rollback() method, the current transaction is either committed or rolled back, and a new transaction is started.

This example explains how the transacted session works:

    MessageProducer messageProducer = (MessageProducer) session.createProducer(queue);

	//Send a message in transacted session and commit it.

	//Send message
	TextMessage msg1 = session.createTextMessage();
	String messageText1 = "Hello 1";
	msg1.setText(messageText1);
	messageProducer.send(msg1);

	//Commit the transaction.
	session.commit();

	//Now we have one message in the queue.
	
	//Next, we want to send and receive in the same transaction.

	MessageConsumer messageConsumer = (MessageConsumer) session.createConsumer(queue);

	//Send a Message in transaction.
	TextMessage msg2 = session.createTextMessage();
	String messageText2 = "Hello 2";
	msg2.setText(messageText2);
	messageProducer.send(msg2);

	//Receive message in the same transaction. There should be 1 message available.
	Message message1 = messageConsumer.receive();
	TextMessage txtMsg1 = (TextMessage) message1;

	//Send another Message in transaction.
	TextMessage msg3 = session.createTextMessage();
	String messageText3 = "Hello 3";
	msg3.setText(messageText3);
	messageProducer.send(msg3);

	//Commit the transaction.
	//This should remove the one message we sent initially and received above and send 2 messages.
	session.commit();

    //2 messages are in the queue so we can receive these 2 messages.

	//Receive 1
	Message message2 = messageConsumer.receive();
	TextMessage txtMsg2 = (TextMessage) message2;

	//Receive 2
	Message message3 = messageConsumer.receive();
	TextMessage txtMsg3 = (TextMessage) message3;

	//Commit the transaction. This will consume the two messages.
	session.commit();

	//Receive should fail now as there should be no messages available.
	Message message4 = messageConsumer.receive();
	//message4 will be null here.

AUTO_ACKNOWLEDGE mode

If the first argument to createSession() or createQueueSession() is false and the second argument is Session.AUTO_ACKNOWLEDGE, the messages are automatically acknowledged.

DUPS_OK_ACKNOWLEDGE mode

This mode instructs the session to lazily acknowledge the message, and it is okay if some messages are redelivered. However, in EDB JMS, this option is implemented the same way as Session.AUTO_ACKNOWLEDGE, where messages will be acknowledged automatically.

CLIENT_ACKNOWLEDGE mode

If the first argument to createSession() or createQueueSession() is false and the second argument is Session.CLIENT_ACKNOWLEDGE, the messages are acknowledged when the client acknowledges the message by calling the acknowledge() method on a message. Acknowledging happens at the session level, and acknowledging one message will cause all the received messages to be acknowledged.

For example, if we send 5 messages and then receive the 5 messages, acknowledging the 5th message will cause all 5 messages to be acknowledged.

    MessageProducer messageProducer = (MessageProducer) session.createProducer(queue);

  	//Send 5 messages
  	for(int i=1; i<=5; i++) {
		TextMessage msg = session.createTextMessage();
		String messageText = "Hello " + i;
		msg.setText(messageText);
		messageProducer.send(msg);
	}

	MessageConsumer messageConsumer = (MessageConsumer) session.createConsumer(queue);
      
	//Receive 4
	for(int i=1; i<=4; i++) {
		Message message = messageConsumer.receive();
		TextMessage txtMsg = (TextMessage) message;
	}

	//Receive the 5th message
	Message message5 = messageConsumer.receive();
	TextMessage txtMsg5 = (TextMessage) message5;

	//Now acknowledge it and all the messages will be acknowledged.
	txtMsg5.acknowledge();

	//Try to receive again. This should return null as there is no message available.
	Message messageAgain = messageConsumer.receive();

Message types

EDB-JDBC JMS API supports the following message types and can be used in a standard way:

Message typeJMS type
aq$_jms_messagejavax.jms.Message
aq$_jms_text_messagejavax.jms.TextMessage
aq$_jms_bytes_messagejavax.jms.BytesMessage
aq$_jms_object_messagejavax.jms.ObjectMessage

Please note that the corresponding payload types (user-defined types) are not pre-defined and must be created by the user before configuring the queue table. This is discussed in the upcoming sections.

You can specify schema-qualified user-defined types, but the property types and message types must be in the same schema.

Message properties

All of the above-mentioned message types support setting and getting message properties. Before creating the actual message type, you must create the corresponding user-defined type for message properties.

This example shows how to create the user-defined type for message properties:

CREATE OR REPLACE TYPE AQ$_JMS_USERPROPERTY
AS object
(
    NAME VARCHAR2(100),
    VALUE VARCHAR2(2000)
);

All primitive types of message properties are supported.

TextMessage

Text messages can be sent using the TextMessage interface. EDBTextMessageImpl is an implementation of TextMessage, but for most cases, you will be using the standard TextMessage.

Before using the text message, it is necessary to create a user-defined type for it. This example shows how to create the user-defined type for TextMessage:

CREATE OR REPLACE TYPE AQ$_JMS_TEXT_MESSAGE AS object(PROPERTIES AQ$_JMS_USERPROPERTY[], STRING_VALUE VARCHAR2(4000));

Once the user-defined type is created, you can then proceed to create the queue table using this type:

EXEC DBMS_AQADM.CREATE_QUEUE_TABLE (queue_table => 'MSG_QUEUE_TABLE', queue_payload_type => 'AQ$_JMS_TEXT_MESSAGE', comment => 'Message queue table');

After setting up the queue table, you can send and receive TextMessages using the standard procedure outlined in the Java code snippet:

MessageProducer messageProducer = (MessageProducer) session.createProducer(queue);
// Create text message
TextMessage msg = session.createTextMessage();
String messageText = "Hello there!";
msg.setText(messageText);
msg.setStringProperty("myprop1", "test value 1");
// Send message
messageProducer.send(msg);

MessageConsumer messageConsumer = (MessageConsumer) session.createConsumer(queue);
// Receive Message
Message message = messageConsumer.receive();
TextMessage txtMsg = (TextMessage) message;
System.out.println(txtMsg.getText());
System.out.println(txtMsg.getStringProperty("myprop1"));

BytesMessage

The BytesMessage is used to send a stream of bytes. EDBBytesMessageImpl is an implementation of BytesMessage, but in most cases, you will use the standard BytesMessage. Before using the bytes message, a user-defined type must be created.

This example shows how to create the user-defined type for BytesMessage:

CREATE OR REPLACE TYPE AQ$_JMS_BYTES_MESSAGE AS OBJECT (PROPERTIES AQ$_JMS_USERPROPERTY[], RAW_VALUE CLOB);

Now, BytesMessage can be sent and received in the standard way.

This example shows how to create and use a BytesMessage in Java:

MessageProducer messageProducer = (MessageProducer) session.createProducer(queue);
BytesMessage msg = session.createBytesMessage();
String messageText = "Hello there!";
msg.writeBytes(messageText.getBytes());
messageProducer.send(msg);

MessageConsumer messageConsumer = (MessageConsumer) session.createConsumer(queue);
Message message = messageConsumer.receive();
BytesMessage byteMsg = (BytesMessage) message;
byteMsg.reset();
byte[] bytes = new byte[(int) byteMsg.getBodyLength()];
byteMsg.readBytes(bytes);
System.out.println(new String(bytes));

ObjectMessage

An ObjectMessage is used to send a serializable object as a message. EDBObjectMessageImpl is an implementation of ObjectMessage, but the standard ObjectMessage is most commonly used.

Before using the ObjectMessage, it is necessary to create the user-defined type for the object message.

This example shows how to create the user-defined type for ObjectMessage:

CREATE OR REPLACE TYPE AQ$_JMS_OBJECT_MESSAGE AS object(PROPERTIES AQ$_JMS_USERPROPERTY[], OBJECT_VALUE CLOB);

For example we have the following serializable Java class:

import java.io.Serializable;

public class Emp implements Serializable {
    private int id;
    private String name;
    private String role;

    // Getter and setter methods
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }
}

This example shows how to use ObjectMessage to send a message containing an object of this class:

MessageProducer messageProducer = (MessageProducer) session.createProducer(queue);

// Create object message
ObjectMessage msg = session.createObjectMessage();
Emp emp = new Emp();
emp.setId(1);
emp.setName("Joe");
emp.setRole("Manager");
msg.setObject(emp);

// Send message
messageProducer.send(msg);

MessageConsumer messageConsumer = (MessageConsumer) session.createConsumer(queue);

// Receive Message
Message message = messageConsumer.receive();
ObjectMessage objMsg = (ObjectMessage) message;
Emp empBack = (Emp) objMsg.getObject();
System.out.println("ID: " + empBack.getId());
System.out.println("Name: " + empBack.getName());
System.out.println("Role: " + empBack.getRole());

Message

A Message can be used to send a message with only properties and no body. EDBMessageImpl is an implementation of a Message, but you will most often use the standard Message. Before using a message, it is required to create a user-defined type.

This example shows how to create the user-defined type for Message:

CREATE OR REPLACE TYPE AQ$_JMS_MESSAGE AS object(PROPERTIES AQ$_JMS_USERPROPERTY[]);

This example shows how to send a message that contains only properties and no body:

MessageProducer messageProducer = (MessageProducer) session.createProducer(queue);
// Create message. 
Message msg = session.createMessage();
msg.setStringProperty("myprop1", "test value 1");
msg.setStringProperty("myprop2", "test value 2");
msg.setStringProperty("myprop3", "test value 3");
// Send message
messageProducer.send(msg);
MessageConsumer messageConsumer = (MessageConsumer) session.createConsumer(queue);
// Receive Message 
message = messageConsumer.receive();
System.out.println("myprop1: " + message.getStringProperty("myprop1"));
System.out.println("myprop2: " + message.getStringProperty("myprop2"));
System.out.println("myprop3: " + message.getStringProperty("myprop3"));

Non-standard message

EDB-JDBC JMS allows users to send and receive non-standard messages that are fully controlled by the API user. These messages do not support the setting and getting of properties. The process involves creating a user-defined type and setting it as the payload for the queue table.

This example shows how to create a Java Bean corresponding to the type you created:

package mypackage;
import com.edb.jms.common.CompareValue;
import java.util.ArrayList;
public class MyType extends com.edb.aq.UDTType {
    private Integer code;
    private String project;
    private String manager;
    public MyType() {
    }
    /**
     * @param code the code to set
     */
    @CompareValue(0)
    public void setCode(Integer code) {
      this.code = code;
    }
    /**
     * @return the code
     */
    public Integer getCode() {
      return code;
    }
    /**
     * @param project the project to set
     */
    @CompareValue(1)
    public void setProject(String project) {
      this.project = project;
    }
    /**
     * @return the project
     */
    public String getProject() {
      return project;
    }
    @CompareValue(2)
    public void setManager(String manager) {
      this.manager = manager;
    }
    public String getManager() {
      return manager;
    }
    public String valueOf() {
        StringBuilder sql = new StringBuilder("CREATE TYPE ");
        sql.append(getName() + " ");
        sql.append("AS (");
        sql.append("code int, ");
        sql.append("project TEXT);");
        return sql.toString();
    }
  /**
   * Override this method and call getter methods in the same order as in CREATE TYPE statement.
   * CREATE OR REPLACE TYPE mytype AS object (code int, project text, manager varchar(10))
   * @return object array containing parameters.
   */
  @Override
  public Object[] getParamValues() {
    ArrayList<Object> params = new ArrayList<>();
    params.add(getCode());
    params.add(getProject());
    params.add(getManager());
    return params.toArray();
  }
}
Note
  • To create a user-defined class, it must extend the com.edb.aq.operations.UDTType class and override the getParamValues() method. In this method, you should add the attribute values to an ArrayList in the same order as they appear in the CREATE TYPE SQL statement in the database.
  • Additionally, make sure to use the annotation @CompareValue(0) with setter methods, as this specifies the order of methods when using the reflection API to reconstruct the object after dequeuing the message from the queue.

Failure to meet these requirements may result in errors.

This example shows how to send an object of this class as a message:

messageProducer = (EDBJmsMessageProducer) session.createProducer(queue);
      MyType udtType1 = new MyType();
      udtType1.setProject("Test Project");
      udtType1.setManager("Joe");
      udtType1.setCode(321);
      udtType1.setName("mytype"); //type name used in "CREATE TYPE"
      messageProducer.send(udtType1);

This example shows how to receive this object as a message:

messageConsumer = (EDBJmsMessageConsumer) session.createConsumer(queue);

Message message = messageConsumer.receive();

MyType myt = (MyType) message;
System.out.println("Code: "+ myt.getCode());
System.out.println("Project: "+ myt.getProject());
System.out.println("Manager: "+ myt.getManager());

InnermostCustom.java:

package mypackage;

import com.edb.aq.UDTType;
import com.edb.jms.common.CompareValue;

import java.util.ArrayList;

public class InnermostCustom extends UDTType {

    public InnermostCustom() {
    }

    private String testing_field_1;

    public String getTesting_field_1() {
        return testing_field_1;
    }

    @CompareValue(0)
    public void setTesting_field_1(String testing_field_1) {
        this.testing_field_1 = testing_field_1;
    }
  @Override
  public Object[] getParamValues(){
    ArrayList<Object> params = new ArrayList<Object>();
    params.add(getTesting_field_1());
    return params.toArray();
  }
}

InnerCustom.java

package mypackage;

import com.edb.aq.UDTType;
import com.edb.jms.common.CompareValue;

import java.util.ArrayList;

public class InnerCustom  extends UDTType {

    public InnerCustom() {
    }

    private String testing_field_1;
    private InnermostCustom innermostCustom;

    public String getTesting_field_1() {
        return testing_field_1;
    }

    @CompareValue(0)
    public void setTesting_field_1(String testing_field_1) {
        this.testing_field_1 = testing_field_1;
    }

  public InnermostCustom getInnermostCustom() {
    return innermostCustom;
  }

  @CompareValue(1)
  public void setInnermostCustom(InnermostCustom innermostCustom) {
    this.innermostCustom = innermostCustom;
  }
  @Override
  public Object[] getParamValues(){
    ArrayList<Object> params = new ArrayList<Object>();
    params.add(getTesting_field_1());
    params.add(getInnermostCustom());
    return params.toArray();
  }
}

CustomType.java

package mypackage;

import com.edb.aq.UDTType;
import com.edb.jms.common.CompareValue;

import java.util.ArrayList;

public class CustomType extends UDTType {

    private String testing_field;
    private InnerCustom innerCustom;

    public String getTesting_field() {
        return testing_field;
    }

    @CompareValue(0)
    public void setTesting_field(String testing_field) {
        this.testing_field = testing_field;
    }

    public InnerCustom getInnerCustom() {
        return innerCustom;
    }

    @CompareValue(1)
    public void setInnerCustom(InnerCustom innerCustom) {
        this.innerCustom = innerCustom;
    }

    public CustomType() {

    }

    public Object[] getParamValues(){
        ArrayList<Object> params = new ArrayList<Object>();
        params.add(getTesting_field());
        params.add(getInnerCustom());
        return params.toArray();
    }
}

This example shows how to read such nested types:

      EDBJmsMessageProducer messageProducer = (EDBJmsMessageProducer) session.createProducer(queue_1);

      InnermostCustom innermostCustom = new InnermostCustom();
      innermostCustom.setTesting_field_1("Innermost set");
      innermostCustom.setName("innermostCustom");

      InnerCustom innerCustom = new InnerCustom();
      innerCustom.setTesting_field_1("Inner set");
      innerCustom.setInnermostCustom(innermostCustom);
      innerCustom.setName("innercustom");

      CustomType customType = new CustomType();
      customType.setTesting_field("EDB");
      customType.setInnerCustom(innerCustom);
      customType.setName("custom_type");

      messageProducer.send(customType);

      EDBJmsMessageConsumer messageConsumer = (EDBJmsMessageConsumer) session.createConsumer(queue_1);

      Message message = messageConsumer.receive();

      CustomType myType = (CustomType) message;
      InnerCustom innerCustom_1 = myType.getInnerCustom();
      InnermostCustom innermostCustom1 = innerCustom_1.getInnermostCustom();

      System.out.println("Outer type test field: " + myType.getTesting_field());
      System.out.println("Inner type test field: " + innerCustom_1.getTesting_field_1());
      System.out.println("Most Inner type test field: " + innermostCustom1.getTesting_field_1());