Anda di halaman 1dari 18

SMI Framework

Before explain how SMI framework works and is used, it is good to know how to develop CORBA application using WLE. Question: How CORBA applications are developed using WLE? First I try by simple way, the way in most of textbooks illustrate an examples. Then I will try to develop in different way that gives power to extend the functionality with minor changes. Whole document divided into 3 sections. 1. Simple way 2. Another way 3. What is SMI? 1. Simple way To explain this I choose a simple case. I want to develop an interface that returns persons name. Following steps are required in developing CORBA application, o Write an interface o Generate CORBA client stubs and Skeletons o Write CORBA Server o Write Client 1.1 Write an interface For each CORBA object, you need two interfaces. First interface is to define object methods and the other one is factory that returns object reference. person.idl // Interface to return name of person interface Person { string getName(); }; // Interface to creates object reference to the Person object interface PersonFactory { Person find_person(); }; 1.2 Generate CORBA client stubs and Skeletons Using IDL compiler, generate client stubs and server skeletons. In PDS, these files are located in idl directory. List of files generated by IDL compiler are

stubs: person_c.h, person_c.cpp and skeletons: person_s.h, person_s.cpp NOTE: Use these files only to view interface ids and other details like data types. Do not edit them. IDL compiler also optionally (using -i switch) generates implementation files with signatures for the methods. You can write these files manually. person_i.h and person_i.cpp person_i.h #ifndef _person_i_h #define _person_i_h #include person_s.h class Person_i : public POA_Person { public: Person_i (); virtual ~Person_i(); virtual char* getName(); }; class PersonFactory_i : public POA_PersonFactory { public: PersonFactory_i (); virtual ~PersonFactory_i(); virtual Person_ptr find_person(); }; #endif person_i.cpp #include person_i.h // Person_i::Person_i () { } //

Person_i::~Person_i () { } // char* person_i::getName() { ::CORBA::Char * _method_result = ::CORBA::string_alloc (1); /* M3_PRESERVE_BEGIN(Simple_i::to_lower) */ /* Insert code that you want preserved here */ /* M3_PRESERVE_END(Simple_i::to_lower) */ return _method_result; } // PersonFactory_i::PersonFactory_i () { } // PersonFactory_i::~PersonFactory_i () { } // Person_ptr PersonFactory_i::find_person() { ::person_ptr _method_result = ::Person::_nil(); /* M3_PRESERVE_BEGIN(SimpleFactory_i::find_simple) */ /* Insert code that you want preserved here */ /* M3_PRESERVE_END(SimpleFactory_i::find_simple) */ return _method_result; } 1.3 Write CORBA Server Steps to create server object a. Implements business logic for each interface method. b. Create CORBA server object. Override Server::initialize(), Server::release() and Server::create_servant() methods. c. Define object activation policies d. Create and register a factory e. Release the CORBA server application 1.3.1 Implements business logic for each interface method // implement getName()

char* person_i::getName() { CORBA::String_var v_name = CORBA::string_dup(Bhasha); return v_name._retn(); } // implement find_person() factory method Person_ptr PersonFactory_i::find_person() { CORBA::Object_var v_person_oref = TP::create_object_reference( _tc_Person->id(), // interface id (got from person_s.h) PersonObject, // object id (any thing you like but unique) CORBA::NVList::_nil() // routing criteria (do not bother about it) ); return Simple::_narrow(v_simple_oref.in()); } 1.3.2 Create CORBA server object Server object performs the following tasks o o o Initializes CORBA Server application, including registering factories Performs CORBA server application shutdown and cleanup procedures Instantiates CORBA objects needed to satisfy CORBA client requests

CORBA Server implementation Person.cpp #include <Server.h> #include <TP.h> #include Person_i.h // Your object static CORBA::Object_var s_v_fact_ref; // // Method to start up the server // CORBA::Boolean Server::initialize(int argc, char* argv[]) { // create the factory object reference s_v_fact_ref = TP::create_object_reference( _tc_PersonFactory->id(), // factory interface id (got from person_s.h)

