Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Professional C++ [eng].pdf
Скачиваний:
284
Добавлен:
16.08.2013
Размер:
11.09 Mб
Скачать

Chapter 24

Using the Objects

You’re now ready to use your distributed objects. Using the objects requires two steps. One piece of code must create an object and register it with the Object Request Broker (ORB) framework via the Portable Object Adapter. It must also provide a way for client code to lookup references to the object. One technique is to use a nameserver. This nameserver must be available from all the machines on which the distributed program runs. As a nameserver, it maps names to object references and tracks the actual physical location of all the distributed objects on the system. If you don’t have a nameserver available, you can use other ad hoc methods to register and lookup object references. Although the CORBA standard includes a nameserver, and omniORB supplies one, for simplicity our database example just writes the object reference key to a file.

The code that wants to use an object looks it up in the nameserver, or, in our case, the file, to retrieve a reference to it. When this client code calls a method on the reference, the request is sent to the ORB layer, which is either a layer in each process, or its own process on each node, depending on the implementation. At this point, there are two options. If the underlying object is in the same process as the caller, the method is executed locally as a normal C++ method call. However, if the underlying object is in a different process on the same machine, or on a remote machine, the ORB sends the method request over the network to the server process. All this work occurs under the surface: the code that makes the method call on the object reference doesn’t need to worry about whether the actual object is local or remote.

Figure 24-3 shows the basic CORBA architecture.

Machine 1

Machine 2

Client

 

Object

 

 

Lookup

Implementation

 

 

object

 

 

 

reference

Skeleton

Call

 

 

 

Name

 

Method

 

 

Implementation

Make

server

Portable Object

 

Method

Stub

Adapter

 

Call

 

 

 

 

ORB

ORB

 

 

Make Remote Procedure

 

 

 

Cell using IIOP

 

 

Figure 24-3

CORBA works for interprocess communication on the same machine as well as intermachine communication. You can use CORBA as a mechanism for “sharing” objects between processes on the same machine.

The rest of this section continues the database example by showing a sample implementation of a server and client. We don’t expect you to understand all the code details; we merely want to give you a sample

706

Exploring Distributed Objects

so you get a general feeling for CORBA programming and a taste of how powerful the technology can be. If you want to become an expert CORBA programmer, you should consult the references listed in Appendix B.

The Server Process

The server process must initialize the ORB, create a new DatabaseServer object, register the object, and save a key to its reference in a file for clients to find. This example assumes that clients will have access to the directory from which this server process is started, either through a network file system, or because they are running on the same node. The comments explain the steps taken. Note that you don’t use a special compiler to compile this code; you can use a standard C++ compiler, such as g++, as long as you link to the appropriate omniORB libraries.

#include “DatabaseServer.h” #include <iostream> #include <fstream>

using namespace std;

const char* objRefFile = “OBJ_REF_FILE.dat”;

int main(int argc, char** argv)

{

//Try to initialize the orb. CORBA::ORB_var orb;

try {

orb = CORBA::ORB_init(argc, argv); } catch(CORBA::SystemException&) {

cerr << “Unable to initialize the ORB\n”; exit(1);

}

//Obtain a reference to the “Portable Object Adapter” and downcast

//it to the appropriate type.

CORBA::Object_var obj = orb->resolve_initial_references(“RootPOA”);

PortableServer::POA_var poa = PortableServer::POA::_narrow(obj);

//Create the DatabaseServer object and register/activate it

//with the portable object adapter.

DatabaseServer* myDb = new DatabaseServer();

PortableServer::ObjectId_var dbid = poa->activate_object(myDb);

//Write a string version of the object reference to a

//file so clients can find us.

CORBA::Object_var dbobj = myDb->_this();

CORBA::String_var sior(orb->object_to_string(dbobj));

ofstream ostr(objRefFile); if (ostr.fail()) {

cerr << “Unable to open object reference file for writing.\n”; exit(1);

}

ostr << (char*)sior; ostr.close();

707

Chapter 24

// Tell the reference counter that we’re done with the object.

//Now only the POA has a reference to it. myDb->_remove_ref();

//Move the POA from holding to active state, so that it will process

//incoming requests.

PortableServer::POAManager_var pman = poa->the_POAManager(); pman->activate();

//Wait for incoming requests. orb->run();

//Shouldn’t return from the run call, but if we do, we need to clean up orb->destroy();

return (0);

}

The Client Process

The final step is to write a client process. Here is a basic client that reads the object reference key from a file, creates an object reference from the key, and calls two methods on the object reference. These calls are translated by the ORB layer into calls to the DatabaseServer object in the server process.

#include “database.hh” #include <iostream> #include <fstream> using namespace std;

const char* objRefFile = “OBJ_REF_FILE.dat”;

int main(int argc, char** argv)

{

//Try to initialize the orb. CORBA::ORB_var orb;

try {

orb = CORBA::ORB_init(argc, argv); } catch(CORBA::SystemException&) {

cerr << “Unable to initialize the ORB\n”; exit(1);

}

//Read the server object reference from the file. ifstream istr(objRefFile);

if (istr.fail()) {

cerr << “No object reference file!\n”; exit(1);

}

char objRef[1024]; istr.getline(objRef, 1024);

//Construct an object reference from the string. database_var dbref;

try {

CORBA::Object_var obj = orb->string_to_object(objRef);

708

Exploring Distributed Objects

dbref = database::_narrow(obj); if(CORBA::is_nil(dbref) ) {

cerr << “Can’t narrow reference to type database\n”; exit (1);

}

} catch(CORBA::SystemException&) {

cerr << “Unable to find the object reference\n”;

}

//Make calls on the object reference, which are translated to

//calls on the server object in the server process.

try {

dbref->addRecord(“key1”, “value1”);

const char* lookup = dbref->lookupRecord(“key1”); if (strcmp(lookup, “value1”) == 0) {

cout << “Success!\n”;

} else {

cout << “strings don’t match\n”;

}

} catch(CORBA::COMM_FAILURE&) { cerr << “Communication error\n”; exit(1);

} catch(CORBA::SystemException&) {

cerr << “Communication error (SystemException)\n”; exit(1);

}

// We’re done. orb->destroy();

return (0);

}

