class JmsAsyncProducer extends JmsProducer {

  @Override
  protected void produce(AdaptrisMessage msg, JmsDestination jmsDest) throws JMSException, CoreException {
    try {
      setupSession(msg);
      Message jmsMsg = translate(msg, jmsDest.getReplyToDestination());
      jmsMsg.setStringProperty(ID_HEADER, msg.getUniqueId());
      
      if (!perMessageProperties()) {
        producerSession().getProducer().send(jmsDest.getDestination(), jmsMsg, getEventHandler());
      } else {
        producerSession().getProducer().send(jmsDest.getDestination(), jmsMsg,
            calculateDeliveryMode(msg, jmsDest.deliveryMode()),
            calculatePriority(msg, jmsDest.priority()),
            calculateTimeToLive(msg, jmsDest.timeToLive()),
            getEventHandler());
      }
      // in real time speed JMSMessageID may not yet be set, therefore we set a header.
      getEventHandler().addUnAckedMessage(jmsMsg.getStringProperty(ID_HEADER), msg);
      // Standard workflow will attempt to execute this after the produce, 
      // let's remove them so it's handled by our async event handler.
      msg.getObjectHeaders().remove(CoreConstants.OBJ_METADATA_ON_SUCCESS_CALLBACK);
      msg.getObjectHeaders().remove(CoreConstants.OBJ_METADATA_ON_FAILURE_CALLBACK);
      
      captureOutgoingMessageDetails(jmsMsg, msg);
      log.info("msg produced to destination [{}]", jmsDest);
    } catch (Throwable ex) {
      ExceptionHelper.rethrowProduceException(ex);
    }
  }

  public  JmsAsyncProducer();

}