person_factory, // object id (any thing you like but unique) CORBA::NVList::_nil() // routing criteria (do not bother about it) ); // Register the factory reference with the Factory Finder (CORBA service): TP::register_factory( s_v_fact_ref.in(), // factory object reference _tc_PersonFactory->id() // factory interface id (got from person_s.h) ); // weve succeeded: return CORBA_TRUE; } // // Method to shutdown the server // void Server::release() { // this will only be called if Server::initialize succeeded // thus we know that the factory has been registered with // the factory finder. // unregister the factory. // use a try block since cleanup code shouldnt throw exceptions try { TP::unregister_factory( s_v_fact_ref.in(), // factory object reference _tc_PersonFactory->id() // factory interface id ); } catch () { TP::userlog(Couldnt unregistering the PersonFactory); } } // // Method to create servants // Tobj_Servant Server::create_servant(const char* intf_repos_id) { if (!strcmp(intf_repos_id, _tc_PersonFactory->id())) { return new PersonFactory_i(); }

if (!strcmp(intf_repos_id, _tc_Person->id())) { return new Person_i(); } return 0; // unknown interface } 1.3.3 Define object activation policies Object activation policies are defined in person.icf (In PDS this file is located in idl directory). If no ICF file exists, then default policies are used. Activation policies: o method: Causes the object to be activate only for the duration of the invocation on one of the objects methods. o transaction: Causes the object to be activated when an operation is invoked on it. o process: Causes the object to be activated when an operation is invoked on it, and to be deactivated only when either process shutdown or TP::deactivateEnable() is invoked on the object. person.icf implementation POA_Person_i { activation_policy ( method ); transaction_policy ( optional ); concurrency_policy ( system_controlled ); implements ( person ); }; implementation POA_PersonFactory_i { activation_policy ( method ); transaction_policy ( optional ); concurrency_policy ( system_controlled ); implements ( PersonFactory ); }; 1.3.4 Create and register a factory This is already covered in 1.3.2. 1.3.5 Release the CORBA server application This is already covered in 1.3.2. 1.4 Write Client Following things need to invoke method on Person object o Intialize the ORB o Use Bootstrap object to establish communication with the BEA Tuxedo domain o Resolve initial referance to Factory Finder object o Use a factory to get an object referance to the desired CORBA object (Person) o Invoke methods on the CORBA object In following code I will show how actions are performed.

Client.cpp #include <Tobj_Bootstrap.h> #include <tobj_c.h> #include simple_c.h int main(int argc, char* argv[]) { try { // Initialize the ORB : CORBA::ORB_var v_orb = CORBA::ORB_init(argc, argv, ); // Create the bootstrap object: Tobj_Bootstrap bootstrap(v_orb.in(), ); // Use the bootstrap object to find the factory finder : CORBA::Object_var v_fact_finder_oref = bootstrap.resolve_initial_references(FactoryFinder); // Narrow the factory finder : Tobj::FactoryFinder_var v_fact_finder_ref = Tobj::FactoryFinder::_narrow(v_fact_finder_oref.in()); // Use the factory finder to find the person factory : CORBA::Object_var v_simple_factory_oref = v_fact_finder_ref->find_one_factory_by_id( _tc_PersonFactory->id() ); // Narrow the person factory : PersonFactory_var v_person_factory_ref = PersonFactory::_narrow(v_person_factory_oref.in()); // Find the person object : Person_var v_person = v_person_factory_ref->find_person(); // Invoke getName() on Person object CORBA::String_var v_name = v_person->getName(); std::cout << v_name.in() << std::endl; return 0; } catch () { cerr <<unexpected exception << endl;

} return 1; } 2. Another way I am going develop a CORBA application that does same thing as in Section 1, but in different way. 2.1 Create a IDL smi.idl interface Smi { string invokeMethod(in string MethodName); }; interface SmiFactory { Smi getSmi(); }; IDL compiler generates smi_c.h, smi_c.cpp, smi_s.h, smi_s.cpp, smi_i.h and smi_i.cpp 2.2 Create few utility classes 1. SmiCmd 2. Utility smiCmd.h class SmiCmd { public: SmiCmd() {}; ~SmiCmd() {}; virtual std::string execute() = 0; }; Utility.h #ifndef _utility_h #define _utility_h static std::map<std::string, Tobj_Servant> ServantList; static std::map<std::string, *SmiCmd> CommandList; #endif 2.3 Implement interface method in smi_i.cpp smi_i.cpp -

