In an object-oriented language, one servant object may implement all of the operations.The client does not know about the implementation issues involved, so a servant can existfor the du
Trang 1printer This connection could be performed via any popular management protocol (SNMP, WEBM,RMI, etc.) For this exercise:
a) Define interface RemotePrinter which exposes the management operations of class Printer (Fig 25.8) RemotePrinter must extend interface Remote Create a stand-alone application, RemotePrinterImpl, that starts a Printer thread Class RemotePrinterImpl must implement RemotePrinter interface Remote- PrinterImpl must post an RMI stub reference of itself in the Jini lookup service of
the Jiro domain Class RemotePrinterImpl must delegate any remote method calls
to its Printer instance
b) Modify PrinterManagementImpl (Fig 25.5) to retrieve a RemotePrinter stub from the Jini lookup service of the local Jiro domain PrinterManagement dynamic service must delegate all printer management operations to stub RemotePrinter.
“Executive Overview.” Jiro Web site <www.jiro.com/overview/>.
“Frequently Asked Questions.” Jiro Web site <www.jiro.com/faqs/>.
“Jiro Document Center.” Jiro Web site <jiro.com/documentcenter/>.
“Jiro Recipes.” Jiro Web site <jiro.com/education/recipes/>.
“Jiro Technical Overview.” Jiro Web site <www.jiro.com/overview/ tech_overview.html>
“Jiro Technology Discussion Forum.” Jiro Web site mate.cgi?action=intro>
<www.jiro.com/cgi-bin/Ulti-Monday, P., and W Connor The Jiro Technology Programmer’s Guide And Federated Management Architecture Boston, MA: Addison-Wesley, 2001.
Trang 226 Common Object Request
Broker Architecture (CORBA): Part 1
• To understand distributed exceptions.
• To implement the Deitel Messenger application using
CORBA.
• To compare CORBA to other technologies for
building distributed systems.
In the master there is a servant, in the servant a master.
Marcus Tullius Cicero
Excellence is to do a common thing in an uncommon way.
Booker T Washington
The virtue in most request is conformity.
Ralph Waldo Emerson
It is often wonderful how putting down on paper a clear
statement of a case helps one to see, not perhaps the way out,
but the way in.
A.C Benson
Trang 326.1 Introduction*
To appreciate what Java has brought to the software-development industry in the past fewyears, one must first appreciate the happenings just beneath the radar screens of most de-velopers prior to Java’s introduction—the gradual acceptance that legacy systems were notgoing away and that there existed a need to take advantage of these systems In addition,the explosive growth of the Web has made it critical to develop systems that can be distrib-uted (networked) “out of the box” rather than building the same communications infra-structure repeatedly Java offered several features that made these systems possible but didnot offer higher-level classes, tools or abstractions for building large-grained distributedsystems in generic and predictable fashions Java lacked the ability to make invocations on
26.9 Comments and Comparisons
26.10 Internet and World Wide Web Resources
Summary • Terminology • Self-Review Exercises • Answers to Self-Review Exercises • Exercises • Works Cited • Bibliography
* This chapter was co-authored by Carlos Valcarcel of EinTech, Inc
Trang 4local objects that, in reality, were invocations on remote objects This capability wouldhave allowed Java to make standard method calls on objects that appeared local, but were
in a different process space The supporting infrastructure was not available to Java, so dors in the distributed-object arena began porting their infrastructure products to supportJava The infrastructure that was the best fit with Java turned out to be CORBA
ven-CORBA stands for the Common Object Request Broker Architecture More accurately,
CORBA stands for “glue.” It allows programs written in various languages, with varyingimplementations running in disparate locations, to communicate with each other as easily
as if they were in the same process address space Conceptually, in the same way objectscooperate to accomplish specific tasks, CORBA describes architecture made of cooper-ating services
Software Engineering Observation 26.1
CORBA does not enforce good systems-integration practice; it merely enables the
CORBA relies on object technology to accomplish this Encapsulation, inheritance,polymorphism and dynamic binding hide implementation details, making CORBA’s workappear transparent Transparency is a crucial goal of CORBA This transparency enablesdevelopers and system integrators to define standard services that legacy systems provideand make these services available to other systems that want to use them Within this trans-parent infrastructure, a myriad of services are available to other users that need the services.Three areas leveraged by clients using CORBA are invocation transparency, implementa-tion transparency and location transparency
Invocation transparency defines the viewpoint of a client sending a message to a
server The language used to implement a client specifies how a called object receives amessage—how arguments are passed on the stack, how the proper method is called, andhow return values are delivered Once a server (an object that is responsible for delivering
a collection of related services) is defined within a CORBA framework, a client can makemethod calls to this CORBA-enabled object similarly as a call to any other object imple-mented within the target language This kind of behavior is more naturally understood bydevelopers using an object-oriented language (e.g., Java, C++, and Smalltalk), but isequally valid for developers using a non-OO language (e.g., C, COBOL, or Lisp) CORBAsupports a number of object-oriented and non-object-oriented languages (10 altogether)—
C, C++, Java, COBOL, Ada, Lisp, Smalltalk, PL/1, Python and IDLscript
Implementation transparency is a encapsulation applied to distributed systems A
client knows three things about a method invocation—the method name, the methodparameters (if any) and the method return type The client is not concerned with how theunderlying code processes parameters and ensures returning valid values—even with per-formance considerations, the client can notify the server as to any performance constraintsprior to making any method invocations A client invokes a method in the target (client’s)language, and the code invoked to satisfy the method call is executed in any language sup-ported by an OMG mapping
Location transparency allows a client to invoke CORBA-enabled code that might
exe-cute elsewhere on the network This builds on implementation transparency—the clientsappear to make local calls, but in reality, they call code that executes in different languagesoutside of the process space where the client is located (e.g., a Java servlet running in New
Trang 5York communicates with a COBOL legacy database running in Japan) All of this is sible because of various object-technology concepts (encapsulation, inheritance, and poly-morphism) used in implementation-independent ways.
pos-The Object Management Group (OMG) is the consortium responsible for CORBA.
Founded in April 1989, the OMG’s goals are far reaching and have the backing of imately 800 members Their main goal is to create a “component-based software market-place by hastening the introduction of standardized object software.”1 A major step towardthe creation of this object marketplace was the defining of the OMG’s Object ManagementArchitecture (OMA)
approx-The Object Management Architecture (OMA) distinguishes CORBA from other
dis-tributed system technologies Objects in an object-oriented system cooperate to achievesolutions to domain problems The OMA (as a reference architecture) defines a system con-sisting of cooperating services solving a domain problem The granularity of the solution
is larger, but the concept of objects (or components) working together toward a commongoal remains the same
So, how do the goals of systems integration, transparency, and ease of use cometogether, using a reference architecture in a fashion that allows multilanguage, multiplat-form, and multilocation issues to be handled in a consistent and straightforward fashion?The answer is in these three acronyms—IDL, ORB and IIOP
For objects to appear to speak the same language, they must use a common mapping
to their particular language For code in languages such as COBOL, Java, C, and Python tocommunicate to one another, an intermediate language must bind them This intermediatelanguage should be simple to use, easy to learn and have minimal overhead
OMG IDL™, the OMG Interface Definition Language (commonly referred to as IDL),
allows developers to describe the interface (or API) of the data type they wish to useremotely in a language-independent fashion IDL is a pure description language—noimplementation details are included in IDL files (unless someone deliberately inserts com-ments describing implementation assumptions) Using a C++-like syntax, developersdescribe only two things—the interface to an object and any data structures a method call
to the object may take or return as values An IDL compiler takes an IDL file
(convention-ally ending with idl) and generates the code needed for a client to call a
CORBA-com-pliant object and for the CORBA-comCORBA-com-pliant object to receive and return values When wespeak of a CORBA-compliant “object” we make no assumptions about whether it is anobject in the way Java describes a object or procedural COBOL code that implements theoperations (methods) defined in an IDL file in a non-object oriented fashion The code thatimplements the operations (i.e., handles client requests to a CORBA object) constitutes a
servant In a non-object-oriented language there is an individual servant for each operation.
In an object-oriented language, one servant (object) may implement all of the operations.The client does not know about the implementation issues involved, so a servant can existfor the duration of a method call, for until the server within which the servant is running isshut down or for some duration in between (this, however, is controlled by an objectadapter which mediates all access to servants We discuss this in more detail inSection 26.4)
An IDL compiler creates a number of language-dependent files for each IDL file piled A project would need as many IDL compilers as there are target languages in thesystem to be developed To develop a Java front-end to a legacy COBOL system, two IDL
Trang 6com-compilers are needed—one to generate the client-side Java code, and one to generate theserver-side COBOL code For example, a Java front end would need the following gener-
ated client-side Java files to interact with a back-end system named StockTicker:
StockTicker.java contains the base definition of the remote server The
StockTickerOperations source file contains method definitions of the operations that the CORBA object supports The _StockTickerStub class is responsible for client-side communication, while the StockerTickerHelper file defines a conve-
nience class usable by the client for CORBA-related tasks
These files hide the invocation mechanism from a caller StockTicker.java and StockTickerOperations.java define interfaces for use by implementation
classes; _StockTickerStub.java defines actual CORBA invocation code to make the remote method call to a server Files StockTickerHelper.java and Stock- TickerHolder.java are additional support files that we discuss later
The vendor who supplies the server component ships an IDL file that describes the API
to their server object Using the vendor-supplied IDL file and an IDL compiler, a developerwould generate the needed client-side files to talk directly to this server-side object
If a GUI written in C for the StockTicker system were to attempt to send messages
to server-side objects written in Java (CORBA-enabled Java objects) the following Javafiles would have been generated by an IDL compiler to allow the Java server object toreceive messages from any callers:
StockTicker.java
StockTickerOperations.java
_StockTickerImplBase.java
The files StockTicker.java and StockTickerOperations.java are the
same as above (interfaces for use by implementation classes), and
_StockTickerImplBase.java represents the CORBA code used by the server toaccept method calls and deliver values across the network
In addition to declaring Java interfaces for developer use, both client-side and
server-side files defined above implement base classes as proxies—stand-ins for other objects.
Proxies allow a client to believe it is sending a message to one object when the client is
really sending the message to another object CORBA defines two related proxies—a stub and a skeleton A stub is the client-side proxy and a skeleton is the server-side proxy Both
proxies hide the use of the ORB from the client and the server
The Object Request Broker is the “ORB part” of CORBA Interoperability is the
ORB’s central purpose All CORBA-enabled objects must use an ORB to make or receivemethod requests, but those same objects rarely see the ORB In the examples that follow,note the similarity of the code for connecting various pieces This code similarity is theOMG at work The base connectivity CORBA API is the same regardless of the CORBAimplementation
Trang 7Portability Tip 26.1
Unless you use vendor-specific value-added features under CORBA 3.0, the replacement of
an existing ORB installation with an ORB vendor’s new product should not require the
When a client invokes an operation on a distributed object, the client’s ORB uses anobject reference to complete the invocation request For example, if the client was written inJava, it behaves as if the reference is to a local version of the object being invoked The objectreference used by the client (supporting the public API of the object defined in the IDL file)
contain an opaque network reference (opaque because neither the client nor server infer
implementation details with the information contained in the reference) A client invokes
operations on a distributed object through an object reference, whereas an Interoperable
Object Reference (IOR) refers specifically to an object reference whose structure is
well-understood by ORBs using the OMG-supported protocols (such as IIOP, discussed
momen-tarily) The object reference comes from an object adapter pointing to the remote object The
object reference contains three important pieces of information—the distributed object’slocation (an address, but not a memory address), a reference to the adapter that created the
object reference and an object ID for the servant All CORBA-compliant ORBs understand
what object references are (and, for true interoperability, they must understand IORs) andhow to use them to connect clients to servants The final piece needed for interoperability isthe creation and parsing of the IOR into the “on-the-wire” protocol to send a request acrossthe network.2 However, knowledge of IORs is not enough to allow one vendor’s ORB tocommunicate predictably with another vendor’s ORB To enable robust, predictable
communication, the OMG specified the Internet Inter-ORB Protocol or IIOP.
All vendors must support IIOP (Internet Inter-ORB Protocol) for their ORBs to be
CORBA-compliant Vendors can support their own protocol as well, but, at a minimum, theymust also support IIOP IIOP is the protocol for how ORBs communicate with each other.The average developer does not need to know anything about IIOP; a CORBA site adminis-trator maintains the appropriate ORB protocol at any particular location ORBs that expect tocommunicate with each other must speak the same protocol If the ORBs support differentprotocols, custom bridges must be developed to map the protocols to enable communicationsbetween nonstandard-protocol ORBs As the standard ORB protocol, IIOP should be thedefault protocol for any ORB installation, although IIOP is not the only choice
IIOP is the implementation of another OMG standard—the General Inter-ORB
Pro-tocol, or GIOP GIOP defines the messages needed by ORBs to communicate with each
other and the support for the underlying transport mechanism of the platform on which theORB runs TCP/IP is the preferred transport—there is also specification support for NovellIPX and OSI Vendors are free to support other transport mechanisms Java, with its built-
in network support, and CORBA, with its “under-the-covers” transport to connect uted objects transparently, are complementary technologies
distrib-Every programming language that the OMG supports must have an guage mapping Shortly after Java’s introduction, a number of ORB vendors made theirown mappings to satisfy the demand for distributed Java applications The OMG adopted
IDL-to-target-lan-a JIDL-to-target-lan-avIDL-to-target-lan-a mIDL-to-target-lan-apping IDL-to-target-lan-as IDL-to-target-lan-a CORBA stIDL-to-target-lan-andIDL-to-target-lan-ard in July 1998 When the OMG rIDL-to-target-lan-atified the officiIDL-to-target-lan-alIDL-to-Java mapping, vendors upgraded their products to conform Conformity to the IDLmappings is an important step to maintaining integrity in the CORBA world The IDL-to-Java mapping defines how the standard IDL keywords and data types translate into Java
Trang 8constructs Java 2 was the first official Sun release to support the OMG mappings directly.
We discuss IDL-to-Java mappings shortly
26.2 Step-by-Step
The steps necessary to implement a distributed system using Java and CORBA are:
1 Perform analysis and design by modeling the problem domain, modeling the tem domain and defining subsystems using the system domain
sys-2 Define the IDL by specifying the API of the subsystems to be distributed and ifying any data structures that cross system boundaries
spec-3 Implement the servant, using files generated by the IDL compiler
4 Implement a client, using the stub files generated by the IDL compiler
5 Decide on a method to distribute the servant’s object reference (traditionally doneusing a Naming Service, but this is not required)
6 Start the servant implementation
7 Run the client
Software Engineering Observation 26.2
Implementing a distributed system is a nontrivial task Developers must follow standard ware development practices when using CORBA as an enabling infrastructure to bind vari-
Good Programming Practice 26.1
Several processes and methodologies for modeling problem domains exist Make sure the model you choose maps to the problem being solved (otherwise, you might find yourself re-
The OMG’s OMA remains the preferred reference architecture for directing tural concerns OMA defines architecture in the context of a collection of cooperating ser-vices Consider the subsystems you declare as sharing responsibilities There are moreopportunities for process reuse if your system defines fundamental services that are usable
architec-by other development groups
Once subsystems have been defined, you want to decide which subsystems to figure as distributed services If all of the subsystem designs assume distributed/sharablefunctionality, the migration of subsystems to CORBA becomes much easier In any case,the public API of the service becomes the interface accessible by clients In typical OOfashion, the interface revealed in the IDL can be a subset of the available functionalityoffered by a server It is not until the implementation of the server (we use Java as the targetlanguage) that the developer worries about how much additional functionality (administra-tion, security, etc.) the server is given
con-If there are data structures that a server must return to a client (or vice versa), the tification and definition of these data structures must be in the IDL file This is a bit of athrowback to the way languages such as C define data structures, but the CORBA modelmakes allows non-object-oriented languages to describe non-object-oriented constructs in
iden-a “pseudo-object” fiden-ashion Two CORBA constructs support this mechiden-anism—the struct
Trang 9and the valuetype A client and a server pass IDL structs back and forth as raw data
for allowing local handling of information A standard optimization is sending this data
directly to the client so the server can handle more demanding requests The valuetype
construct is the IDL description of an entity consisting of both data and behavior A
struct consists of pure data (and a struct compiled into Java defines the instance attributes as public), whereas a valuetype encapsulates the data and adds any logic
for making the object as simple or complex as needed Section 26.8.5 explains a CORBA
valuetype in more detail.
ad-Assume that the declared server API is in an IDL file and an IDL compiler has piled the file Now the client uses the generated client-side files needed to speak with theserver The client needs only the IDL-generated files to take advantage of the underlyingmechanism that allows communication across the network transparently The client couldinstantiate a local version of the server (instead of using a CORBA object reference, they
com-could simply perform a new ServerImpl()) and send messages directly, but the server
would no longer be a distributed object—the server would be running in the client’s processspace having lost the low-coupling advantage we originally had by using the glue codelocated in the generated files
26.3 First Example: SystemClock
This example provides a basic service (time) and allows a client to query for the currenttime The requirements are:
• Retrieve the current system time
• Display the current system time in a GUI window
The SystemClock server interface declares a single method TimeMillis (which mimics the call in class java.lang.System) The method returns the system time as a long A Date object would have been more appropriate for
current-Java If this were an example of the CORBA Time Service, a Universal Time Object would
have been even more appropriate However, a long helps keep this pure-Java example
simple (a non-trivial time service factors issues such as network latency)
Trang 1026.3.1 SystemClock.idl
Figure 26.1 declares the IDL for the SystemClock server Lines 1 and 2 are single-line comments; they follow standard C++ syntax with the double slash (//) denoting a single-
line comment Line 4 is the first real line of “code” (CORBA does not dictate
implementa-tion, so the IDL is not technically code) The module keyword maps a given name directly
to a Java package Nested module names concatenated together create a complete package name The module name in Fig 26.1 is clock.
The curly braces at lines 4 and 10 denote scope boundaries of the block Note that, in
IDL, a semicolon always identifies the end of a block (including the module declaration).
Java, C and C++ are block-scoped languages and use a similar syntax but do not considerthe block itself as a line that requires a semicolon to be complete A missing semicolon is
a syntax error in IDL
Lines 7-9 declare the interface the SystemClock server Is the server type actually SystemClock? From the client’s perspective, the answer is yes—the data type of the
server is SystemClock From the server’s perspective, the answer is no—that is not the direct type The server is a derived class (concrete implementation) of interface Sys- temClock The indirection to the client is deliberate, allowing an arbitrary server imple-mentation
The curly braces at lines 7 and 9 mark the boundary of the interface declaration.
Again, notice the semicolon at the end of line 9 used to identify the end of the block.Line 8 is a method/function/message declaration Everything declared in IDL is
public , so there are no special keywords in IDL interfaces to denote public, vate or protected declarations (although metatypes component and valuetype have keywords private and public) The method currentTimeMillis, by defi- nition, is public and returns an IDL long long, which maps to a Java long (a single IDL long maps to a Java int).
pri-The Java IDL compiler, idlj, compiles systemclock.idl with the command line
idlj -td c:\src -pkgPrefix clock com.deitel.advjhtp1.idl -fall systemclock.idl
We discuss the Java tool idlj and its command line options shortly The Java IDL compiler generates the following server-side files after compiling systemclock.idl:
Trang 11SystemClock.java and SystemClockOperations.java are interfaces SystemClock.java (Fig 26.2) shows interface SystemClock.
Lines 11 and 12 declare interface SystemClock and the three interfaces from which SystemClock inherits Two of the three are CORBA-defined types from which all CORBA-enabled objects must inherit org.omg.CORBA.Object and org.omg.CORBA.portable.IDLEntity The third—interface System- ClockOperations (Fig 26.3)—is generated from the IDL and declares the public
operations of the server SystemClock inherits from SystemClockOperations, but
is otherwise empty SystemClock defines a base class that inherits from ClockOperations and the CORBA interfaces mentioned previously—part of the structure needed by derived classes to appear as proper CORBA objects SystemClock- Operations , inheriting from nothing, declares the single method current- TimeMillis originally defined in the IDL _SystemClockImplBase inherits from SystemClock, another CORBA interface (InvokeHandler), and a base CORBA implementation class named org.omg.CORBA.portable.ObjectImpl (Impl is
System-an abbreviation for “implementation”) The server requires these three object types toinherit the structure and behavior needed to be a valid CORBA-enabled distributed object
The interface InvokeHandler declares method invoke, which _SystemClockImplBase implements The ORB uses method invoke to call the var- ious SystemClock methods in a generic fashion The _SystemClockImplBase method invoke is generated by the IDL compiler based on the IDL interface declared in the IDL file systemclock.idl.
26.3.2 SystemClockImpl.java
SystemClockImpl (Fig 26.4) is the SystemClock interface implementation
Con-ventionally, the concrete class that implements a CORBA distributed object’s public
inter-face is named <IDL interinter-face name>Impl This class does not have to declare a main
method, but it can
Lines 7–9 are standard import statements We use classes outside the java.lang
namespace, so we include them in the Java file A discussion of the classes declared in these
imports follows shortly
Trang 12Method main (lines 62–74) starts the SystemClock server Line 65 instantiates the SystemClockImpl object The SystemClockImpl constructor (lines 20–23) is for the startup initialization We instantiate SystemClockImpl like any other Java object
and, in this example, we do not appear to use the object for anything (in fact, the object iswaiting for an incoming client request) Line 68 creates an object we can lock against and
call its thread’s wait method (line 72) The use of keyword synchronized (line 71) means no other object can access object while the synchronized block is active Line 72 stores the object in the thread queue until someone calls object.notify Object timeServer could call notify within its own scope, but that would potentially
cause the server to terminate when it completes handling an incoming call
13 public interface SystemClockOperations
14 public long currentTimeMillis()
Trang 1319 // initialize SystemClockImpl object by calling method register
20 public SystemClockImpl( String params[] ) throws Exception
21 {
22 register( "TimeServer" , params );
23 }
24
26 private void register( String corbaName, String params[] )
27 throws org.omg.CORBA.ORBPackage.InvalidName,
28 org.omg.CosNaming.NamingContextPackage.InvalidName,
29 CannotProceed, NotFound
30 {
33 if ( ( corbaName == null ) ||
34 ( corbaName.trim().length() == 0 ) )
35 throw new IllegalArgumentException(
36 "Registration name cannot be null or blank." );
37
39 ORB orb = ORB.init( params, null );
52 NameComponent namingComponent =
53 new NameComponent( corbaName, "" );
54 NameComponent path[] = { namingComponent };
55
57 naming.rebind( path, this );
58 System.out.println( "Rebind complete" );
59 }
60
62 public static void main( String[] args ) throws Exception
63 {
65 SystemClock timeServer = new SystemClockImpl( args );
66
68 java.lang.Object object = new java.lang.Object();
69
Fig 26.4 Implementation of the SystemClock server (part 2 of 3)
Trang 14The SystemClockImpl constructor can throw exceptions of type Exception For this example, we allow the constructor to throw Exception out of expedience and not out of correctness The incoming argument params is an array of Strings that may contain properties needed to run the server The register method takes array params and the String “TimeServer” to initialize the SystemClock service.
Lines 26–59 declare method register Aside from the SystemClock service receiving a name (contained in variable corbaName) and any useful configuration param- eters (params), this method can throw one of four exceptions:
• InvalidName thrown by the ORB
• InvalidName thrown by the Naming Service
• CannotProceed
• NotFound
The ORB or the Naming Service may throw one of these exceptions based on server
interactions In this case, the ORB is part of the process space of the SystemClock
server The server instantiates the objects needed to accomplish its tasks and does not knowwhat kind of ORB it uses As the CORBA standard does not specify the ORB’s implemen-tation the ORB can be either a local object taking care of network connectivity or a proxy
to a daemon process (a background process running in its own address space) taking care
of network connectivity The Naming Service is a separate process the server registers with
to allow clients to find them
Lines 35–36 throw a Java IllegalArgumentException if the incoming ment corbaName is null or blank (checked at line 33–34) The server cannot register
argu-itself for use by others without a name—this error is severe enough that we would not want
to continue without one
Line 39 is a static method call to the ORB class requesting the creation of a new
ORB object based on the incoming arguments A valid incoming argument is a
command-line option telling the ORB what communications port to use (for example, tialPort) There is also a no-argument version of init that returns a default ORB instead of instantiating a newly configured ORB based on incoming properties The init method can have its arguments as null.
ORBIni-Line 42 passes the implementation object to the ORB All access to the server is nowthe responsibility of the ORB The ORB (depending on its implementation) is responsiblefor load balancing, security, custom filters, etc In addition, the ORB is responsible for the
underlying protocol’s basic operation—the particulars of every generated ImplBase class
will vary based on its IDL definition (the methods being invoked and the object types
71 synchronized ( object ) {
72 object.wait();
73 }
74 }
Fig 26.4 Implementation of the SystemClock server (part 3 of 3)
Trang 15involved can be different per server type), but ultimately the functionality is the same The
ORB calls method _invoke (found in the _SystemClockImplBase class); _invoke takes care of marshaling incoming arguments (converting values into a format suitable for network transport) and unmarshaling any return values (converting values back
into a usable form) Once the ORB has the implementation object, the object cannot beaccessed except through the ORB
A server can make itself available to clients in a number of ways Lines 45–48 show
the easiest way to register a distributed object for client access The SystemClock server (implemented in SystemClockImpl) registers itself with some directory service clients
can reference when they look for services A directory service serves the same purpose afile system does—it maintains a listing of resources and their locations in an accessible
form A standard CORBA directory service is the Naming Service, which lists resources for
future use by clients The act of registration with Naming does not mean a server is forming any tasks; the server is merely making itself available for client use The serviceshould be prepared to handle incoming requests for functionality needed by a calling client
per-at any moment The startup sequence for a server, or bootstrapping, can be problemper-atic—
how does the server find the Naming Service the first time the server starts up? Is there aNaming Service finder?
The ORB solves the problem for us—method resolve_initial_references knows a select list of services reachable directly from the ORB The string “NameSer- vice” is a standard name defined in the CORBA specification (along with a list of othernames3) The ORB effectively has a mini-naming service with which it can perform thelookup of base services
Lines 45–46 retrieve the object reference to the Naming Service However, for
resolve_initial_reference to work with any of a number of different services,
the method returns the object reference as an object of type org.omg.CORBA.Object Lines 47–48 use static method narrow of class NamingContextHelper to con- vert the returned object reference into an object of the proper type (in this case, Naming- Context) The narrow method is the CORBA mechanism to cast one reference type into another safely The narrow method checks if the interface into which we are trying to cast
the target object is supported by the target object Standard casting does not work withCORBA object references, because the object reference is a proxy to remote information
All Helper classes have a static narrow method that allows us to cast from a parent
class to a derived class
Lines 52–54 create a NameComponent object and place it in an array For a name to
be properly registered (or bound) the resource must set up a naming context The server is
registered in the main (or root) naming context, so the only thing needed by the NamingService is the server’s name, which the server sends at line 57 (the name was passed in as
an argument to register) using rebind Method rebind enters the nent if it is not in the Naming Service or re-enters the NameComponent if it is in the Naming Service However, using rebind in this way allows only one instance of the SystemClock to be accessed at a time (the NamingContext has been hard-coded to the incoming corbaName and every running instance will use the same name) The last SystemClock registered is the server to which clients bind.
NameCompo-In summary, the IDL describes the server, the compiler generates the needed Java
sup-port files and SystemClockImpl implements the server.
Trang 1626.3.3 SystemClockClient.java
SystemClockClient (Fig 26.5) represents the client that connects to Clock SystemClockClient’s primary functionality is in method run (lines 58–80) This object connects to the SystemClock service, requests the current time and displays
System-a String in System-a JOptionPSystem-ane Every time the user clicks the OK button, the client quests the latest time from the server and displays the new time When the user clicks Can- cel, the client application exits
re-Method connectToTimeServer (lines 29–48) throws the same exceptions (InvalidName, NotFound and CannotProceed) as method register of class SystemClockImpl The client and the server throw the same exceptions, because thelogic the client uses to read from the Naming Service is similar to the logic used by theserver to write to the Naming Service
Line 35 calls static method init of class ORB to create an ORB The String array params allows the dynamic configuration of the ORB at runtime (which was passed from method main, which received the String array from the command line) When the client obtains the ORG, lines 37–38 call method resolve_initial_references of
this ORB to get the object reference to the Naming Service Lines 39–40 cast the object
ref-erence from a CORBA Object to a NamingContext object using method ContextHelper.narrow
18 public class SystemClockClient implements Runnable {
19 private SystemClock timeServer;
Trang 1728 // use NameService to connect to time server
29 private void connectToTimeServer( String params[] )
30 throws org.omg.CORBA.ORBPackage.InvalidName,
31 org.omg.CosNaming.NamingContextPackage.InvalidName,
32 NotFound, CannotProceed
33 {
35 ORB orb = ORB.init( params, null );
44 new NameComponent( "TimeServer" , "" );
45 NameComponent path[] = { nameComponent };
46 corbaObject = naming.resolve( path );
47 timeServer = SystemClockHelper.narrow( corbaObject );
48 }
49
51 private void startTimer()
58 public void run()
59 {
60 long time = 0
61 Date date = null ;
62 DateFormat format =
63 DateFormat.getTimeInstance( DateFormat LONG );
64 String timeString = null ;
65 int response = 0
66
67 while ( true ) {
68 time = timeServer.currentTimeMillis();
69 date = new Date( time );
70 timeString = format.format( date );
71
72 response = JOptionPane.showConfirmDialog( null , timeString,
73 "SystemClock Example" , JOptionPane OK_CANCEL_OPTION );
74
75 if ( response == JOptionPane CANCEL_OPTION )
76 break ; // Get us out of here
Trang 18The client must ask the Naming Service for an object reference to the service the client
seeks—the SystemClock service, named “TimeServer” (declared in the ClockImpl class)
System-Good Programming Practice 26.2
Store service names in a properties file, rather than hard-code them in a class coding implies additional maintenance of the class files when the values change A prop- erties file allows for configuring an already deployed system, thereby making the fix an administrative issue, not a development issue. 26.2
Hard-Lines 43–44 creates a NameComponent object In SystemClockImpl (Fig 26.4)
we used the NameComponent object to register with the NamingContext the path to (and IOR of) where the SystemClock is located In this case, SystemClockClient uses the NameComponent object to ask the NamingContext for the location of a ser- vice with a particular name Lines 45–46 store the NameComponent object in an array, then pass the array to the NamingContext through its method resolve This method returns an object of type CORBA Object, so we use static method SystemClock- Helper.narrow to downcast the object reference to the desired derived class At thispoint, the client has an active distributed object, and the client calls the distributed object
when the user clicks the OK button.
81
83 public static void main( String args[] ) throws Exception
90 // process exceptions that occur while client executes
91 catch ( Exception exception ) {
Fig 26.5 Client that connects to SystemClock (part 3 of 3)
Trang 1926.3.4 Running the Example
Before running the preceding example, make sure that JDK 1.3 is installed on a workstation
and the PATH environment variable is updated to include the bin directory of the JDK 1.3
installation
The steps to execute the SystemClock example are as follows:
1 Compile the IDL file using idlj.
2 Implement and compile the server class
3 Implement and compile the client class
4 Run a Naming Service
5 Run the server
6 Run the client
To compile the IDL file on the command line, use the idlj compiler supplied with the JDK A partial list of idlj’s command-line options are:
• -f<client | server | all>
• -pkgPrefix <module name or IDL type> <prefix to be appended>
• -td <output directory>
The -f option to the idlj compiler controls the code generation of the stubs and etons Option -fclient generates only client-side files, -fserver generates only server-side files and -fall generates both The -pkgPrefix option generates package names This option is used with a module name A module named modName compiled with -pkgPrefix modName prefix would generate Java files with a package name of
skel-prefix.modName The -td option directs idlj to write the generated files in the
spec-ified directory
For example, if you had your source code in C:\src, the command line would look
like this (based on the IDL defined in Fig 26.1):
idlj –pkgPrefix clock com.deitel.advjhtp1.idl –td c:\src –fall SystemClock.idl
This generates both the server-side and client-side CORBA-Java files After menting the client and server, compile the client and server code The code supplied in
imple-Fig 26.4 and imple-Fig 26.5 (SystemClockImpl.java and Client.java) is sufficient for this example
SystemClock-Java 2 includes tnameserv, which is the basic implementation of the CORBA Object
Service (COS) Naming Service The tnameserv tool is not intended as a
production-ready Naming Service; rather, it serves as a testing tool to ensure that clients and servers
communicate properly The Naming Service must execute before the server ClockImpl) can run Run tnameserv as a background process (in Windows, run tnameserv in a separate command window; under UNIX, just append an ampersand to
(System-the end of (System-the line starting tnameserv):
Trang 20All the processes started for this example use port 1050 to communicate The defaultport for the name server shipped with Java 2 is port 900—however, sometimes that port isavailable only to administrators.
Start SystemClockImpl as a separate process:
The underlying concepts in CORBA discussed so far should be familiar to those developers
who are familiar with design patterns Stubs and skeletons are proxies (objects that control access to other objects) Services that return objects are factories (objects that create ob-
jects, but defer object implementation to derived classes) Factories and proxies can befound everywhere in the CORBA landscape Those classes and objects that use design pat-terns hide a multitude of implementation details from developers
Good Programming Practice 26.3
Design patterns standardize design terms and solutions Learning design patterns helps velopers reuse designs, components, services and frameworks. 26.3The ORB is the central mechanism of CORBA All CORBA-enabled objects musthave an ORB standing between them and whatever is calling them (Fig 26.6) One ORBmust exist for every object in a CORBA-enabled distributed system
de-Fig 26.6 Call path from a client to a distributed object
call path in reality
Trang 21We can view an Object Request Broker as the back plane (or communication bus) ofdistributed systems As a communication bus, the implication is that everything using anORB can communicate with everything else on the communication bus using an ORB.What advantage is there to using ORBs? ORBs are a flexible construct, but what problems
do they solve? The OMG addressed both of these questions in the Object Management
Architecture.
A typical software system addresses various business needs Legacy systems (i.e.,
anything system installed earlier than yesterday) are typically separate, distinct and donot share information They solve a focused problem, even if the solution involves largevolumes of data Over time, as modifications are made to the systems, they become moreexpensive to enhance Over the last 30-40 years, these systems became incompatible Thechanging hardware, software, and business landscape created a plethora of incompatiblesystems until the systems-integration field handled this communication problem Theinvention of custom solutions to integrate these systems emphasized the need to make theintegration less of a duplication of effort and more of an “out-of-the-box” solution TheOMG, together with its member vendors, created the Object Management Architecture(shown in Fig 26.7).4
The Object Management Architecture (OMA) is the OMG’s reference architecture fordistributed systems based on the concept of an Object Request Broker Using object-tech-nology concepts, the OMA defines a plug-and-play framework where publicly defined
objects are available for use by any other object or service through an object broker The
object broker is a transparent communication mechanism that ensures that objects sendmessages reliably to one another regardless of their location The OMA defines an abstrac-tion that hides the fact that various systems use different programming languages or useincompatible versions of the same language
The Common Object Request Broker Architecture specifies how the Object RequestBroker behaves and works using different languages OMA defines a polymorphic frame-work of common services that appear similar from the outside (their API), but differ on theinside (their implementation)
ORBs can be implemented in one of two ways—as libraries or as daemons Neither theclient nor the servant are concerned with the means of implementation The creation of anORB object hides the underlying implementation Traditionally, the client uses a library-based ORB, whereas the server uses a daemon-based ORB This is an implementationdetail for system administrators to decide From the perspective of the running process,nothing changes
The ORB plays the most fundamental role possible in the OMA We now examine howboth the client and the servant perceive the ORB The client communicates with the ORB
in one of three ways—through a static stub (generated by the IDL compiler), a dynamicinterface (using CORBA’s dynamic invocation API) or the ORB’s API Conceptually, anORB communicates with a servant in three ways—through a static skeleton, a dynamicinterface or the servant’s object adapter (which appears as if the ORB directly interacts withservant) When a servant wants to communicate with another servant, the servant
“becomes” a client and all its mechanisms become client-based
The most straightforward way to communicate with an ORB is through the static stubsand skeletons They contain the necessary communications code and enables static typingbased on the defined IDL Dynamic invocations (either from a client or a servant) consume
Trang 22more overhead but are more flexible because they allow developers to control ically how remote objects are invoked (Section 27.2 discusses dynamic invocations) Exe-cution of remote methods through direct ORB calls is possible, but not recommended Theindirection that gives CORBA its strength is bypassed and becomes difficult to restore oncesystem implementation is under way The client/servant communicates with the ORB toaccess certain actions that are possible only through the ORB—operations on object refer-
programmat-ences and access to the Interface and Implementation Repositories (two data stores of
object meta-data) Low-level CORBA development of that kind is needed only to ment infrastructure support, such as drivers and bridges Figure 26.8 illustrates the ORBinteractions.5 6
imple-Fig 26.7 Object Management Architecture reference model Courtesy of Object
Management Group, Inc
Fig 26.8 ORB request-interface structure Courtesy of Object Management
domain-Horizontal facility interfaces
General service interfaces
ORB Interface
Static IDL Skeleton
Dynamic Skeleton
Object Adapter
Trang 23A CORBA concept discussed earlier was that of object adapters—objects that stand
between a client and server to control access to the distributed object The object adapteracts as a “connector” between a client and the servant code that executes when an operation
is invoked (the ever-present ORB stands between the client and the object adapter) Prior
to CORBA 3.0, the standard object adapter was the Basic Object Adapter, or BOA The
BOA facilitated binding between a client and a server CORBA 3.0 defined another object
adapter called the Portable Object Adapter (POA) The POA replaces the BOA as the
object adapter of choice The BOA design did not meet demands required by Internet cations When the OMG first specified BOAs, what is now considered standard function-ality (i.e., better CORBA portability between vendors) was not perceived as a high-priorityissue In the same way that Java has supplanted various technologies, the CORBA specifi-cation deprecates the BOA in favor of the POA
appli-The Portable Object Adapter serves many purposes, including the ability to separatethe availability of the servant from the actual servant When a client needs a service, theclient needs particular functionality at a particular time Several components interact tomake this possible First, the client has an object reference represented by a CORBA object.Using the object reference, this CORBA object contains information to find the objectadapter that created it The object adapter handles the client’s invocation by deciding whichentity (or servant) can handle the invocation and completing the invocation as needed(based on various configuration options set when the object adapter was created) If theclient, holding onto the object reference it received when it first connected to the servant,does not actually need to call the servant for some extended period, waiting for the client
to use the servant should not penalize the servant Scalability would suffer, makingCORBA an ineffective solution for systems-integration By separating the servant from theclient’s handle to the service, different servant objects (controlled through object lifetimeand activation patterns) can handle the method calls made on a service There are a number
of issues wrapped up in that last statement The indirection gained by using a POA meanstransparent handling of those issues
Chapter 27 discusses the dynamic interface that the client and server use Static stubs (using the Static Invocation Interface or SII) have hard-coded object types to perform their type checking at compile time, whereas dynamic stubs (using the Dynamic Invocation
Interface or DII) perform their type checking at runtime.
CORBAservices are the baseline services available to all objects sitting on the ORB
communication bus Because the ORB is the center of a CORBA system, CORBAservicescan assume the existence of an ORB when they are running There are sixteen services:7
1 Naming Service
2 Event Management Service
3 Life Cycle Service
4 Persistent State Service
5 Transaction Service
6 Concurrency Service
7 Relationship Service
8 Externalization Service
Trang 24The CORBAfacilities are a step above the intermediate CORBAservices and come in two groups—horizontal and vertical The horizontal facilities target client-side function-
ality, the vertical facilities target domain-specific functionality The horizontal cilities have only three specifications: 8 9
CORBAfa-1 Mobile Agents Facility
2 Printing Facility
3 Internationalization Facility
All three are course-grained enough not to be grouped with CORBAservices, but abstractenough not to conflict with potential vendor offerings that could be built on top of COR-BAservices
The vertical CORBAfacilities—also called CORBA Domains—are between the
BAservices and the Applications Objects (Fig 26.7) They make use of various BAservices and horizontal facilities and define domain-specific services Eleven domaintask forces define the various business areas:10
COR-1 Common Enterprise Models
Trang 25The various OMG committees for different industries are creating, enhancing andvoting on dozens of specifications CORBA Domains are worth the effort of a visit to the
OMG site (www.omg.org).
The Applications Objects are the top layer of the OMA Relatively speaking, opers find the least amount of reusable code here; the objects at this layer address enter-prise-specific domain areas Applications Objects have the functionality not found at thedomain layer, facilities layer or the services layer Custom applications sit securely in theOMA framework, using existing IDL-defined services or brand new services developershave written in response to design requests
devel-An understanding of the OMA means a head start in developing an architecture,because so many of the pieces needed in most systems are defined in the OMA Distributedsystems are inherently complex and interesting, but the basic concepts are the same regard-less of the designed system’s size
26.5 CORBA Basics
Distributed objects need to be defined so they can be discovered and used by other uted objects We define the distributed objects in IDL and use the stubs and skeletons gen-erated by the IDL compiler to mediate the invocations in a consistent manner.’
distrib-ORB vendors ship IDL compilers with their products As of Java 1.2, Javasoft moditized the OMG libraries for Java by shipping them with the JDK Having the CORBAlibraries available allows Java/CORBA developers to generate their own stubs and skele-
com-tons using the Java-supplied IDL compiler idlj Ideally, the Java stubs generated by the
compiler should interoperate with the skeleton code running under another vendor’s ORB(and the stub code from other vendor’s ORBs should interoperate with the Java skeletoncode), but test often and be aware of possible incompatibilities
OMG document formal/99-07-53 defines the IDL-to-Java mapping and covers
every-thing from package names to Helpers to mapping CORBA pseudo objects Syntactically
IDL is similar to C++, but the similarity ends there Figure 26.9 lists the most frequentlyused specification mappings.11
Trang 26Packages starting with org.omg contain the Java packages that comprise the core
CORBA infrastructure CORBA vendors deliver their version of the CORBA libraries withtheir Java ORB products
The following example walks through various IDL keywords and their Java parts The IDL in Fig 26.10 uses many of the IDL keywords so that we can see how theIDL compiler maps the keywords in the generated files listed in Fig 26.11–Fig 26.13
counter-wstring java.lang.String
unsigned short short
unsigned long int
unsigned long long long
Trang 27File maptest.idl starts with two different types of comments—one multi-line
block (lines 1–5), and a single-line comment (line 7) These comments do not appear in thegenerated files created by the IDL compiler The comments are for the author and main-
tainers of the idl file as a documentation aid Comments placed in an IDL file appear in the generated files only if they are within the module scope Therefore, lines 1–5 and line
7 from maptest.idl are extraneous to the java files but not to the idl file The module name maptest (line 9) maps directly to a package named maptest (however, the compiler can handle the prepending of a package name using the -pkg- Prefix command line option as we did in the SystemClock example) The module
and its curly braces represent the highest level of symbol scope in IDL
The comment on line 11 appears in the generated file so any documentation
appro-priate to the Java code can be included (it is within the scope of the module) Lines 12–
31 declare struct StructMap StructMap uses the bulk of the IDL data types to observe how they map to Java data types Line 31 completes struct StructMap with
a closing brace and a semicolon
It would seem, from the table listing the translation points, that IDL does not handle
complex types In fact, structs allow for the complex aggregation of primitives and
22 unsigned short uShortValue;
23 long longValue;
24 unsigned long uLongValue;
25 long long longLongValue;
26 unsigned long long uLongLongValue;
33 typedef sequence <StructMap> StructMapSeq;
34 typedef sequence <StructMap, 5 > BoundStructMapSeq;
35
36 typedef long IntArray[ 5 ];
37
40 interface interfaceName {
41
43 attribute long anAttribute;
44 readonly attribute long roAttribute;
45 const long constantValue = 42 ;
46
48 void seqMethod( in StructMapSeq seq );
49 void boundSeqMethod( in BoundStructMapSeq seq );
50 void arrayMethod( in IntArray array );
51 void intOutMethod( inout long intValue );
Trang 28object references However, because a struct is not really a class (even though it gets converted into one), the compiler generates a public final class to prevent the creation
of derived classes from the struct A struct is a collection of data compiled into a
class definition that a remote servant can return to, or receive from, a client at runtime Inboth cases, a local copy of the data is received (instead of an object reference)
Most of the primitive IDL-to-Java mappings are straightforward The IDL compilermaps signed primitives to corresponding signed primitive types in Java; unsigned IDL prim-itives run the risk of truncation, because they are mapped to their signed Java primitive coun-terparts (a signed short cannot store as large a value as an unsigned short) The IDL compileralso enforces the clean initialization of the instance variables by setting them to integer zero,
0.0, false or null (casting where necessary) Notice, in the generated Java code from StructMap.java (Fig 26.11) that the declared instance variables are public The IDL- generated code breaks encapsulation In fact, everything in IDL is public, because C,
COBOL and other IDL-mapped languages do not support encapsulation concepts
Software Engineering Observation 26.3
Write wrapper classes to surround the structs-turned-objects as a way of restoring
encap-sulation Wrapper classes define objects that mediate access to another object through a
well-defined API Pass the object representing the CORBA struct into the wrapper
ob-ject’s constructor when the wrapper object is instantiated. 26.3
An interface (line 40) declares attributes clients can query and methods that
cli-ents can invoke on remote objects A struct represcli-ents a real chunk of runtime data, whereas an interface represents a remote object that might be in a different process
space, but appears as a local object The interface represents the remote object because
the IDL compiler does not implement the distributed object The developer must take the
generated code and implement the actual servant, using the generated definitions Two of
the generated interface files (InterfaceNameOperations.java and faceName.java) encourage developers to (1) structure the servant in a way that allows polymorphic access to the servant through the parent interface (InterfaceName) and
Inter-(2) inherit the distributed protocol behavior we need from an abstract class
Only an interface can have attribute declarations If the attribute
key-word is used alone, the compiler generates two methods—an accessor (get method) and a
mutator (set method) Using the readonly keyword with attribute would generate
only the accessor Originally, the accessor methods looked like JavaBean-style get methods
(getAge, getAttribute) In the latest incarnation of the IDL specification, the
Java-Beans naming convention is effectively deprecated Overloaded methods are generated forboth the accessor and mutator using the name of the attribute and are different based on
their signatures—the accessor method signature for attribute balance would return
a value while the mutator would take an incoming argument and return nothing The cation is that CORBA objects cannot be JavaBeans, but that discussion continues in theCORBAcomponents section in Chapter 27
Trang 29impli-In IDL, the const keyword declares a constant Syntactically, Java declares constant values using the final keyword Idiomatically, the Java keywords static and final
declare constants as there is no point in having multiple copies of an unchangeable value.The IDL compiler generated code complies with the Java idiom (Fig 26.13, line 14) The
IDL compiler also acknowledges the fact that integral values in Java start out as longs and
so casts the literal to the smaller type
The mapping of methods, the parameter-passing modes, holders and arrays representthe remaining concepts needed to define server-side objects and the services they provide.Java developers take many of these features for granted as Java defines cross-platform datasizes and mechanisms to invoke operations on objects in the Java Language Specification.CORBA IDL mappings make the same guarantees for data and invocations between anyCORBA-supported languages
Note the use of the in keyword in the method declaration in Fig 26.10, line 48 IDL includes keywords in, out and inout to describe method arguments A variable declared as in has a copy of itself passed to the called method The scope of a change made
by the servant is visible only to the servant (similar to call-by-value) When the method
returns, the client will not see any changes An out variable must be a reference to a Java
object containing another Java object where the contained Java object may be substitutedwith another Java object and the change is visible to the client (similar to call-by-reference)
A variable declared as inout uses both semantics Java has two value types—primitives
and object references An object reference is, by definition, a call-by-reference Use of a
primitive, on the other hand, is only as a value CORBA uses Holder objects to make the
changing of values by a server-side object similar for both primitives and references A
Holder can have its values modified and the client can see the modification In fact, this
works similar to Java Number objects that wrap primitive values—however, Java Number objects are immutable while Holders are mutable (modifiable).
Every time a struct or interface is declared, the IDL compiler generates an associated Holder class for use when the struct or interface is an inout or out
variable If a servant needs to read a value (whether primitive or object), send the value as
an in variable If a servant needs to send a value to a client (whether primitive or object), send the value as an out (or inout) variable, and use the Holder objects to transport them across the network safely All of the Java primitives have Holder classes available for them in the org.omg.CORBA package and the IDL compiler generates the proper method signature in the Operations interface defining the Holder object needed.
Lines 33 and 36 present the two ways to declare arrays in IDL—using the keyword
sequence and the use of open-and-close square brackets ([]) The sequence keyword
or [] are not used alone in either case The IDL writer must declare a type definition (a typedef) using sequence or [] to declare the array as a simple name For example, the type StructMapSeq is a sequence (array) of type struct StructMap.
Common Programming Error 26.1
The symbol sequence <StructMap> cannot define an array identifier; the IDL compiler requires a typedef-defined identifier for array types or the compiler generates a syntax er-
ror Renaming the array declaration makes the new symbol become an additional object type.26.1
The sequence keyword can be used in one of two ways—bounded or unbounded.
When a length is given, the sequence is considered bounded (line 34); otherwise, it is
Trang 30considered unbounded (line 33) In both cases, the IDL-to-Java compiler unrolls the
typedef back to an actual array declaration and generates Helper and Holder types for those array types (in this case, StructMapSeqHelper, StructMapSeqHolder, BoundStructMapSeqHelper , and BoundStructMapSeqHolder) We examine
the Holders when we discuss parameter passing modes.
The standard square brackets notation also can declare arrays However, the use of IDLarrays is non-standard to Java In Java, lengths are not part of the intrinsic definition of a data
type In IDL, the new array (using []) defined using typedef has a bounded length enforced in the stub/skeleton proxies The typedef keyword defines an array of a particular data type using a new data type name and the array length A typedef in IDL is similar to
a typedef in C and C++—a new data type appears to exist, but the data type is an alias for use by the compiler Using a typedef allows the IDL developer to define new data types without the implementation issues involved in the declaration In maptest.idl, (Fig 26.10) an array of struct StructMap is declared using the keyword typedef, the type to be redefined and the new name, which is surrounded by <> (lines 33–34) The array’s
length (its bound) is declared in the name, but is not used anywhere else; the array is bounded
Figure 26.11 is the listing for StructMap.java—one of the generated files from maptest.idl Line 1 (and the first line in each upcoming generated file) declares the
package name as maptest Lines 12 and 17 are the comments listed in Fig 26.10 at
lines 11 and 14 IDL authors and maintainers are responsible for including information onthe IDL and its intended use, rather than including information on implementation specificdetails that can change
The instance variables declared in lines 18–31 of Fig 26.11 are the declared struct
variables from Fig 26.10 The Java code initializes the instance variables to include the use
of explicit casting The Java class mapped from the struct has two constructors available
for object instantiation—a zero-argument constructor, and a constructor with all of the
struct’s field types as arguments Creating objects of this type can have default values(using the zero-argument constructor) or pre-defined values (using the second constructor)
InterfaceNameOperations.java (Fig 26.12) contains the interface
information declared in Fig 26.10 at lines 40–52 The IDL compiler translated the tions into Java syntax and the comments from the IDL file are visible in the generated code
opera-at lines 12, 15, 18 and 22 A Java interface cannot contain any instance variables or implementation code, which makes an interface a perfect choice for declaring the vis- ible structure for the implementation object Note that InterfaceNameOpera- tions.java does not declare the attributes defined in Fig 26.10 lines 43–44,
except indirectly through the available accessor and mutator (lines 16, 19 and 20) The IDL
does not dictate the implementation of the attributes—the IDL dictates that they be available through a particular interface.
Trang 316 * Generated by the IDL-to-Java compiler (portable), version "3.0"
13 public final class StructMap implements
14 org.omg.CORBA.portable.IDLEntity
15 {
16
18 public boolean boolValue = false ;
19 public char charValue = ( char ) 0
20 public char wCharValue = ( char ) 0
21 public byte octetValue = ( byte ) 0
22 public String stringValue = null ;
23 public String wStringValue = null ;
24 public short shortValue = ( short ) 0
25 public short uShortValue = ( short ) 0
26 public int longValue = ( int ) 0
27 public int uLongValue = ( int ) 0 ;
28 public long longLongValue = ( long ) 0
29 public long uLongLongValue = ( long ) 0
30 public float floatValue = ( float ) 0
31 public double doubleValue = ( double ) 0
37 public StructMap( boolean _boolValue, char _charValue,
38 char _wCharValue, byte _octetValue, String _stringValue,
39 String wStringValue, short _shortValue,
40 short _uShortValue, int _longValue, int _uLongValue,
41 long _longLongValue, long _uLongLongValue,
42 float _floatValue, double _doubleValue )
Trang 32The final generated file discussed is InterfaceName.java in Fig 26.13 The laration of interface InterfaceName extends three interfaces and declares the constant constantValue at line 14 (otherwise, the interface is empty) Constants always appear in the file named after the interface declared in the IDL file.
dec-When the IDL compiler processes an IDL file, primary responsibilities for the piler is to generate these two proxy classes (one for the server, and one for the client) Theseproxies do not contain any application-specific functionality—they handle only connectingthe client to the server The stub, which directly reflects the API of the server declared in
com-the IDL, can have any of com-the public methods of com-the server called from it In com-the temClock example, when the client makes a call to currentTimeMillis, the client calls a method in the stub that handles calling method _invoke in the stub’s abstract parent (org.omg.CORBA.portable.ObjectImpl) ObjectImpl’s _invoke
13 public interface InterfaceNameOperations
14 {
17
19 void anAttribute( int newAnAttribute);
21
23 void seqMethod( maptest.StructMap[] seq );
24 void boundSeqMethod( maptest.StructMap[] seq );
25 void arrayMethod( int [] array );
26 void intOutMethod( org.omg.CORBA.IntHolder intValue );
Fig 26.12
Fig 26.12 IDL-generated file InterfaceNameOperations.java
(re-formatted for clarity)
Fig 26.11
Fig 26.11 IDL-generated file StructMap.java (re-formatted for clarity)
(part 3 of 3)
Trang 33method marshals any incoming values (in this case there are none), and the stub code takes
care of unmarshaling any return values (which in this case is a long value) From the
client’s perspective, it makes a method call on the server and blocks until the method
returns with a value In reality, the ORB makes the request by calling _invoke on the stub
to handle the method call The _invoke method calls the proper method on the servant,
waits for the method to return and unmarshals any return values
Prior to CORBA 3, there were two types of static invocations—synchronous and
oneway (there was also one for dynamic invocation, but more on that later) When a client
makes a synchronous method call to a server, the client blocks (does not return) until the
server’s method completes The oneway modifier declared an invoked method as
returning immediately—but did not declare any quality-of-service options Quality of
Ser-vice (known as QoS) defines the policy assigned to a particular task allowing the task to
complete within a reasonable length of time.12 The OMG considered QoS so important aseparate QoS framework specification exists to allow developers to control QoS at various
levels (generally speaking they are ORB level, thread level and object-reference level).
Object reference level QoS overrides thread level QoS and thread level QoS overrides ORBlevel QoS.13 QoS makes CORBA 3 invocation choices much more symmetrical—they can
be synchronous (normal or oneway) or asynchronous (callback or polling) A callback is
an invocation made from the server, whereas polling is an invocation made from theclient—in either case, a method is being invoked based on the needs of the calling object.From an implementation perspective, a callback has more overhead as the callback object(the client) needs to use CORBA libraries to behave as a CORBA server A polling clienthas no additional overhead to make repeated calls to a server The distinction has to do with
a met condition (a server alerts a callback object) or an expected condition (a client polls
an object to check on state changes)
Portability Tip 26.2
The OMG has not yet decided on standard default values for QoS, ORB vendors can define
nonportable values If you use these values, place them in a separate.properties file for
11 public interface InterfaceName extends InterfaceNameOperations,
Trang 34A synchronous call is a standard method invocation—a client invokes a method and
blocks until the call completes If an IDL method signature includes the oneway keyword,
the compiler generates code that does not block on the invocation and returns based on the
QoS settings To return immediately, the method must receive only in arguments, must not
return values and cannot throw exceptions The caller does not need to wait for a response(it notifies the server something has happened and does not care what happens next) or theclient wants to make itself available as soon as possible to other callers In either case, asynchronous call is client-initiated
An asynchronous call differs from a synchronous call In a callback situation, theserver can call a client at any time In many cases, a server calling a client asynchronouslyworks fine (e.g., listeners in the Java event model), but consider when a client needs the
server to notify it in a more controlled fashion? The CORBA Asynchronous Method
Invo-cation specifiInvo-cation supports both callback and polling models The callback model
sup-ports (with various QoS options) the ability of a servant to call a client arbitrarily at thediscretion of the servant In the polling model, the client decides when to retrieve a possible
result based on a call to a oneway method In standard polling, there may be nothing to
retrieve, so the client continues polling until it receives a valid value or decides to stop
As a matter of convention, passing an object reference to another distributed object(especially for the express intent of callbacks) demands declaring its registration method as
oneway The oneway keyword tells the IDL compiler to generate code that does not
block on the invocation waiting for the called operation to return This nonblockingbehavior prevents the registration method from making method calls on the incomingobject reference If neither object is multithreaded, a server calling a client can cause dead-
lock Without the use of oneway, the client would wait for the server to return, and the
server would wait for the client method to return (Fig 26.14) Section 26.6 presents an
explicit example of the use of the oneway keyword.
Good Programming Practice 26.4
To avoid deadlock, use the oneway keyword whenever passing an object reference to a
Trang 3526.6 Example: AlarmClock
The AlarmClock example is a different type of application from the SystemClock
ex-ample SystemClock is a typical pull-model application—the client decides when to
re-trieve information from the server The AlarmClock example, on the other hand, is a
typical push-model application—the server decides when to send information to the client.
In AlarmClock, the client sets a server-side “alarm,” then waits for the server to wake it
up when the alarm sounds In this example, the client generates a random sleep time withwhich to set the alarm clock When the alarm goes off, the server notifies the client and theawakened client displays a new sleep time and resets the alarm
26.6.1 AlarmClock.idl
Figure 26.15 is the IDL declaring the two servers
Line 4 declares the module name, and lines 5 and 9 declare the names of the server types The module has two interface declarations—the server interface and the callback interface The main server is AlarmClock, and AlarmListener is the callback definition Using the keyword const, line 10 defines a constant called NAME for the implementation code when we bind to the Naming Service AlarmClock method addAlarmListener at line 12–13 adds AlarmListener objects to a list of callback objects—any object holding a reference to an AlarmListener can call method upda- teTime The caller sends in an arbitrary name for the server to associate the caller’s object
reference with the name as a primary key An AlarmListener object is a reference to a listener, so we add keyword oneway to make sure the compiler generates nonblocking code for this operation The object implementing the AlarmListener interface can reg- ister itself with AlarmClock and then wait until the alarm expires Figure 26.16 is the
implementation of the “real” server
15 void setAlarm( in string listenerName,
16 in long long seconds );
18 };
Fig 26.15 alarmclock1.idl
Trang 3626.6.2 AlarmClockImpl.java
In Fig 26.16, lines 21–52 are the same as method register in SystemClockImpl
(Fig 26.4, lines 26–59) Lines 26–29 check the incoming arguments Line 32 creates an ORB
using the ORB.init factory method, and line 35 connects with the ORB Lines 38–41 find
a reference to a Naming Service Lines 45–47 create a NameComponent object, and line 50 sends this NameComponent object to the Naming Service using method rebind Lines 56–77 declares the addAlarmListener registration method After the stan- dard argument checks, Line 76 stores the listener the incoming name in a Hashtable, if the name and listener had not been saved The Hashtable contains the listener name and
an AlarmTimer object that sleeps the required number of seconds, then notifies the tener that the alarm has sounded (AlarmTimer inherits from java.util.Timer
lis-which handles the threading for calling the client independent of the main thread) Inner
class TaskWrapper (registered with the AlarmTimer at lines 90 and 91) calls the tener method updateTime in method TaskWrapper.run (lines 143–151) and promptly removes itself as an alarm Every time a client sets an alarm using method set- Alarm (lines 81–92), we create a new TaskWrapper and return to the caller as fast as
18 private Hashtable alarmList = new Hashtable();
19
21 public void register( String corbaName, String params[] )
28 throw new IllegalArgumentException(
29 "Registration name cannot be null or blank" );
30
Fig 26.16 AlarmClockImpl is the AlarmClock server implementation
(part 1 of 4)
Trang 3731 // create and initialize ORB
32 ORB orb = ORB.init( params, null );
45 NameComponent namingComponent =
46 new NameComponent( corbaName, "" );
47 NameComponent path[] = { namingComponent };
48
50 naming.rebind( path, this );
51 System.out.println( "Rebind complete" );
62 throw new IllegalArgumentException(
63 "Name cannot be null or blank" );
64 else
65
66 if ( alarmList.get( listenerName ) != null )
67 th row new IllegalArgumentException(
68 "Name is already registered, please choose another" );
69 else
70
71 if ( listener == null )
72 throw new IllegalArgumentException(
73 "Listener cannot be null" );
74
76 alarmList.put( listenerName, new AlarmTimer( listener ) );
77 }
78
Fig 26.16 AlarmClockImpl is the AlarmClock server implementation
(part 2 of 4)
Trang 3879 // Set an alarm for a client If client not registered
81 public void setAlarm( String name, long seconds )
82 {
84 AlarmTimer timer = ( AlarmTimer ) alarmList.get( name );
85
86 if ( timer == null )
87 throw new IllegalArgumentException(
88 "No clock found for the incoming name" );
95 public static void main( String args[] ) throws Exception
96 {
97 AlarmClockImpl alarm = new AlarmClockImpl();
98 alarm.register( AlarmClock NAME , args );
109 private class AlarmTimer extends Timer {
110
112 private AlarmListener listener;
Trang 3926.6.3 AlarmClockClient.java
Figure 26.17 is a simple GUI for the application The GUI consists of a JFrame that plays a String informing the user when the alarm has sounded
129 private class TaskWrapper extends TimerTask {
130
132 private AlarmListener listener;
133 private long seconds;
134
137 public TaskWrapper( AlarmListener l, long s )
150 this cancel();
151 }
152 } // end private inner class TaskWrapper
13 public class ClockClientGUI extends JFrame {
14 private JLabel outputLabel;
Trang 40AlarmClockClient (Fig 26.18) is the client for the AlarmClock service Lines 22–38 define the AlarmClockClient constructor Using the system time, Alarm- ClockClient gives itself a name and, after creating the GUI, passes the name to method connectToAlarmServer (lines 41–68) along with any incoming parameters Alarm- ClockClient connects to the AlarmClock the same way SystemClockClient connects to the TimeServer Line 48 creates an ORB object, using the ORB factory method init By passing the client reference in as the second argument, AlarmClock- Client registers itself with the ORB The newly instantiated ORB handles mediating allcalls made from and sent to the client The ORB, created as an object separate from the
AlarmClockClient , can control access to and from the AlarmClockClient, but
only if the ORB has a usable reference to complete invocations started (or ending) in the
stub client code Method init makes the AlarmClockClient ORB-enabled Using the same ORB, AlarmClockClient can obtain a reference to the Naming Service As
in the example from Fig 26.5, ORBs have mini-naming services that allow them to strap with a predefined list of external services (naming being one of them) Using the
boot-NamingContextHelper.narrow method, line 55 downcasts the CORBA object
returned from resolve_initial_references to an object of type text Figure 26.18 displays the output when the client and server connected
NamingCon-NameComponents allow clients to traverse the Naming Service to look for needed
services Lines 58–59 create a NameComponent object that the Naming Service uses to find the AlarmClock service When the AlarmClockClient calls the Naming Ser- vice methods resolve and downcasts the returned object reference into an object of type
22 new JLabel( "The alarm has not gone off " );
23 getContentPane().add( outputLabel, BorderLayout NORTH );
35 public void setText( String message )
36 {
37 outputLabel.setText( message );
38 }
39
Fig 26.17 ClockClientGUI informs the user when the alarm has sounded
(part 2 of 2)