bool run_multitopic_test(const Publisher_var& pub, const Subscriber_var& sub)
{
  DomainParticipant_var sub_dp = sub->get_participant();

  // Writer-side setup

  Writer<LocationInfo> location(pub, "Location", sub_dp);
  Writer<PlanInfo> flightplan(pub, "FlightPlan", sub_dp);
  Writer<MoreInfo> more(pub, "More", sub_dp);
  Writer<UnrelatedInfo> unrelated(pub, "Unrelated", sub_dp);
  MoreInfoDataWriter_var midw = MoreInfoDataWriter::_narrow(more.dw_);

  // Reader-side setup

  ResultingTypeSupport_var ts_res = new ResultingTypeSupportImpl;
  check(ts_res->register_type(sub_dp, ""));
  CORBA::String_var type_name = ts_res->get_type_name();
  MoreInfo mi;
  DDS::DataReader_var dr;

  for (int i = 0; i < N_ITERATIONS; ++i) {

    MultiTopic_var mt = sub_dp->create_multitopic("MyMultiTopic", type_name,
      "SELECT flight_name, x, y, z AS height, more, misc "
      "FROM Location NATURAL JOIN FlightPlan NATURAL JOIN More NATURAL JOIN "
      "Unrelated WHERE height < 1000 AND x<23", StringSeq());
    if (!mt) return false;
    dr = sub->create_datareader(mt, DATAREADER_QOS_DEFAULT,
                                0, DEFAULT_STATUS_MASK);

    // Write samples (Location)

    waitForMatch(location.dw_);
    LocationInfoDataWriter_var locdw =
      LocationInfoDataWriter::_narrow(location.dw_);
    LocationInfo sample = {100, 97, 23, 2, 3}; // filtered out (x < 23)
    ReturnCode_t ret = locdw->write(sample, HANDLE_NIL);
    if (ret != RETCODE_OK) return false;
    LocationInfo sample2 = {100, 96, 1, 2, 3000}; // filtered out (height < 1000)
    ret = locdw->write(sample2, HANDLE_NIL);
    if (ret != RETCODE_OK) return false;
    LocationInfo sample3 = {100, 99, 1, 2, 3};
    ret = locdw->write(sample3, HANDLE_NIL);
    if (ret != RETCODE_OK) return false;
    LocationInfo sample3_5 = {100, 98, 4, 5, 6};
    ret = locdw->write(sample3_5, HANDLE_NIL);
    if (ret != RETCODE_OK) return false;

    // Write samples (FlightPlan)

    waitForMatch(flightplan.dw_);
    PlanInfoDataWriter_var pidw = PlanInfoDataWriter::_narrow(flightplan.dw_);
    PlanInfo sample4;
    sample4.flight_id1 = 100;
    sample4.flight_id2 = 99;
    sample4.flight_name = "Flight 100-99";
    sample4.tailno = "N12345";
    ret = pidw->write(sample4, HANDLE_NIL);
    if (ret != RETCODE_OK) return false;
    PlanInfo sample4_1(sample4);
    sample4_1.flight_id2 = 97;
    sample4_1.flight_name = "Flight 100-97";
    ret = pidw->write(sample4_1, HANDLE_NIL);
    if (ret != RETCODE_OK) return false;
    PlanInfo sample4_2(sample4);
    sample4_2.flight_id2 = 96;
    sample4_2.flight_name = "Flight 100-96";
    ret = pidw->write(sample4_2, HANDLE_NIL);
    if (ret != RETCODE_OK) return false;

    // Write samples (More)

    waitForMatch(more.dw_);
    mi.flight_id1 = 12345;
    mi.more = "Shouldn't see this";
    ret = midw->write(mi, HANDLE_NIL);
    if (ret != RETCODE_OK) return false;
    mi.flight_id1 = 100;
    mi.more = "Extra info for all flights with id1 == 100";
    ret = midw->write(mi, HANDLE_NIL);
    if (ret != RETCODE_OK) return false;

    // Write samples (Unrelated)

    waitForMatch(unrelated.dw_);
    UnrelatedInfoDataWriter_var uidw =
      UnrelatedInfoDataWriter::_narrow(unrelated.dw_);
    UnrelatedInfo ui;
    ui.misc = "Misc";
    ret = uidw->write(ui, HANDLE_NIL);
    if (ret != RETCODE_OK) return false;

    // Read resulting samples

    WaitSet_var ws = new WaitSet;
    ReadCondition_var rc = dr->create_readcondition(ANY_SAMPLE_STATE,
      ANY_VIEW_STATE, ANY_INSTANCE_STATE);
    ws->attach_condition(rc);
    Duration_t infinite = {DURATION_INFINITE_SEC, DURATION_INFINITE_NSEC};
    ConditionSeq active;
    ret = ws->wait(active, infinite);
    if (ret != RETCODE_OK) return false;
    ws->detach_condition(rc);
    ResultingDataReader_var res_dr = ResultingDataReader::_narrow(dr);
    ResultingSeq data;
    SampleInfoSeq info;
    ret = res_dr->take_w_condition(data, info, LENGTH_UNLIMITED, rc);
    if (ret != RETCODE_OK) return false;
    if (data.length() > 1 || !info[0].valid_data) return false;
    std::cout << "Received: " << data[0].flight_id1 << '-' <<
      data[0].flight_id2 << " \"" << data[0].flight_name << "\" " << data[0].x <<
      " " << data[0].y << " " << data[0].height << " \"" << data[0].more <<
      "\" \"" << data[0].misc << "\"" << std::endl;
    if (data[0].flight_id1 != sample4.flight_id1 || data[0].flight_id2 !=
        sample4.flight_id2 || strcmp(data[0].flight_name, sample4.flight_name) ||
        data[0].x != sample3.x || data[0].y != sample3.y ||
        data[0].height != sample3.z || strcmp(data[0].more, mi.more) ||
        strcmp(data[0].misc, ui.misc)) {
      return false;
    }
    // Check return get_key_value
    Resulting resulting_value;
    ret = res_dr->get_key_value(resulting_value, DDS::HANDLE_NIL);
    if (ret != RETCODE_BAD_PARAMETER) return false;

    data.length(0);
    info.length(0);
    ret = res_dr->read_w_condition(data, info, LENGTH_UNLIMITED, rc);
    dr->delete_readcondition(rc);
    if (ret != RETCODE_NO_DATA) return false;

    // Reader cleanup
    if (i != N_ITERATIONS - 1) {
      sub->delete_datareader(dr);
      waitForMatch(location.dw_, 0);
      waitForMatch(flightplan.dw_, 0);
      waitForMatch(more.dw_, 0);
      waitForMatch(unrelated.dw_, 0);
      sub_dp->delete_multitopic(mt);
    }
  }

  // Dispose

  ReturnCode_t ret = midw->dispose(mi, HANDLE_NIL);
  if (ret != RETCODE_OK) return false;
  ReadCondition_var rc =
    dr->create_readcondition(ANY_SAMPLE_STATE, ANY_VIEW_STATE,
                             NOT_ALIVE_DISPOSED_INSTANCE_STATE);
  WaitSet_var ws = new WaitSet;
  ws->attach_condition(rc);
  const Duration_t infinite = {DURATION_INFINITE_SEC, DURATION_INFINITE_NSEC};
  ConditionSeq active;
  ret = ws->wait(active, infinite);
  if (ret != RETCODE_OK) return false;
  ws->detach_condition(rc);
  ResultingDataReader_var res_dr = ResultingDataReader::_narrow(dr);
  ResultingSeq data;
  SampleInfoSeq info;
  ret = res_dr->read_w_condition(data, info, LENGTH_UNLIMITED, rc);
  dr->delete_readcondition(rc);
  if (ret != RETCODE_OK) return false;
  if (info[0].valid_data ||
      info[0].instance_state != NOT_ALIVE_DISPOSED_INSTANCE_STATE) return false;
  return true;
}
int ACE_TMAIN (int argc, ACE_TCHAR *argv[])
{
  DDS::DomainParticipantFactory_var dpf = DDS::DomainParticipantFactory::_nil();
  DDS::DomainParticipant_var participant = DDS::DomainParticipant::_nil();

  try 
  {
     QuantLibAddinCpp::initializeAddin();

     boost::gregorian::date date ( boost::gregorian::from_undelimited_string( "20111019" ) );

     long evaluationDate = QuantLib::Date( date.day(), QuantLib::Month(date.month().as_number()), date.year() ).serialNumber(); 

     QuantLibAddinCpp::qlSettingsSetEvaluationDate(evaluationDate, OH_NULL);

     std::string ticker;

     // Initialize, and create a DomainParticipant
     dpf = TheParticipantFactoryWithArgs(argc, argv);
     
     qldds_utils::BasicDomainParticipant participant( dpf, EQUITY_OPTIONS_DOMAIN_ID );
     participant.createPublisher();
     participant.createSubscriber();
     DDS::DomainParticipant_var dp = participant.getDomainParticipant();  

 
     ACE_Get_Opt cmd_opts( argc, argv, ":s:" );
  
     int option;
  
     while ( (option = cmd_opts()) != EOF )
     {
       switch( option )
       {
         case 's' :
           ticker = cmd_opts.opt_arg();
           break;
       }
     }


     // Topics
     // setting up qlBlackConstantVols Topic
     DDS::Topic_var ql_black_constant_vols_topic = participant.createTopicAndRegisterType
        < qlBlackConstantVolsTypeSupport_var, qlBlackConstantVolsTypeSupportImpl >
         ( QL_BLACK_CONSTANT_VOLS_TOPIC_NAME );

     // setting up qlGeneralizedBlackScholesProcesses Topic
     DDS::Topic_var ql_generalized_black_scholes_processes_topic = participant.createTopicAndRegisterType
        < qlGeneralizedBlackScholesProcessesTypeSupport_var, qlGeneralizedBlackScholesProcessesTypeSupportImpl >
         ( QL_GENERALIZED_BLACK_SCHOLES_PROCESSES_TOPIC_NAME );

     // setting up qlStrikedTypePayoff Topic
     DDS::Topic_var ql_striked_type_payoffs_topic = participant.createTopicAndRegisterType
       < qlStrikedTypePayoffsTypeSupport_var, qlStrikedTypePayoffsTypeSupportImpl >
         ( QL_STRIKED_TYPE_PAYOFFS_TOPIC_NAME );

     // setting up qlEuropeanExercises Topic
     DDS::Topic_var ql_european_exercises_topic = participant.createTopicAndRegisterType
        < qlEuropeanExercisesTypeSupport_var, qlEuropeanExercisesTypeSupportImpl >
         ( QL_EUROPEAN_EXERCISES_TOPIC_NAME ); 

     StraddleSetupTypeSupport_var ts_res = new StraddleSetupTypeSupportImpl;
     if ( ts_res->register_type(dp, "") != DDS::RETCODE_OK )
     {
       std::cout << "Registration of the Topic FAILED!!!!" << std::endl;
     }

     CORBA::String_var type_name = ts_res->get_type_name();
     std::cout << "Type Name : " << type_name << std::endl; 

     std::stringstream multi_topic_select;

     multi_topic_select << "SELECT ticker, putVols, callVols, putPayoffs, callPayoffs, process, exercises FROM "<<
                          QL_BLACK_CONSTANT_VOLS_TOPIC_NAME << " NATURAL JOIN " << 
                          QL_GENERALIZED_BLACK_SCHOLES_PROCESSES_TOPIC_NAME << " NATURAL JOIN " <<
                          QL_STRIKED_TYPE_PAYOFFS_TOPIC_NAME << " NATURAL JOIN " << 
                          QL_EUROPEAN_EXERCISES_TOPIC_NAME << " WHERE ticker = '" << ticker << "'";

     std::cout << multi_topic_select.str() << std::endl; 

     DDS::MultiTopic_var mt = dp->create_multitopic("MyMultiTopic", type_name, multi_topic_select.str().c_str(), DDS::StringSeq()); 

     if ( CORBA::is_nil( mt ) ) 
       std::cout << "MultiTopic Subscribtion failed.!!!!" << mt << std::endl;

     DDS::Subscriber_var sub = participant.getSubscriber();
     std::cout << "Creating Data Reader"<< std::endl;
     DDS::DataReader_var dr = sub->create_datareader(mt, DATAREADER_QOS_DEFAULT, 0, ::OpenDDS::DCPS::DEFAULT_STATUS_MASK);
     std::cout << "Done..."<< std::endl;

     DDS::WaitSet_var ws = new DDS::WaitSet;
     DDS::ReadCondition_var rc = dr->create_readcondition( DDS::ANY_SAMPLE_STATE, DDS::ANY_VIEW_STATE, DDS::ANY_INSTANCE_STATE);
     ws->attach_condition(rc);
     DDS::Duration_t infinite = { DDS::DURATION_INFINITE_SEC, DDS::DURATION_INFINITE_NSEC};
     DDS::ConditionSeq active;
     int ret = ws->wait(active, infinite);
     if (ret != DDS::RETCODE_OK) return false;
     ws->detach_condition(rc);

     // setting up topic for Straddles 
     DDS::Topic_var straddles_topic = participant.createTopicAndRegisterType
        < StraddlesTypeSupport_var, StraddlesTypeSupportImpl >
         ( STRADDLES_TOPIC_NAME );

     StraddlesDataWriter_var straddles_dw = participant.createDataWriter
       < StraddlesDataWriter_var, StraddlesDataWriter >
         ( straddles_topic );

     
      int calculation_performed = 0;

      do {
       StraddleSetupDataReader_var res_dr = StraddleSetupDataReader::_narrow(dr);
       StraddleSetupSeq data;
       DDS::SampleInfoSeq info;

       int ret = res_dr->take_w_condition(data, info, DDS::LENGTH_UNLIMITED, rc);

       if (ret == DDS::RETCODE_OK) 
       {
         qlBlackConstantVolMatrix& putVols = data[0].putVols;
         qlStrikedTypePayoffSeq& putPayoffs = data[0].putPayoffs;

         qlBlackConstantVolMatrix& callVols = data[0].callVols;
         qlStrikedTypePayoffSeq& callPayoffs = data[0].callPayoffs;

         processes::qlGeneralizedBlackScholesProcess& process = data[0].process;
         qlEuropeanExerciseSeq& exercises = data[0].exercises;

         Straddles straddles;
         straddles.ticker = CORBA::string_dup( ticker.c_str() );
         straddles.underlying = data[0].process.Underlying; 

         int strike_count = putPayoffs.length() + callPayoffs.length();
         int exercises_count = exercises.length();

         straddles.options.length( strike_count * exercises_count );

         int priced_options = 0;

         price( ticker, putVols, putPayoffs, process, exercises, straddles, priced_options );
         price( ticker, callVols, callPayoffs, process, exercises, straddles, priced_options );

         ACE_DEBUG( (LM_INFO, "(%T|%P|%t) Publishing Straddles for ticker : %s trading @%f\n", ticker.c_str(), data[0].process.Underlying )  );

         int ret = straddles_dw->write( straddles, DDS::HANDLE_NIL );
         if (ret != DDS::RETCODE_OK) {
             ACE_ERROR ((LM_ERROR, ACE_TEXT("(%P|%t) ERROR: Publishing Straddles for ticker : %s failed %d.\n"), ticker.c_str(), ret));
         }

         calculation_performed++;
       } 
     } while ( calculation_performed < 30 );

    cout << "Exiting..." << endl; 
  } catch (CORBA::Exception& e) 
  {
    cerr << "Exception caught in main.cpp:" << endl << e << endl;
    ACE_OS::exit(1);
  }

  TheServiceParticipant->shutdown(); 
    
  return 0;
}