#include smiCmd.h #include smi_i.h #include Utility.h smi_i::smi_i() { } Smi_i::~Smi_i() { } // Invoke method char* Smi_i::invokeMethod(const char * method) { CORBA::String_var v_retVal = CommandList[method]->execute(); return v_retVal._retn(); } SmiFactory_i::SmiFactory_i() { } SmiFactory_i::~SmiFactory_i() { } // implement find_smi() factory method Smi_ptr SmiFactory_i::find_smi() { CORBA::Object_var v_smi_oref = TP::create_object_reference( _tc_Smi->id(), // interface id (got from person_s.h) SmiObject, // object id (any thing you like but unique) CORBA::NVList::_nil() // routing criteria (do not bother about it) ); return Smi::_narrow(v_smi_oref.in()); } 2.4 Create a derived command class that returns First name of the person firstNameCmd.h #include smiCmd.h class FirstNameCmd : public SmiCmd

{ public: FirstNameCmd() {}; ~FirstNameCmd() {}; std::string execute(); }; firstNameCmd.cpp #include firstNameCmd.h std::string FirstNameCmd::execute() { return Bhasha; } 2.5 Update Server Person.cpp (Changes are highlighted compared to Section 1 Person.cpp) #include <Server.h> #include <TP.h> #include smi_i.h // Your object implementation #include firstNameCmd.h #include utility.h static CORBA::Object_var s_v_fact_ref; // // Method to start up the server // CORBA::Boolean Server::initialize(int argc, char* argv[]) { // create the factory object reference s_v_fact_ref = TP::create_object_reference( _tc_SmiFactory->id(), // factory interface id (got from person_s.h) smi_factory, // object id (any thing you like but unique) CORBA::NVList::_nil() // routing criteria (do not bother about it) ); // register the factory reference with the Factory Finder (CORBA service): TP::register_factory( s_v_fact_ref.in(), // factory object reference _tc_SmiFactory->id() // factory interface id (got from person_s.h) );

// Save Servant object ServantList[_tc_SmiFactory->id()] = new SmiFactory_i(); ServantList[_tc_Smi->id()] = new Smi_i(); // Save first name command. Method name = FIRST_NAME CommandList[FIRST_NAME] = new FirstNameCmd(); // weve succeeded: return CORBA_TRUE; } // // Method to shutdown the server // void Server::release() { try { TP::unregister_factory( s_v_fact_ref.in(), // factory object reference _tc_SmiFactory->id() // factory interface id ); } catch () { TP::userlog(Couldnt unregistering the PersonFactory); } } // // Method to create servants // Tobj_Servant Server::create_servant(const char* intf_repos_id) { return ServantList[intf_repos_id]; } 2.6 Update Client Client.cpp #include <Tobj_Bootstrap.h> #include <tobj_c.h> #include smi_c.h int main(int argc, char* argv[]) { try {

// Initialize the ORB : CORBA::ORB_var v_orb = CORBA::ORB_init(argc, argv, ); // Create the bootstrap object: Tobj_Bootstrap bootstrap(v_orb.in(), ); // Use the bootstrap object to find the factory finder : CORBA::Object_var v_fact_finder_oref = bootstrap.resolve_initial_references(FactoryFinder); // Narrow the factory finder : Tobj::FactoryFinder_var v_fact_finder_ref = Tobj::FactoryFinder::_narrow(v_fact_finder_oref.in()); // Use the factory finder to find the smi factory : CORBA::Object_var v_smi_factory_oref = v_fact_finder_ref->find_one_factory_by_id( _tc_SmiFactory->id() ); // Narrow the person factory : SmiFactory_var v_smi_factory_ref = SmiFactory::_narrow(v_smi_factory_oref.in()); // Find the smi object : Smi_var v_smi = v_smi_factory_ref->find_smi(); // Invoke invokeMethod() on Smi object CORBA::String_var v_name = v_person->invokeMethod(FIRST_NAME); std::cout << v_name.in() << std::endl; // Expected name = Bhasha return 0; } catch () { cerr <<unexpected exception << endl; } return 1; } 2.7 Add new interface to return last name (surname) of the person Method name = LAST_NAME (both server and client should agree on this) 2.7.1 Create command class that returns last name lastNameCmd.h #include smiCmd.h

