Queued Components in COM+

download Queued Components in COM+

of 23

Transcript of Queued Components in COM+

  • 8/8/2019 Queued Components in COM+

    1/23

    Queued Components in COM+

    Queued components provide for an easy implementation of asynchronous (as well asdisconnected) method calls, where the client does not have to wait until the method call

    finishes. Queued components are very useful in batch processing applications or in a

    remote order entry type of environment. The Queued component architecture in COM+internally uses the MSMQ queues to deliver the messages (method calls) to a COM+

    component. The receiving components machine does not have to be online to receive the

    message. The transmitted message is stored in the queue and attempted for delivery whenthe receiving components machine becomes available. The basic transmission

    mechanism is shown below.

    You can also use the MSMQ API to implement asynchronous communication but COM+

    queued components hide much of the underlying complexity in using the MSMQ queues.A COM+ application can be set up to support queued components through the properties

    dialog using the component services explorer, as shown below.

    When you select the above check box for the COM+ application to be queued, COM+creates a set of MSMQ queues for the application. A Client uses the Queued Component

    1

    Client

    QC Recorder(COM component)

    MSMQ Queue

    MSMQ Queue

    MSMQ Queue

    Queued Component

    Listener

    Queued ComponentPla er (COM com .)

    COM Object

    Server

  • 8/8/2019 Queued Components in COM+

    2/23

    Recorder to call any methods on a queued interface of a component. You can think of

    the recorder as being similar to a proxy. The recorder has the same methods available as

    the queued components queued interface. When the client makes a method call, therecorder records it, and then when the client de-references (or deactivates) the recorder, it

    makes a message and sends it to the MSMQ queue. The MSMQ queue usually resides on

    the COM servers computer. On the server side, the Queued Component Listenerchecks the MSMQ queue for messages. When a message is found to be present, the

    listener instantiates a player object, which unpacks the method call in the message and

    invokes the queued component.Here are some of the important points to note when dealing with queued

    components.

    Queued component methods cannot have [out], or [out,retval], or [in,out] type ofparameters i.e., the only allowed attributes for method parameters is [in]. Also, the

    methods of a queued interface cannot return application specific HRESULTS. Note that

    this is necessary because of the asynchronous nature of calls. The client might have

    terminated before the called method returns from a queued component.

    If the client is interested in a response from a queued component, then the clientcan pass a response object as one of the parameters in a queued component call. Note that

    in this case the response object will be configured as the queued component itself. The

    client will have to instantiate this response object and specify the clients machine as the

    destination (using moniker approach) before invoking a call to the queued componentmethod on the server. In typical applications, the response object may write to a database

    on the client side or send an email to the client.

    The messages in the MSMQ queue are organized by their priority. A higher

    priority message will be at the front of the queue even if it arrived later than a low

    priority message. For example, in an order processing application, perhaps new ordersshould be given higher priority than cancellation orders. You can also use a separate

    queue for new order processing, and a separate one for order cancellations, and perhaps

    allocate more server computers for the new order processing as compared to ordercancellation processing.

    A message can contain any type of data e.g., text, binary, XML, disconnected

    recordset, a serialized COM object that implements IPersistStream or IPersistStorageinterface. Note that the receiver of the message has to know in advance the type of

    message being received.

    The receiving application can peek at the message before removing it from the

    MSMQ queue. The message is not dequeued from the MSMQ queue until it is guaranteed

    that the entire message has been received correctly. MSMQ also provides a set of COMclasses with connection point interfaces that can be used by the receiver to receive

    notification when there is a message waiting in the queue.

    Queued applications can be used in a disconnected environment such as wireless

    applications. In this case the client should be configured as an MSMQ independent client,

    2

  • 8/8/2019 Queued Components in COM+

    3/23

    so that if the remote server is unavailable (perhaps out of wireless range), the client will

    queue the message locally and the local client queue server will attempt to deliver it to

    the destination queue at a later time when connectivity is reestablished.

    Queued component architecture can be used to develop a distributed and scalable

    platform for computationally intensive applications. A group of COM servers can listento a queue for computational jobs to arrive. Each server when it becomes available goes

    to the queue to pick a job to perform. This technique can be used to develop fault-

    tolerant, scalable distributed multiprocessing applications.

    There are two types of MSMQ queues, public and private. Public queues are

    published in the active directory, whereas a private queue is listed only on a particular

    computer and you have to use the exact path name of the private queue to be able to useit.

    Queued components require public queues so the MSMQ has to be set up in a

    domain environment mode. Thus for queued components to work, the computer on whichyou are using MSMQ must be set up as a primary domain controller and also have the

    active directory service running properly.

    The message sent can be part of a transaction. More details on it later in this handout.

    Configuring your Windows 2000 server for Queued Components:Step 1: Configure your computer for Active directory services and to be the primary

    domain controller. From the start menu choose, Administrative tools->Configure yourserver.

    Click on the active directory link. Then click on the start Active directory wizard link.

    3

  • 8/8/2019 Queued Components in COM+

    4/23

    Choose domain controller for a new domain if you do not have an existing domain.

    4

  • 8/8/2019 Queued Components in COM+

    5/23

    5

  • 8/8/2019 Queued Components in COM+

    6/23

    Make sure your computer is online (either via modem, or via the network card) otherwiseyou will get the following error message.

    6

  • 8/8/2019 Queued Components in COM+

    7/23

    7

  • 8/8/2019 Queued Components in COM+

    8/23

    After you click finish, it may take several minutes to install the active directory services

    and the DNS server.

    Next, you need to install the MSMQ server on your machine. From the control panel,

    choose add/remove programs, then click on add/remove windows components.

    8

  • 8/8/2019 Queued Components in COM+

    9/23

    Then check Message Queuing Services and click on next.

    9

  • 8/8/2019 Queued Components in COM+

    10/23

    Follow the wizard screens and accept defaults.

    Testing to see if MSMQ is installed properly:If you are able to successfully create a public queue, then MSMQ is hopefully

    installed correctly. From the start menu choose, administrative tools->computermanagement. Expand on Services and Applications, and then Message Queuing.

    Right click on the Public Queues and choose new public Queue. Give the queue a

    name of MyQueue.

    10

  • 8/8/2019 Queued Components in COM+

    11/23

    If you are able to create the public queue successfully, then MSMQ is correctly installed.

    Queued Component Transactions:Queued components can take a part in a transaction on the client side or on the

    server side. If the transaction is aborted on the client side, the message is never sent to the

    destination MSMQ. Note that the client sends the message only after the method callfinishes on the client-side.

    On the server-side, the QC player which reads the message from MSMQ queue is

    a transactional component. If the method call to the server component fails, the QCplayer puts the message back in the queue to try it later. However, this may have the

    potential for infinite retries if each time the call runs into some kind of error message.

    This situation is referred to as a poison message. To solve this problem, COM+ has sixretry queues for each queued application. Five of these are named appname_n where n

    varies from 0 to 4. The sixth retry queue is name appname_deadqueue. The message in

    the appname_0 queue is retried every one minute and moved to the appname_1 queue if

    three attempts fail. Similarly, the message in appname_1 queue is retried every twominutes (twice as long as the previous queue) and moved to queue number 2 if three

    attempts fail. Finally if there are problems, the message will be moved to the dead queue

    where it will remain until removed manually using the component services explorer.

    11

  • 8/8/2019 Queued Components in COM+

    12/23

    In some situations, you may want to know if the message had a problem in executing and

    is being moved to the dead queue. You can specify an exception class with a queued

    component for this purpose through the component services explorer.

    Example: First create an SQL server database for testing purposes.

    Create a SQL server database called EStore with the following tables in it.The SQL script file for the EStore database is shown below:

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FK_Orders_Customers]') andOBJECTPROPERTY(id, N'IsForeignKey') = 1)

    ALTER TABLE [dbo].[Orders] DROP CONSTRAINT FK_Orders_Customers

    GO

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FK_Inventory_Products]') and

    OBJECTPROPERTY(id, N'IsForeignKey') = 1)

    ALTER TABLE [dbo].[Inventory] DROP CONSTRAINT FK_Inventory_Products

    GO

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FK_Orders_Products]') andOBJECTPROPERTY(id, N'IsForeignKey') = 1)

    ALTER TABLE [dbo].[Orders] DROP CONSTRAINT FK_Orders_Products

    GO

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Customers]') and

    OBJECTPROPERTY(id, N'IsUserTable') = 1)drop table [dbo].[Customers]

    GO

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Inventory]') and

    OBJECTPROPERTY(id, N'IsUserTable') = 1)

    drop table [dbo].[Inventory]

    GO

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Orders]') and OBJECTPROPERTY(id,

    N'IsUserTable') = 1)drop table [dbo].[Orders]

    GO

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Products]') and

    OBJECTPROPERTY(id, N'IsUserTable') = 1)

    drop table [dbo].[Products]

    GO

    CREATE TABLE [dbo].[Customers] (

    [CustID] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,[CustFname] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,

    [CustLname] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,

    [CustAccountBalance] [money] NULL ,

    [CustCreditLimit] [money] NULL

    ) ON [PRIMARY]

    GO

    CREATE TABLE [dbo].[Inventory] (

    [ProdID] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,

    12

  • 8/8/2019 Queued Components in COM+

    13/23

    [InStockQty] [bigint] NOT NULL ,

    [Inum] [bigint] IDENTITY (1, 1) NOT NULL

    ) ON [PRIMARY]

    GO

    CREATE TABLE [dbo].[Orders] (

    [OrderID] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,[CustID] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,

    [ProdID] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,

    [Quantity] [int] NOT NULL ,

    [Price] [money] NOT NULL

    ) ON [PRIMARY]

    GO

    CREATE TABLE [dbo].[Products] (

    [ProdID] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,

    [ProdName] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,

    [ProdPrice] [money] NOT NULL

    ) ON [PRIMARY]

    GO

    You can initialize some data in the database as:

    13

  • 8/8/2019 Queued Components in COM+

    14/23

    Now let us create a queued COM component.

    Create an ATL COM wizard project. Name the project OrderQ. Accept all the defaults.

    From the insert menu, choose New ATL object, then choose simple object. Name thecomponent Order, select threading model to be Free (we will manually change it to

    Neutral later on). Also check the ISupportErrorInfo as shown below.

    14

  • 8/8/2019 Queued Components in COM+

    15/23

    Type the following in the StdAfx.h file, right after #include line :

    #import "c:\program files\common files\system\ado\msado15.dll" \

    no_namespace \rename("EOF","adoEOF")

    Change the threading model in Order.rgs file to Neutral as shown below:.

    InprocServer32 = s '%MODULE%'

    {val ThreadingModel = s 'Neutral'

    }

    Add a method to the IOrder interface called AddOrder with the following IDL.

    [in] BSTR oid, [in] BSTR cid, [in] BSTR pid, [in] int qty, [in] CY amt

    Type the following in the AddOrder method. You will need to include the filein order to use the _itow function (int to wide character).

    // Order.cpp : Implementation of COrder

    #include "stdafx.h"

    #include "OrderQ.h"

    #include "Order.h"

    15

  • 8/8/2019 Queued Components in COM+

    16/23

    #include

    STDMETHODIMP COrder::AddOrder(BSTR oid, BSTR cid, BSTR pid, int qty, CY amt)

    {

    // TODO: Add your implementation code here

    HRESULT hr;_ConnectionPtr pCn;_RecordsetPtr pRecordset;

    hr=pCn.CreateInstance(__uuidof(Connection));

    if (SUCCEEDED(hr))

    {

    _bstr_t cn(L"Provider=SQLOLEDB;User ID=sa;Password=;Initial Catalog=EStore;Data

    Source=tennis;");

    hr = pCn->Open(cn, _bstr_t(L""),_bstr_t(L""),adModeUnknown);

    if (SUCCEEDED(hr)){

    _bstr_t SQ(L"INSERT INTO Orders (OrderID,CustID,ProdID,Quantity,Price) ");SQ += _bstr_t(L"VALUES (");

    SQ += _bstr_t(L"'");

    SQ += oid;

    SQ += _bstr_t(L"',");

    SQ += _bstr_t(L"'");

    SQ += cid;

    SQ += _bstr_t(L"',");

    SQ += _bstr_t(L"'");

    SQ += pid;

    SQ += _bstr_t(L"', " );

    wchar_t s1[10];

    SQ += _bstr_t(_itow(qty,s1,10));

    SQ += _bstr_t(",");

    SQ += _bstr_t(amt);SQ += _bstr_t(L")");

    Sleep(10000); // for debugging purposes

    _variant_t vRecsAffected(0L);

    pRecordset = pCn->Execute(SQ,&vRecsAffected,adOptionUnspecified);

    }

    }

    else return E_FAIL;

    return S_OK;

    }

    Build the dll.

    Test VB Client: Create a VB standard exe project, add a reference to the OrderQ typelibrary. Put a button on the form with the following code:

    Private Sub Command1_Click()

    Dim s1 As New Order

    s1.AddOrder "O101", "C101", "P101", 2, 50#

    End Sub

    16

  • 8/8/2019 Queued Components in COM+

    17/23

    Run the client to see if another row for order O101 gets added to the orders table.

    Delete the row corresponding to order O101after it has been added to the Orders table

    through the SQL server Enterprise Manager.

    Making the component Queued:

    Step 1: Add the OrderQ.Order component to an existing COM+ application (or you cancreate a new application). I added the Order component to the existing MyST COM+

    application on my computer.

    Step 2: Make the application queued, and also enable the queue listener on the COM+application. You can do this by right clicking on the application and choosing properties,

    and the queuing tab.

    17

  • 8/8/2019 Queued Components in COM+

    18/23

    Note that as soon as you select the application to be queued, six queues for the

    application are created. You can view these by selecting thestart->administrative tools-

    >computermanagement and then expanding on message queuing.

    Step 3: You need to make an interface in the OrderQ.Order component queued. From the

    component services explorer, expand on the Order component, and then the interfaces.

    Right click on the IOrder interface, and choose properties, then check the queued check

    box from the queuing tab.

    18

  • 8/8/2019 Queued Components in COM+

    19/23

    Note: If the COM+ application to which you added the Order component had the security

    enabled on it, and if you had created roles earlier, then either you will have to enable

    roles for the Order component, or remove the Enforce access .. check mark below, inorder to successfully test the component.

    Step 4: Start the COM+ Queued application by going through the component servicesexplorer and right clicking on the application and choosing start application. Note that

    the Queued COM+ application has to be running in order for the client to be able to

    deposit a message in the queue.

    Monikers: Monikers are special COM objects whose job is to locate and create otherCOM objects. For example the job of the standard new moniker is to locate a COMobject through its CLSID or ProgID, and create an object of it.

    As another example of a moniker, there is a standard URL moniker that is used inside

    a browser for registering and invoking ActiveX controls that are downloaded from a webserver. An ActiveX control can be embedded inside an HTML page by using the object

    tag e.g.,

    When the page is downloaded by the browser, the code for the ActiveX control isdownloaded also, if the control is not registered on the browsers machine. After

    downloading, the Activex control is registered and an object of it is created and launched

    in the browser. All of these tasks are accomplished by the URL moniker.

    COM+ has introduced two special monikers related to queued components. One is a

    queue moniker and the other is the new moniker. The queue moniker is responsible for

    19

  • 8/8/2019 Queued Components in COM+

    20/23

    creating the recorder object on the client side. The queue moniker pipes the recorder to

    the new moniker to create a correct client-side proxy for the queued component. In

    Visual Basic, the client side code using the queue and the new monikers appears as:dim recorder as new MyProject.MyQueuedComp

    set rc=GetObject(queue:ComputerName=kiwi/new:MyProj.MyQComp)

    rc.methodname()

    In a VC++ client, the queue and new monikers can be invoked as:

    CoGetObject(Lqueue:Priority=5,ComputerName=kiwi/new:MyProj.MyQComp,NULL, IID_IDispatch, (void **) &pIDispatch)

    Note that the message from the client is not sent out until the client release the reference

    to the queued component proxy object i.e., the recorder object created through the

    GetObject or CoGetObject call.

    Step 5: Modify the VB client to invoke the component through the queue and new

    monikers as shown below.Private Sub Command1_Click()

    ' Dim s1 As New Order

    ' s1.AddOrder "O101", "C101", "P101", 2, 50#

    Dim objOrder As Order

    Set objOrder = GetObject("queue:Priority=5,

    ComputerName=tennis/new:OrderQ.Order")

    objOrder.AddOrder "O101", "C101", "P101", 2, 50#

    End Sub

    Run the client, and check the database to see if a new record for the order has been added

    to the order table (after 10 seconds, recall that the Order component had a Sleep of 10seconds to test the asynchronous behavior). You will notice that when you press the

    button in the VB client, the call returns immediately because now it is an asynchronous

    call. Also, the queue moniker feeds to the new moniker to create the client-side side

    proxy.

    The Orders table should have the Order O101 added to it after 10 seconds (because of an

    intentional sleep call in the component) as shown below.

    20

  • 8/8/2019 Queued Components in COM+

    21/23

    Step 6: Delete the Order O101 from the Orders table. Then modify the client to invoke

    the COM+ component directly without the queue moniker to test the synchronous callbehavior, as shown below.

    Private Sub Command1_Click()Dim s1 As New Order

    s1.AddOrder "O101", "C101", "P101", 2, 50#

    Dim objOrder As Order

    Set objOrder = GetObject("queue:Priority=5,

    ComputerName=tennis/new:OrderQ.Order")

    objOrder.AddOrder "O101", "C101", "P101", 2, 50#End Sub

    The call will still modify the Orders table, but the client will hang for 10 seconds as it is

    now a synchronous call.

    Note: If you get error messages or if the database is not being modified, check the publicmessage queue for the application to see if messages are being delivered. Also, check to

    see if the security options on the application and the Order component are set properly. If

    security is enabled, then proper roles are also enabled for the Order component.

    If the security is enabled on the application and the Order component, then the listener

    will pick up the message from the queue, but the call to the Order component will fail

    because of the security settings. Since the call is part of a transaction, the message will beput back and retried each minute as mentioned earlier. After three failed attempts, the

    message will be moved to the myst_1 queue, as shown below.

    21

  • 8/8/2019 Queued Components in COM+

    22/23

    Step 7: Delete the Order O101 from the orders table. Enable the security on the COM+application in which the queued component is residing. Enable the appropriate roles on

    the components interfaces. Run the client through the moniker to see if the message gets

    delivered (i.e., the database is modified for the Orders O101 correctly).

    22

  • 8/8/2019 Queued Components in COM+

    23/23

    23