As you can see, the CORBA framework is certainly complicated and has a steep learning curve. However, it can be invaluable for industrial-strength distributed programming.

XML

Extensible Markup Language (XML) is a simple and general markup language. Fundamentally, XML can be used to represent just about anything. You could use XML as the file format for storing an MP3 music playlist or as the internal representation of a complex purchase order. Because XML is easy to work with and has cross-platform support, it has quickly become popular as a format for network communication, remote procedure calls, and distributed objects.

A Crash Course in XML

One of the greatest aspects of XML, and surely one of the reasons for its rapid adoption, is that it has a very friendly learning curve. Getting started with XML is easy. Within minutes, you’ll know the terminology and be able to read and write valid XML. From there, an XML developer can proceed down any

709

Chapter 24

number of more complex roads, such as XML transformations, or Simple Object Access Protocol (SOAP), a distributed object technology built upon XML.

What Is XML?

XML is merely a syntax for describing data. Outside of a specific application, XML data has no meaning. For example, you could write a home inventory program that produces a perfectly valid XML document describing all of your worldly possessions. If you gave that document to somebody else, they might be able to look at it and figure it out, but the XML-based home inventory program that they wrote wouldn’t necessarily be able to interpret it. The reason is that XML defines the structure of the document but not its meaning. Another application may represent the same information in a different structure.

XML is written in a plain text format, which makes it easy for human beings to grok. Even if you’ve never seen XML before, you can probably understand the following snippet of XML data:

<inventory>

<office>

<desk type=”wood”/> <computer type=”Macintosh”/> <chair type=”leather”/>

</office>

<kitchen>

<mixer type=”chrome”/> <stove type=”electric”/>

</kitchen>

</inventory>

In addition to readability, the text format also means that XML is easy to work with in software. You don’t need to learn a complicated framework or purchase an expensive toolset to parse text. Because even the most obscure operating systems understand plain text, it’s easy to send XML between systems without worrying about binary compatibility issues.

To be fair, textual representation has some downsides. Readability quickly becomes verbosity. An XML representation of data is usually larger than its equivalent binary representation. When the data set is large, the XML representation can grow to be enormous. Text also takes time to parse, unlike a binary format, which doesn’t require any parsing at all.

The other important characteristic about XML, implied by the indentation of the previous example, is that it is hierarchical. As you’ll see, XML is often parsed into a tree structure that you can walk through to process the data.

XML Structure and Terminology

XML documents begin with a document prolog, which specifies the character encoding and other metadata about the document. Many programmers omit the prolog, but some stricter XML parsers will fail to recognize the document as XML if the prolog is not found on the first line. The details of information that can be specified in the prolog are beyond the scope of this book. The following prolog is sufficient for most uses:

<?xml version=”1.0”?>

710

Exploring Distributed Objects

The document prolog is a special type of tag, a piece of syntax that XML recognizes as having some sort of meaning. If you have written HTML files, you’re already familiar with tags. The body of an XML document is made up of element tags. They are simply markers that identify the start and end of a logical piece of the structure. In XML, every starting element tag has a corresponding ending element tag. For example, the following line of XML uses the tag sentence to mark the start and end of a sentence element.

<sentence>Let’s go get some ice cream.</sentence>

In XML, the end tag is written as a slash followed by the name of the element. Element tags don’t always have to contain data as the previous example does. In XML, you can have an empty tag, which simply exists on its own. One way of doing this is to follow a start tag immediately with an end tag:

<empty></empty>

XML also provides a shorthand for empty element tags. If you end a tag with a slash, it serves as both the start tag and the end of the element:

<empty />

The topmost element, which contains all other elements in the document, is known as the root element.

In addition to its name, an element tag can contain key/value pairs called attributes. There are no set-in- stone rules about what can be written as an attribute (remember: XML is just a syntax) but in general, attributes provide metainformation about the element. For example, the sentence element could have an attribute that gives the speaker of the sentence:

<sentence speaker=”Marni”>Let’s go get some ice cream.</sentence>

Elements can have multiple attributes, though they must have unique keys:

<sentence speaker=”Marni” tone=”pleading”>Let’s go get some ice cream.</sentence>

When you see an XML element whose name has a colon in it, such as <a:sentence>, the string prior to the colon, is its namespace. Just like namespaces in C++, namespaces in XML allow you to segment the use of names.

In the previous examples, the content of an element was either empty or textual data, commonly referred to as a text node. In XML, elements can also contain other elements, which gives XML its hierarchical structure. In the following example, the dialogue element is made up of two sentence elements. Note that the indentation exists only for readability — XML ignores white space between tags.

<dialogue>

<sentence speaker=”Marni”>Let’s go get some ice cream.</sentence>

<sentence speaker=”Scott”>After I’m done writing this C++ book.</sentence> </dialogue>

Those are the basics! Elements, attributes, and text nodes are the building blocks of XML. For more advanced syntax, such as special character escaping, consult one of the XML reference books listed in Appendix B.

711