class LastNameCmd : public SmiCmd { public: LastNameCmd() {}; ~LastNameCmd() {}; std::string execute(); }; lastNameCmd.cpp #include lastNameCmd.h std::string LastNameCmd::execute() { return Syed; } 2.7.2 Update Server object Person.cpp #include <Server.h> #include <TP.h> #include smi_i.h // Your object #include firstNameCmd.h #include utility.h static CORBA::Object_var s_v_fact_ref; // // Method to start up the server // CORBA::Boolean Server::initialize(int argc, char* argv[]) { // create the factory object reference s_v_fact_ref = TP::create_object_reference( _tc_SmiFactory->id(), // factory interface id (got from person_s.h) smi_factory, // object id (any thing you like but unique) CORBA::NVList::_nil() // routing criteria (do not bother about it) ); // register the factory reference with the Factory Finder (CORBA service): TP::register_factory( s_v_fact_ref.in(), // factory object reference

_tc_SmiFactory->id() // factory interface id (got from person_s.h) ); // Save Servant object ServantList[_tc_SmiFactory->id()] = new SmiFactory_i(); ServantList[_tc_Smi->id()] = new Smi_i(); // Save first name command CommandList[FIRST_NAME] = new FirstNameCmd(); CommandList[LAST_NAME] = new LastNameCmd(); // weve succeeded: return CORBA_TRUE; } 2.7.3 Update Client to invoke Last Name Client.cpp #include <Tobj_Bootstrap.h> #include <tobj_c.h> #include smi_c.h int main(int argc, char* argv[]) { try { // Initialize the ORB : CORBA::ORB_var v_orb = CORBA::ORB_init(argc, argv, ); // Create the bootstrap object: Tobj_Bootstrap bootstrap(v_orb.in(), ); // Use the bootstrap object to find the factory finder : CORBA::Object_var v_fact_finder_oref = bootstrap.resolve_initial_references(FactoryFinder); // Narrow the factory finder : Tobj::FactoryFinder_var v_fact_finder_ref = Tobj::FactoryFinder::_narrow(v_fact_finder_oref.in()); // Use the factory finder to find the smi factory : CORBA::Object_var v_smi_factory_oref = v_fact_finder_ref->find_one_factory_by_id( _tc_SmiFactory->id() ); // Narrow the person factory :

SmiFactory_var v_smi_factory_ref = SmiFactory::_narrow(v_smi_factory_oref.in()); // Find the smi object : Smi_var v_smi = v_smi_factory_ref->find_smi(); // Invoke method on Smi object to get First name CORBA::String_var v_fname = v_person->invokeMethod(FIRST_NAME); std::cout << v_fname.in() << std::endl; // Expected name = Bhasha // Invoke method on Smi object to get last name CORBA::String_var v_lname = v_person->invokeMethod(LAST_NAME); std::cout << v_lname.in() << std::endl; // Expected name = Syed return 0; } catch () { cerr <<unexpected exception << endl; } return 1; } 3. What is SMI? SMI works exactly same way as explained in Secton 2. It has one interface that has only one method, invokeStaticMethod(). This method takes method name, list of key/value pair (std::map) inputs and returns list of key/value pair of outputs. In SMI framework, most of code is already done (Things that are explained in Section 2.1, 2.2, 2.3) for you. Steps you need to do, to add new SMI command (as explained in Section 2.7) o o o Define your command class and override its execute() with business logic Identify the Server you are going to use (like RestrictionsUU) Check idl directory for IDL file. If it does not have highlighted lines add them.

