|
CS 696 Emerging Technologies: Distributed Objects |
|
---|
Spring Semester, 1998
ActiveX, DCOM, & JavaBeans
To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 14-May-98
Contents of Doc 36, ActiveX, DCOM, & JavaBeans
- References
- JavaBeans - More Features
- ActiveX Bridge
- Glasgow
- Runtime Containment and Services
- Drag and Drop
- JavaBeans Activation Framework
- Object Aggregation/Delegation Model
- Enterprise beans
- InfoBus
- ActiveX
- COM/DCOM
- IUnknown
- Monikers
- Automation
- COM/DCOM Servers
- DCOM Overall Architecture
- A DCOM-CORBA Example
- Corba IDL
- DCOM IDL
- CORBA C++ Class Interface
- CORBA C++ Implementation
- DCOM C++ Class Interface
- DCOM Server Main
- DCOM Client Code
- DCOM Object Activation
- DCOM Method Invocation
COM and DCOM: Microsoft's Vision for Distributed Objects, Roger
Sessions, John Wiley & Sons, 1998
Client/Server Progamming with Java and Corba, Orfali & Harkey, John
Wiley & Sons, 1997
Essential COM, Don Box, Addison Wesley, 1998
ActiveX Demystified, Chappell & Linthicum, Byte, Sept 1997,
pp56-64
DCOM and CORBA Side by Side, Step by Step, and Layer by Layer, by P.
Emerald Chung, Yennun Huang, Shalini Yajnik, Deron Liang, Joanne C. Shih,
Chung-Yih Wang, Yi-Min Wang
http://www.cs.wustl.edu/~schmidt/submit/Paper.html
http://java.sun.com/beans/softare/bridge/
The ActiveX bridge allows beans to operate as an ActiveX control and as a VB
component
I do not know about the performance, nor how the JVM is activated
Java Serialization does work in the ActiveX world with minor restrictions
Type Mapping between Java and ActiveX
Java Type | OLE Automation Type |
boolean | VT_BOOL |
char | VT_UI1 |
double | VT_R4 |
float | VT_R2 |
int | VT_I4 |
byte | VT_I2 |
short | VT_I2 |
long | VT_I4 |
java.lang.String | VT_BSTR |
java.awt.Color | VT_COLOR |
java.awt.Font | VT_FONT |
others | VT_DISPATCH |
Code-name for the next release of the JavaBeans specification
Documentation can be found at:
- http://java.sun.com/beans/glasgow/
Glasgow adds three new types of enhancements to JavaBeans:
"This protocol allows developers to nest Beans within other Beans more
seamlessly, where the nested Beans can procure additional services at runtime
from its environment in a standard fashion. Similarly, it provides a standard
mechanism for the environment or containing Bean to extend its capabilities
directly to Beans within it."
Will be part of the JDK
Will be part of the JDK
Supports Drag & Drop between Java programs and native applications
Is a standard extension of the JDK, available now
"With the JavaBeans Activation Framework, Java developers can take advantage of
standard services to determine the type of an arbitrary piece of data,
encapsulate access to it, discover the operations available on it, and to
instantiate the appropriate JavaBeans component to perform said operation(s).
For example, if a browser obtained a JPEG image, this framework would enable
the browser to identify that stream of data as an JPEG image, and from that
type, the browser could locate and instantiate an object that could manipulate,
or view that image."
"it has come apparent from much of the feedback from developers that
"aggregation" is a much overloaded term that is interpreted by many to solve
problems that this proposal does not nor should not address. In light of this
observation, we have reconsidered the general utility this facility provides
and have decided to defer the delivery of the implementation of this
specification until a future (post-Glasgow) JavaBeans release."
Component architecture for building distributed object-oriented business
applications in the Java programming language.
Enterprise JavaBeans 1.0 defines two types of enterprise Beans:
- A session object type.
- An entity object type.
Session objects
A typical session object has the following characteristics:
- Executes on behalf of a single client.
- Can be transaction-aware.
- Updates shared data in an underlying database.
- Does not represent directly shared data in the database, although it may
access and update such data.
- Is relatively short-lived.
- Is removed when the EJB server crashes. The client has to re-establish a
new session object to continue computation.
A typical EJB server and container provide a scalable runtime environment to
execute a large number of session objects concurrently.
Entity objects
A typical entity object has the following characteristics:
- Represents data in the database.
- Is transactional.
- Allows shared access from multiple users.
- Can be long-lived (lives as long as the data in the database).
- Survives crashes of the EJB server. A crash is transparent to the
client.
A typical EJB server and container provide a scalable runtime
environment for a large number of concurrently active entity objects.
"InfoBus enables dynamic exchange of data between JavaBeans components by
defining a small number of interfaces between cooperating Beans and specifying
the protocol for use of those interfaces. The protocols are based on a notion
of an information bus. All components which implement these interfaces can plug
into the bus. As a member of the bus any component can exchange data with
any other component in a structured way, including arrays, tables, and database
rowsets."
In the beginning there was OLE - Object Linking and Embedding
OLE was Microsoft's compound-document technology, which allows a word processor
document to contain a spreadsheet table, etc.
The second release (May 93) of OLE (OLE 2) introduced COM - Component Object
Model
COM provided a general mechanism for allowing one piece of software to provide
services to another piece of software
While OLE 2 used COM, COM was general, hence started to be used in may
different ways
Microsoft wanted a brand name for the functionality of COM
The brand name used at first was OLE, so OLE meant anything that use COM
In 1996 the brand name changed to ActiveX
Now OLE means just Object Linking and Embedding
ActiveX covers anything that uses COM
- An ActiveX control is just a component like a JavaBean
-
- Distributed COM (DCOM) started in 1996 allows COM to operate across a
network
Since DCOM is just using COM across the wire, be boundary between DCOM and COM
is not clear
In COM/DCOM we produce DLL's (Dynamic Linked Libraries) for use by other
programs
- DLL's are in binary format and can be written in any language
COM uses an IDL (interface definition language) to define interfaces to COM
objects
MIDL is the Microsoft's IDL compiler
COM IDL is based on the Open Software Foundation Distributed Computing
Environment Remote Procedure Call (OSF DCE RPC) IDL, but is modified a
bit
A COM interface is more a collection of function calls than the public
interface of an object
COM objects can support multiple interfaces
COM IDL does not support multiple inheritance or object state
Interface Names
Each interface has two names: physical and logical
The developer gives the interface the logical name: MyCalculator
The physical name is a 128-bit value assigned to the interface by the
CoCreateGuid method
The 128-bit value is an instance of a Globally Unique Identifier -
(GUID)
- BDA4A270-A1BA-11d0-8C2C-0080C73925BA
A GUID use to name an interface is called an Interface ID or IID
A GUID use to name an implementation is called a Class ID or CLSID
This interface must be supported be all COM/DCOM objects
interface IUnknown {
HRESULT QueryInterface([in] REFIID riid, [out] void **ppv);
ULONG AddRef( void );
ULong Release( void )
}
Virtual Table (vtable)
- The vtable is an array of function pointers
At run time a client accesses the methods in an interface through the vtable
for that interface
A client uses the QueryInerface method to determine which interfaces an object
supports
The client never access an interface method directly
AddRef and Release are used for memory management
COM/DCOM Objects
Also called an Active object
Clients get pointers to interfaces, not a reference or proxy to an object
In CORBA/RMI a client can get a reference to a remote object and "interact"
with the "same" object across sessions with the server
This is not the case with COM
Each time a client makes the first reference to an interface, an object that
supports the interface is created
If the object uses persistent data, the client needs to tell the object where
it is
Monikers are used to make activation of objects easier
Monikers are COM objects that will activate a COM object for a client
Since monikers are COM objects the client must provide the file containing the
data the moniker needs to create the object
Automation is an alternative method of clients invoking functions on a server
object
Automation is designed for use with simpler languages like Visual Basic (VB)
but works with C++
Originally this was called OLE Automation
Automation does not use vtables it uses dispatch interfaces (dispinterfaces)
Object Definition Language (ODL) is used to define interfaces for automation
dispinterface Dog
{
properties:
[id(0)] long Age;
methods:
[id(1)] long Bark;
[id(2)] long Sit;
[id(3)] long Run;
};
The
MKTYPELIB compiler compiles ODL
The implementation class needs to implement the IUnknown and IDispatch
interface
IDispatch interface which contains the following methods:
- Invoke maps an dispID to a method call or property access
-
- GetIDsOfNames converts text names of properties and methods to
dispIDs
-
- GetTypeInfoCount returns whether there is type information available
for this dispinterface
-
- GetTypeInfo returns metadata that describes the interface
DCOM has three types of servers:
In-process
- Executes in the same process space as their clients
-
- Implemented as DLL's
Local servers
- Executes in a separate process from their clients on the same machine
-
- Clients use the Lightweight RPC (LRPC) mechanism to communicate with a
local server
-
- Local servers implemented as .EXE's
Remote Servers
- Executes in a separate process on a remote machine and possibly on a
different operating system
-
- Clients use RPC mechanism to communicate with a remote server
What is a COM/DCOM Server?
A COM/DCOM server is a DLL or EXE that supports one or more server objects
A COM/DCOM server must:
Implement a class factory interface
- Server must implement a factory with the IClassFactory interface for each
supported class (CLSID) in the server
- If the class supports licensing, then server must use the IClassFactory2
interface
Register the classes it supports
- For each CLSID it must create one or more entries that provide the pathname
to the server DLL or EXE
Initialize the DCOM Library
- Use the CoInitiallize method to initialize COM/DCOM
-
- The Co stands for COM
Verify that the library is of a compatible version
- Call CoBuildVersion
Provide an unloading mechanism
- Server needs to have a way to terminate it self when there are no active
clients for its objects
Uninitialize the DCOM library
- Call CoUninilialize
Picture taken from:
DCOM and CORBA Side by Side, Step by Step, and Layer by Layer, by P.
Emerald Chung, Yennun Huang, Shalini Yajnik, Deron Liang, Joanne C. Shih,
Chung-Yih Wang, Yi-Min Wang
http://www.cs.wustl.edu/~schmidt/submit/Paper.html
This example, code and images are taken directly from :
DCOM and CORBA Side by Side, Step by Step, and Layer by Layer, by P.
Emerald Chung, Yennun Huang, Shalini Yajnik, Deron Liang, Joanne C. Shih,
Chung-Yih Wang, Yi-Min Wang
http://www.cs.wustl.edu/~schmidt/submit/Paper.html
Implement in CORBA and DCOM a Grid object
The grid object maintains a two-dimensional grid of integers
Grid has two interfaces
One to access the elements of the grid
One to reset the elements of the grid
interface grid1
{
long get(in short n, in short m);
void set(in short n, in short m, in long value);
};
interface grid2
{
void reset(in long value);
};
// multiple inheritance of interfaces
interface grid: grid1, grid2
{
};
// uuid and definition of IGrid1
[ object,
uuid(3CFDB283-CCC5-11D0-BA0B-00A0C90DF8BC),
helpstring("IGrid1 Interface"),
pointer_default(unique)
]
interface IGrid1 : IUnknown {
import "unknwn.idl";
HRESULT get([in] SHORT n, [in] SHORT m, [out] LONG *value);
HRESULT set([in] SHORT n, [in] SHORT m, [in] LONG value);
};
// uuid and definition of IGrid2
[ object,
uuid(3CFDB284-CCC5-11D0-BA0B-00A0C90DF8BC),
helpstring("IGrid2 Interface"),
pointer_default(unique)
]
interface IGrid2 : IUnknown {
import "unknwn.idl";
HRESULT reset([in] LONG value);
};
// uuid and definition of type library
[ uuid(3CFDB281-CCC5-11D0-BA0B-00A0C90DF8BC),
version(1.0),
helpstring("grid 1.0 Type Library)
]
library GRIDLib
{
importlib("stdole32.tlb");
// uuid and definition of class
[ uuid(3CFDB287-CCC5-11D0-BA0B-00A0C90DF8BC),
helpstring("Grid Class")
]
// multiple interfaces
coclass CGrid
{ [default] interface IGrid1;
interface IGrid2;
};
};
include "grid.hh" // IDL-generated interface header file
class grid_i : public gridBOAImpl {
public:
virtual CORBA::Long get(CORBA::Short n, CORBA::Short m,
CORBA::Environment &env);
virtual void set(CORBA::Short n, CORBA::Short m,
CORBA::Long value, CORBA::Environment &env);
virtual void reset(CORBA::Long value,
CORBA::Environment &env);
grid_i(CORBA::Short h, CORBA::Short w);
virtual ~grid_i();
private:
CORBA::Long **m_a;
CORBA::Short m_height, m_width;
};
#include "grid_i.h"
CORBA::Long grid_i::get(CORBA::Short n, CORBA::Short m,
CORBA::Environment &) {
return m_a[n][m];
}
void grid_i::set(CORBA::Short n, CORBA::Short m,
CORBA::Long value, CORBA::Environment &) {
m_a[n][m] = value;
}
void grid_i::reset(CORBA::Long value, CORBA::Environment &) {
short n, m;
for (n = 0; n < m_height; n++)
for (m = 0; m < m_width; m++)
m_a[n][m]=value;
return;
}
grid_i::grid_i(CORBA::Short h, CORBA::Short w) {
m_height=h; // set up height
m_width=w; // set up width
m_a = new CORBA::Long* [h];
for (int i = 0; i < h; i++ )
m_a[i] = new CORBA::Long[w];
}
grid_i::~grid_i () {
for (int i = 0; i < m_height; i++)
delete[] m_a[i];
delete[] m_a;
}
#include "grid.h" // IDL-generated interface header file
class CClassFactory : public IClassFactory {
public:
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
STDMETHODIMP_(ULONG) AddRef(void) { return 1; };
STDMETHODIMP_(ULONG) Release(void) { return 1; }
// IClassFactory
STDMETHODIMP CreateInstance(LPUNKNOWN punkOuter,
REFIID iid, void **ppv);
STDMETHODIMP LockServer(BOOL fLock)
{ return E_FAIL; };
};
class CGrid : public IGrid1, public IGrid2 {
public:
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
STDMETHODIMP_(ULONG) AddRef(void)
{ return InterlockedIncrement(&m_cRef); }
STDMETHODIMP_(ULONG) Release(void)
{ if (InterlockedDecrement(&m_cRef) == 0)
{ delete this; return 0; }
return 1;
}
// IGrid1
STDMETHODIMP get(IN SHORT n, IN SHORT m,
OUT LONG *value);
STDMETHODIMP set(IN SHORT n, IN SHORT m,
IN LONG value);
// IGrid2
STDMETHODIMP reset(IN LONG value);
CGrid(SHORT h, SHORT w);
~CGrid();
private:
LONG m_cRef, **m_a;
SHORT m_height, m_width;
};
#include "cgrid.h"
STDMETHODIMP CClassFactory::QueryInterface(REFIID riid, void** ppv) {
if (riid == IID_IClassFactory || riid == IID_IUnknown) {
*ppv = (IClassFactory *) this;
AddRef(); return S_OK;
}
*ppv = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP
CClassFactory::CreateInstance(LPUNKNOWN p, REFIID riid, void** ppv) {
IGrid1* punk = (IGrid1*) new CGrid(100, 100);
HRESULT hr = punk->QueryInterface(riid, ppv);
punk->Release();
return hr;
}
STDMETHODIMP CGrid::QueryInterface(REFIID riid, void** ppv) {
if (riid == IID_IUnknown || riid == IID_IGrid1)
*ppv = (IGrid1*) this;
else if (riid == IID_IGrid2) *ppv = (IGrid2*) this;
else { *ppv = NULL; return E_NOINTERFACE; }
AddRef(); return S_OK;
}
STDMETHODIMP CGrid::get(IN SHORT n, IN SHORT m, OUT LONG* value) {
*value = m_a[n][m];
return S_OK;
}
STDMETHODIMP CGrid::set(IN SHORT n, IN SHORT m, IN LONG value) {
m_a[n][m] = value;
return S_OK;
}
STDMETHODIMP CGrid::reset(IN LONG value) {
SHORT n, m;
for (n=0; n < m_height; n++)
for (m=0; m < m_width; m++)
m_a[n][m] = value;
return S_OK;
}
CGrid::CGrid(SHORT h, SHORT w) {
m_height = h;
m_width= w;
m_a = new LONG*[m_height];
for (int i=0; i < m_height; i++)
m_a[i] = new LONG[m_width];
m_cRef = 1;
}
extern HANDLE hevtDone;
CGrid::~CGrid () {
for (int i=0; i < m_height; i++)
delete[] m_a[i];
delete[] m_a;
SetEvent(hevtDone);
}
HANDLE hevtDone;
void main()
{
// Event used to signal this main thread
hevtDone = CreateEvent(NULL, FALSE, FALSE, NULL);
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
CClassFactory* pcf = new CClassFactory;
hr = CoRegisterClassObject(CLSID_CGrid, pcf,
CLSCTX_SERVER, REGCLS_MULTIPLEUSE , &dwRegister);
// Wait until the event is set by CGrid::~CGrid()
WaitForSingleObject(hevtDone, INFINITE);
CloseHandle(hevtDone);
CoUninitialize();
}
#include "grid.h"
void main(int argc, char**argv)
{
IGrid1 *pIGrid1;
IGrid2 *pIGrid2;
LONG value;
CoInitialize(NULL); // initialize COM
CoCreateInstance(CLSID_CGrid, NULL, CLSCTX_SERVER,
IID_IGrid1, (void**) &pIGrid1);
pIGrid1->get(0, 0, &value);
pIGrid1->QueryInterface(IID_IGrid2, (void**) &pIGrid2);
pIGrid1->Release();
pIGrid2->reset(value+1);
pIGrid2->Release();
CoUninitialize();
}
(1.) Client calls COM library's CoCreateInstance() with CLSID_Grid and
IID_IGrid1.
(2.) COM infrastructure starts an object server for CLSID_Grid.
(3.) As shown in the server main program, server creates class factories for
all supported CLSIDs, and calls CoRegisterClassObject() to register each
factory.
Server blocks on waiting for, for example, an event to be set to signal that
the server is no longer needed. Incoming client requests will be served by
other threads.
(4.) COM obtains the IClassFactory pointer to the CLSID_Grid factory, and
invokes CreateInstance() on it.
(5.) In CreateInstance(), server creates an object instance and makes a
QueryInterface() call to obtain an interface pointer to the IID_IGrid1
interface.
(6.) COM returns the interface pointer as pIGrid1 to the client.
[1.] Client calls pIGrid1->get() which eventually invokes CGrid::get() in
the server.
[2.] To obtain a pointer to another interface IID_IGrid2 of the same object
instance, client calls pIGrid1->QueryInterface() which invokes
CGrid::QueryInterface.
[3.] When finishing using pIGrid1, client calls pIGrid1->Release() (which
may not invoke CGrid::Release()).
[4.] Client calls pIGrid2->reset() which invokes CGrid::reset.
[5.] Client calls pIGrid2->Release() which invokes CGrid::Release().
DCOM Object Activation/Method Invocation
Picture taken from:
DCOM and CORBA Side by Side, Step by Step, and Layer by Layer, by P.
Emerald Chung, Yennun Huang, Shalini Yajnik, Deron Liang, Joanne C. Shih,
Chung-Yih Wang, Yi-Min Wang
http://www.cs.wustl.edu/~schmidt/submit/Paper.html
Copyright © 1998 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
All rights reserved.
visitors since 14-May-98