IDL file: module RestrictionsUU { // interface RestrictionsUUSMI : smip::smip_StaticMethodInvoker {}; interface RestrictionsUUSMIFactory : smip::smip_StaticMethodInvokerFactory {}; //

}; If you have updated IDL file then you need to update ICF file also. ICF file: module POA_RestrictionsUU { implementation RestrictionsUUSMI_i { activation_policy ( method ); transaction_policy ( always ); concurrency_policy ( system_controlled ); implements ( RestrictionsUU::RestrictionsUUSMI ); }; implementation RestrictionsUUSMIFactory_i { activation_policy ( method ); transaction_policy ( ignore ); concurrency_policy ( system_controlled ); implements ( RestrictionsUU::RestrictionsUUSMIFactory ); }; }; In RestrictionsUU.cc, Register the factory, RestrictionsUUSMIFactory using SMIP_ADD_FACTORY() o If you have updated IDL file, then you need to add RestrictionsUUSMI using csv_ServantList::addServant() to servant list. o If you have updated IDL file, then you need to add RestrictionsUUSMIFactory using csv_ServantList::addServant() to servant list. o Register your command with SMI framework. o Let us explain by an example: We want to use SMI technique to get bulletin type using bulletin number. We want to use RestrictionsUU server. Method name = GET_BULLETIN_TYPE inputs: std::map<string,string> inputs; inputs[BULLETIN_NUMBER] = 123; expected outputs: std::map<string,string> outputs; outputs[STATUS] = OK or NOTOK;

outputs[BULLETIN_TYPE] = Between_Limits or some thing else if STATUS=OK 3.1 New Command BulletinTypeCmd.h class BulletinTypeCmd : smi_CmdIf { public: BulletinTypeCmd() {}; ~BulletinTypeCmd() {}; ReturnType execute(const ArgType); } ReturnType BulletinTypeCmd::execute(const ArgType) { int bulletinNumber = ut_stoi(ArgType[BULLETIN_NUMBER]); rstn_FormCBulletin bulletin; // Using bulletinNumber , get rstn_FormCBulletin from versant Database smi_CmdIf::ReturnType t = new smi_CmdIf::ParamMap; if (bulletin exist) { (*t)[BULLETIN_TYPE] = bulletin->type(); (*t)[STATUS] = OK; } else { (*t)[STATUS] = NOTOK; } } 3.2 Updating RestrictionsUU.cc In following code, highlighted is minimum stuff you need to do. Not highlighted stuff is required only if you have updated IDL file. RestrictionsUU.cc #include BulletinTypeCmd.h void initServerApp(int argc, char * argv[]) { //existing code // This is same as registering factory object using TP::register_factory() SMIP_ADD_FACTORY( BULLETIN_DOMAIN, // domain, anything you like RestrictionsUU::_tc_RestrictionsUUSMIFactory->id());

// This is same as Saving Factory Servant in map SMIP_ADD_FACTORY_SERVANT( RestrictionsUU::_tc_RestrictionsUUSMIFactory->id(), RestrictionsUU::_tc_RestrictionsUUSMI->id()); smip_StaticMethodInvoker_i < POA_RestrictionsUU::RestrictionsUUSMI > * smi = new smip_StaticMethodInvoker_i < POA_RestrictionsUU::RestrictionsUUSMI >(); // This is same as Saving Your Servant in map csv_ServantList::addServant( RestrictionsUU::_tc_RestrictionsUUSMI->id(), smi); // ut_SharedPtr <smi_CmdIf> getBulletinTypeCmd = new BulletinTypeCmd(); smi_StaticMethodInvoker::registerMethodInvoker (GET_BULLETIN_TYPE, getBulletinTypeCmd); // existing code } 3.3 What client needs from you domain name = BULLETIN_DOMAIN method name = GET_BULLETIN_TYPE input keys: BULLETIN_NUMBER output keys: STATUS BULLETIN_TYPE Expected output values: STATUS = OK or NOTOK

Anda mungkin juga menyukai