summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwilson_d <wilson_d@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2004-10-07 15:07:04 +0000
committerwilson_d <wilson_d@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2004-10-07 15:07:04 +0000
commit77c566edf39533401136410e0f00dbfd7e525fd1 (patch)
tree0b6bff61c6c1d96a3a819596f7f329effb3a57b6
parent699787b7ccfd5da1c7ad001fec91e815e163e16b (diff)
downloadATCD-77c566edf39533401136410e0f00dbfd7e525fd1.tar.gz
ChangeLogTag: Thu Oct 7 09:40:51 2004 Dale Wilson <wilson_d@ociweb.com>
-rw-r--r--TAO/ChangeLog_pnotify179
-rw-r--r--TAO/docs/notification/reliability.html346
-rw-r--r--TAO/orbsvcs/orbsvcs/CosNotification.mpc25
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Admin.cpp111
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Admin.h25
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Admin.inl14
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/AdminProperties.cpp36
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/AdminProperties.h17
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/AdminProperties.inl24
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/AllocTracker.h81
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Bit_Vector.cpp118
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Bit_Vector.h76
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Builder.cpp202
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Builder.h50
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.cpp119
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.h13
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/CosNotify_Service.cpp5
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Delivery_Method.cpp80
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Delivery_Method.h78
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.cpp192
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.h78
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.cpp179
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.h71
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Delivery_Request.cpp87
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Delivery_Request.h121
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/EventChannel.cpp299
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/EventChannel.h34
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.cpp291
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.h85
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/EventType.cpp35
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/EventType.h10
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.cpp74
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.h15
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Event_Manager.cpp2
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Event_Persistence_Factory.h52
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Event_Persistence_Strategy.h47
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.cpp72
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.h9
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/ID_Factory.cpp1
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/ID_Factory.h6
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/ID_Factory.inl11
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.cpp227
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.h102
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.inl1
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Object.cpp90
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Object.h22
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Object.inl2
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/POA_Helper.cpp34
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/POA_Helper.h8
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Peer.h3
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Persistent_File.cpp158
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Persistent_File.h89
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.cpp401
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.h203
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Properties.h6
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Properties.inl12
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/PropertySeq.cpp12
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/PropertySeq.h10
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/PropertySeq.inl8
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.h3
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.inl7
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Property_T.h9
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Property_T.inl26
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Proxy.cpp81
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Proxy.h40
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/ProxyConsumer.cpp21
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.cpp18
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.h1
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/ProxySupplier_T.cpp3
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Proxy_T.cpp7
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/QoSProperties.cpp81
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/QoSProperties.h32
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/QoSProperties.inl97
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.cpp39
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.h50
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.cpp267
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.h100
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.inl2
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Routing_Slip.cpp878
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Routing_Slip.h241
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.cpp803
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.h264
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.cpp120
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.h92
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.cpp46
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.h58
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.cpp233
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.h128
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.cpp22
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.h3
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.cpp104
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.h26
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Topology_Factory.h46
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Topology_Loader.cpp16
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Topology_Loader.h73
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Topology_Object.h2
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/Topology_Object.inl2
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/XML_Saver.h4
-rw-r--r--TAO/orbsvcs/orbsvcs/Notify/XML_Topology_Factory.h2
-rw-r--r--TAO/orbsvcs/orbsvcs/NotifyExt.idl49
-rw-r--r--TAO/orbsvcs/tests/Notify/PluggableTopology/PlugTop.mpc19
-rw-r--r--TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Saver.cpp37
-rw-r--r--TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Saver.h39
-rw-r--r--TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.cpp26
-rw-r--r--TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.h31
-rw-r--r--TAO/orbsvcs/tests/Notify/PluggableTopology/main.cpp109
-rw-r--r--TAO/orbsvcs/tests/Notify/PluggableTopology/plugtop_export.h40
-rw-r--r--TAO/orbsvcs/tests/Notify/PluggableTopology/plugtop_ns.conf3
-rw-r--r--TAO/orbsvcs/tests/Notify/Reconnecting/Consumer.cpp1878
-rw-r--r--TAO/orbsvcs/tests/Notify/Reconnecting/Consumer.h300
-rw-r--r--TAO/orbsvcs/tests/Notify/Reconnecting/README351
-rw-r--r--TAO/orbsvcs/tests/Notify/Reconnecting/Reconnecting.mpc12
-rw-r--r--TAO/orbsvcs/tests/Notify/Reconnecting/Supplier.cpp1368
-rw-r--r--TAO/orbsvcs/tests/Notify/Reconnecting/Supplier.h209
-rw-r--r--TAO/orbsvcs/tests/Notify/Reconnecting/event.conf6
-rw-r--r--TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt.conf10
-rw-r--r--TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt_both.conf5
-rw-r--r--TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt_topo.conf3
-rw-r--r--TAO/orbsvcs/tests/Notify/Reconnecting/ns_st.conf4
-rw-r--r--TAO/orbsvcs/tests/Notify/Reconnecting/ns_st_both.conf4
-rw-r--r--TAO/orbsvcs/tests/Notify/Reconnecting/ns_st_topo.conf2
-rwxr-xr-xTAO/orbsvcs/tests/Notify/Reconnecting/run_test.pl386
-rw-r--r--TAO/orbsvcs/tests/Notify/XML_Persistence/XML_Persistence.mpc2
-rw-r--r--TAO/orbsvcs/tests/Notify/XML_Persistence/main.cpp360
-rwxr-xr-xTAO/orbsvcs/tests/Notify/XML_Persistence/run_test.pl62
-rw-r--r--TAO/orbsvcs/tests/Notify/XML_Persistence/svc.conf2
-rw-r--r--TAO/orbsvcs/tests/Notify/lib/Periodic_Consumer.cpp6
127 files changed, 13992 insertions, 136 deletions
diff --git a/TAO/ChangeLog_pnotify b/TAO/ChangeLog_pnotify
new file mode 100644
index 00000000000..5b3d2a6cca5
--- /dev/null
+++ b/TAO/ChangeLog_pnotify
@@ -0,0 +1,179 @@
+Thu Oct 7 09:40:51 2004 Dale Wilson <wilson_d@ociweb.com>
+
+ * ChangeLog_pnotify:
+
+ * docs/notification/reliability.html:
+
+ * orbsvcs/orbsvcs/CosNotification.mpc:
+ * orbsvcs/orbsvcs/Notify/Admin.h:
+ * orbsvcs/orbsvcs/Notify/Admin.inl:
+ * orbsvcs/orbsvcs/Notify/Admin.cpp:
+ * orbsvcs/orbsvcs/Notify/AdminProperties.h:
+ * orbsvcs/orbsvcs/Notify/AdminProperties.inl:
+ * orbsvcs/orbsvcs/Notify/AdminProperties.cpp:
+ * orbsvcs/orbsvcs/Notify/AllocTracker.h:
+ * orbsvcs/orbsvcs/Notify/Bit_Vector.h:
+ * orbsvcs/orbsvcs/Notify/Bit_Vector.cpp:
+ * orbsvcs/orbsvcs/Notify/Builder.h:
+ * orbsvcs/orbsvcs/Notify/Builder.cpp:
+ * orbsvcs/orbsvcs/Notify/ConsumerAdmin.h:
+ * orbsvcs/orbsvcs/Notify/ConsumerAdmin.cpp:
+ * orbsvcs/orbsvcs/Notify/CosNotify_Service.cpp:
+ * orbsvcs/orbsvcs/Notify/Delivery_Method.h:
+ * orbsvcs/orbsvcs/Notify/Delivery_Method.cpp:
+ * orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.h:
+ * orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.cpp:
+ * orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.h:
+ * orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.cpp:
+ * orbsvcs/orbsvcs/Notify/Delivery_Request.h:
+ * orbsvcs/orbsvcs/Notify/Delivery_Request.cpp:
+ * orbsvcs/orbsvcs/Notify/EventChannel.h:
+ * orbsvcs/orbsvcs/Notify/EventChannel.cpp:
+ * orbsvcs/orbsvcs/Notify/EventChannelFactory.h:
+ * orbsvcs/orbsvcs/Notify/EventChannelFactory.cpp:
+ * orbsvcs/orbsvcs/Notify/EventType.h:
+ * orbsvcs/orbsvcs/Notify/EventType.cpp:
+ * orbsvcs/orbsvcs/Notify/EventTypeSeq.h:
+ * orbsvcs/orbsvcs/Notify/EventTypeSeq.cpp:
+ * orbsvcs/orbsvcs/Notify/Event_Manager.cpp:
+ * orbsvcs/orbsvcs/Notify/Event_Persistence_Factory.h:
+ * orbsvcs/orbsvcs/Notify/Event_Persistence_Strategy.h:
+ * orbsvcs/orbsvcs/Notify/FilterAdmin.h:
+ * orbsvcs/orbsvcs/Notify/FilterAdmin.cpp:
+ * orbsvcs/orbsvcs/Notify/ID_Factory.h:
+ * orbsvcs/orbsvcs/Notify/ID_Factory.inl:
+ * orbsvcs/orbsvcs/Notify/ID_Factory.cpp:
+ * orbsvcs/orbsvcs/Notify/Name_Value_Pair.h:
+ * orbsvcs/orbsvcs/Notify/Name_Value_Pair.inl:
+ * orbsvcs/orbsvcs/Notify/Name_Value_Pair.cpp:
+ * orbsvcs/orbsvcs/Notify/Object.h:
+ * orbsvcs/orbsvcs/Notify/Object.inl:
+ * orbsvcs/orbsvcs/Notify/Object.cpp:
+ * orbsvcs/orbsvcs/Notify/POA_Helper.h:
+ * orbsvcs/orbsvcs/Notify/POA_Helper.cpp:
+ * orbsvcs/orbsvcs/Notify/Peer.h:
+ * orbsvcs/orbsvcs/Notify/Persistent_File.h:
+ * orbsvcs/orbsvcs/Notify/Persistent_File.cpp:
+ * orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.h:
+ * orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.cpp:
+ * orbsvcs/orbsvcs/Notify/Properties.h:
+ * orbsvcs/orbsvcs/Notify/Properties.inl:
+ * orbsvcs/orbsvcs/Notify/PropertySeq.h:
+ * orbsvcs/orbsvcs/Notify/PropertySeq.inl:
+ * orbsvcs/orbsvcs/Notify/PropertySeq.cpp:
+ * orbsvcs/orbsvcs/Notify/Property_Boolean.h:
+ * orbsvcs/orbsvcs/Notify/Property_Boolean.inl:
+ * orbsvcs/orbsvcs/Notify/Property_T.h:
+ * orbsvcs/orbsvcs/Notify/Property_T.inl:
+ * orbsvcs/orbsvcs/Notify/Proxy.h:
+ * orbsvcs/orbsvcs/Notify/Proxy.cpp:
+ * orbsvcs/orbsvcs/Notify/ProxyConsumer.cpp:
+ * orbsvcs/orbsvcs/Notify/ProxySupplier.h:
+ * orbsvcs/orbsvcs/Notify/ProxySupplier.cpp:
+ * orbsvcs/orbsvcs/Notify/ProxySupplier_T.cpp:
+ * orbsvcs/orbsvcs/Notify/Proxy_T.cpp:
+ * orbsvcs/orbsvcs/Notify/QoSProperties.h:
+ * orbsvcs/orbsvcs/Notify/QoSProperties.inl:
+ * orbsvcs/orbsvcs/Notify/QoSProperties.cpp:
+ * orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.h:
+ * orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.cpp:
+ * orbsvcs/orbsvcs/Notify/Reconnection_Registry.h:
+ * orbsvcs/orbsvcs/Notify/Reconnection_Registry.inl:
+ * orbsvcs/orbsvcs/Notify/Reconnection_Registry.cpp:
+ * orbsvcs/orbsvcs/Notify/Routing_Slip.h:
+ * orbsvcs/orbsvcs/Notify/Routing_Slip.cpp:
+ * orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.h:
+ * orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.cpp:
+ * orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.h:
+ * orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.cpp:
+ * orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.h:
+ * orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.cpp:
+ * orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.h:
+ * orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.cpp:
+
+ * orbsvcs/orbsvcs/Notify/SupplierAdmin.h:
+ * orbsvcs/orbsvcs/Notify/SupplierAdmin.cpp:
+ * orbsvcs/orbsvcs/Notify/Topology_Factory.h:
+ * orbsvcs/orbsvcs/Notify/Topology_Loader.h:
+ * orbsvcs/orbsvcs/Notify/Topology_Loader.cpp:
+ * orbsvcs/orbsvcs/Notify/Topology_Object.h:
+ * orbsvcs/orbsvcs/Notify/Topology_Object.inl:
+ * orbsvcs/orbsvcs/Notify/Topology_Object.cpp:
+ * orbsvcs/orbsvcs/Notify/Topology_Saver.h:
+ * orbsvcs/orbsvcs/Notify/Topology_Saver.cpp:
+ * orbsvcs/orbsvcs/Notify/XML_Loader.h:
+ * orbsvcs/orbsvcs/Notify/XML_Loader.cpp:
+ * orbsvcs/orbsvcs/Notify/XML_Saver.h:
+ * orbsvcs/orbsvcs/Notify/XML_Saver.cpp:
+ * orbsvcs/orbsvcs/Notify/XML_Topology_Factory.h:
+ * orbsvcs/orbsvcs/Notify/XML_Topology_Factory.cpp:
+ * orbsvcs/orbsvcs/Notify/notify_persist_export.h:
+ * orbsvcs/orbsvcs/Notify/Any/CosEC_ProxyPushConsumer.h:
+ * orbsvcs/orbsvcs/Notify/Any/CosEC_ProxyPushConsumer.cpp:
+ * orbsvcs/orbsvcs/Notify/Any/CosEC_ProxyPushSupplier.h:
+ * orbsvcs/orbsvcs/Notify/Any/CosEC_ProxyPushSupplier.cpp:
+ * orbsvcs/orbsvcs/Notify/Any/ProxyPushConsumer.h:
+ * orbsvcs/orbsvcs/Notify/Any/ProxyPushConsumer.cpp:
+ * orbsvcs/orbsvcs/Notify/Any/ProxyPushSupplier.h:
+ * orbsvcs/orbsvcs/Notify/Any/ProxyPushSupplier.cpp:
+ * orbsvcs/orbsvcs/Notify/Any/PushConsumer.h:
+ * orbsvcs/orbsvcs/Notify/Any/PushConsumer.cpp:
+ * orbsvcs/orbsvcs/Notify/Any/PushSupplier.h:
+ * orbsvcs/orbsvcs/Notify/Any/PushSupplier.cpp:
+
+ * orbsvcs/orbsvcs/Notify/Sequence/SequenceProxyPushConsumer.h:
+ * orbsvcs/orbsvcs/Notify/Sequence/SequenceProxyPushConsumer.cpp:
+ * orbsvcs/orbsvcs/Notify/Sequence/SequenceProxyPushSupplier.h:
+ * orbsvcs/orbsvcs/Notify/Sequence/SequenceProxyPushSupplier.cpp:
+ * orbsvcs/orbsvcs/Notify/Sequence/SequencePushConsumer.h:
+ * orbsvcs/orbsvcs/Notify/Sequence/SequencePushConsumer.cpp:
+ * orbsvcs/orbsvcs/Notify/Sequence/SequencePushSupplier.h:
+ * orbsvcs/orbsvcs/Notify/Sequence/SequencePushSupplier.cpp:
+
+ * orbsvcs/orbsvcs/Notify/Structured/StructuredProxyPushConsumer.h:
+ * orbsvcs/orbsvcs/Notify/Structured/StructuredProxyPushConsumer.cpp:
+ * orbsvcs/orbsvcs/Notify/Structured/StructuredProxyPushSupplier.h:
+ * orbsvcs/orbsvcs/Notify/Structured/StructuredProxyPushSupplier.cpp:
+ * orbsvcs/orbsvcs/Notify/Structured/StructuredPushConsumer.h:
+ * orbsvcs/orbsvcs/Notify/Structured/StructuredPushConsumer.cpp:
+ * orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.h:
+ * orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.cpp:
+
+ * orbsvcs/orbsvcs/NotifyExt.idl:
+
+ * orbsvcs/tests/Notify/PluggableTopology/PlugTop.mpc:
+ * orbsvcs/tests/Notify/PluggableTopology/Test_Saver.h:
+ * orbsvcs/tests/Notify/PluggableTopology/Test_Saver.cpp:
+ * orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.h:
+ * orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.cpp:
+ * orbsvcs/tests/Notify/PluggableTopology/main.cpp:
+ * orbsvcs/tests/Notify/PluggableTopology/plugtop_export.h:
+ * orbsvcs/tests/Notify/PluggableTopology/plugtop_ns.conf:
+
+ * orbsvcs/tests/Notify/Reconnecting/Consumer.h:
+ * orbsvcs/tests/Notify/Reconnecting/Consumer.cpp:
+ * orbsvcs/tests/Notify/Reconnecting/README:
+ * orbsvcs/tests/Notify/Reconnecting/Reconnecting.mpc:
+ * orbsvcs/tests/Notify/Reconnecting/Supplier.h:
+ * orbsvcs/tests/Notify/Reconnecting/Supplier.cpp:
+ * orbsvcs/tests/Notify/Reconnecting/event.conf:
+ * orbsvcs/tests/Notify/Reconnecting/ns_mt.conf:
+ * orbsvcs/tests/Notify/Reconnecting/ns_mt_both.conf:
+ * orbsvcs/tests/Notify/Reconnecting/ns_mt_topo.conf:
+ * orbsvcs/tests/Notify/Reconnecting/ns_st.conf:
+ * orbsvcs/tests/Notify/Reconnecting/ns_st_both.conf:
+ * orbsvcs/tests/Notify/Reconnecting/ns_st_topo.conf:
+ * orbsvcs/tests/Notify/Reconnecting/run_test.pl:
+
+ * orbsvcs/tests/Notify/XML_Persistence/XML_Persistence.mpc:
+ * orbsvcs/tests/Notify/XML_Persistence/main.cpp:
+ * orbsvcs/tests/Notify/XML_Persistence/run_test.pl:
+ * orbsvcs/tests/Notify/XML_Persistence/svc.conf:
+
+ * orbsvcs/tests/Notify/lib/Periodic_Consumer.cpp:
+
+ Merge OCI's Notification Service Changes into DOC group.
+ Connectivity (i.e. topology) persistence is working
+ Event persistence is not, yet.
+
+
diff --git a/TAO/docs/notification/reliability.html b/TAO/docs/notification/reliability.html
new file mode 100644
index 00000000000..44c9c198035
--- /dev/null
+++ b/TAO/docs/notification/reliability.html
@@ -0,0 +1,346 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+ <head>
+ <title>Using the Reliable Notification Service</title>
+ <meta content="False" name="vs_snapToGrid">
+ <meta content="False" name="vs_showGrid">
+ <!-- $Id$ -->
+ </head>
+ <body>
+ <h1>Using the Reliable Notification Service</h1>
+ <h2>Background</h2>
+ <p>There are two CORBA services defined by the OMG to support the
+ Supplier/Consumer design pattern.&nbsp; This pattern allows messages (known as
+ Events in this context) to be generated by one or more suppliers and delivered
+ to one or more consumers without requiring that the suppliers and consumers
+ have any knowledge of each other.&nbsp;</p>
+ <P>The Event Service provides a basic implementation of this pattern, and the
+ Notification service extends this basic service to support a rich variety of
+ optional features.</P>
+ <h2>Reliability and Persistence</h2>
+ <p>One of the optional features of the Notification service is Reliability.&nbsp;
+ By default the Event Service and the Notification service provide a&nbsp; <EM>best-effort</EM>
+ support for event delivery.&nbsp; If things go wrong -- program crashes,
+ communications failures, etc.&nbsp; events may be lost without notice.</p>
+ <P>There are some circumstances in which losing events is&nbsp; not
+ acceptable.&nbsp; The Notification service may be used for these situations if
+ it is configured for reliable operation.&nbsp; Reliable operation is not
+ available in the Event Service.&nbsp; Reliable operation means information is
+ saved persistently (usually on a disk file) and used to recover from the
+ various failures that might otherwise lead to loss of data.</P>
+ <P>There are two separate, but related, issues that need to be addressed to
+ provide reliable event delivery:&nbsp; topology persistence an event
+ persistence.</P>
+ <P>To provide topology persistence, sometimes called connection persistence, the
+ Notification service must keep track of what clients (Suppliers and Consumers)
+ have connected to the Notification service and what options have been specified
+ to contol the delivery of events.</P>
+ <P>To provide event persistence the Notification service tracks each event in
+ persistent storage to be sure it is delivered to every consumer that should
+ receive it.&nbsp;
+ </P>
+ <P>There may be situations in which topology persistence is all that is necessary
+ -- it&nbsp;may be&nbsp;acceptable to lose events during a failure as long as
+ the system is restored to normal operation afterward.&nbsp; Event persistence
+ on the other hand can only be supported if topology persistence is also being
+ used.&nbsp; It doesn't help to keep track of events if the system is unable to
+ find the consumers to which the events should be delivered.</P>
+ <P>Two separate issues must be addressed as part of setting up the Notifcation
+ for reliable operation.&nbsp; At the system administration level the
+ Notification&nbsp; service must be configured for topology persistence and
+ possibly for event persistence.&nbsp; At the application level,&nbsp;programs
+ that operate as consumers and suppliers must set the appropriate parameters to
+ enable reliable operation, and must cooperate with the reconnection process
+ that occurs during topology recovery.</P>
+ <h2>Configuring Notification Service Reliability.</h2>
+ <h3>Service Configurator Changes</h3>
+ <P>Runtime configuration of the Notification Service is supported through the
+ service configurator file. This file is normally named svc.conf; however the
+ -ORBSvcConf command line option allows an alternate service configuration file
+ to be specified.
+ </P>
+ <P>
+ Service configuration changes to support Notification Service reliability
+ include a new option on the existing&nbsp; <code>Notify_Default_Event_Manager_Objects_Factory</code>
+ service configuration command, and two new service configuration commands.
+ </P>
+ <H4>Notify_Default_Event_Manager_Objects_Factory option: -AllowReconnect</H4>
+ <p>Certain recovery cases require that a Consumer be able to reconnect to an
+ existing proxy object in the Notification Service in order to receive all
+ events delivered by that proxy object. This behavior is a departure from the
+ OMG Specification which mandates that the Notification Service should throw an
+ "Already Connected" exception when a consumer attempts to connect to a proxy
+ that was previously used by another Consumer.
+ </p>
+ <p>A new option, -AllowReconnect,&nbsp;is available for the existing <code>Notify_Default_Event_Manager_Objects_Factory
+ </code>command to support this requirement. As an example of its use, the
+ following line configures the Notification Service for multi-threaded operation
+ supporting reconnection.</p>
+ <code>static Notify_Default_Event_Manager_Objects_Factory "-DispatchingThreads 2
+ -SourceThreads 2 -AllowReconnect" </code>
+ <H3>Configuring Connection (Topologogy) Reliability</H3>
+ <p>The support for persistent topology is actually a configurable strategy.&nbsp;
+ TAO includes an XML Topology Persistence Strategy that uses an XML file for
+ persistent storage, but it it is designed to allow other strategies to be
+ developed.&nbsp; For example if topology information should be stored in a
+ relational database file, it is possible to develop a persistent topology
+ strategy to do so.&nbsp; The details of doing this are beyond the scope of this
+ document.
+ </p>
+ <P>This document describes how to configure the XML topology persistence included
+ with TAO.</P>
+ <P>An example of the&nbsp;service configuration command to&nbsp;configure the XML
+ strategy is:
+ </P>
+ <p><code>dynamic Topology_Factory Service_Object*
+ TAO_CosNotification_persist:_make_XML_Topology_Factory() "-base_path ./reconnect_test" </code>
+ </p>
+ <p>The first part of this line: <code>dynamic Topology_Factory Service_Object*
+ TAO_CosNotification_persist:_make_XML_Topology_Factory()</code>should be given
+ exactly as shown. For details on this syntax, see chapter 17 of the TAO
+ Developer's Guide.
+ </p>
+ <P>The quoted string at the end of the line contain arguments for the configured
+ strategy. The arguments recognized by the XML topology strategy implemented in
+ this project are:
+ </P>
+ <ul>
+ <li>
+ -v
+ <li>
+ -base_path <EM>file_path</EM>
+ <li>
+ -backup_count&nbsp;<EM>count</EM>
+ <li>
+ -save_base_path <EM>file_path</EM>
+ <li>
+ -load_base_path <EM>file_path</EM>
+ <li>
+ <H4>-no_timestamp
+ </H4>
+ </li>
+ </ul>
+ <H4>Topology_Factory Option: -v</H4>
+ To help diagnose and/or document svc.conf settings, the "-v" will cause the
+ options for the Topology_Factory to be displayed as they are interpreted
+ <H4>Topology_Factory Option: -base_path file_path
+ </H4>
+ <P>The argument for this option is a fully qualified path name without an
+ extension for the xml file in which topology information is saved. Three
+ extensions will be appended to this name: .new, .xml, and .000
+ </P>
+ <P>Saved topology information will be written to <EM>file_path</EM>.new file.
+ Information with a .new extension is not necessarily complete and will not be
+ used to restore the topology.
+ </P>
+ <P>When the .new file is complete, the previous <EM>file_path</EM>.000 (if any)
+ will be deleted, the previous <EM>file_path</EM>.xml (if any) will be renamed
+ as <EM>file_path</EM>.000 and the <EM>file_path</EM>.new file will be renamed
+ as file_path.xml. The assumption is that a file system rename operation is
+ atomic. If this assumption holds than at any time the file <EM>file_path</EM>.xml
+ (if it exists) contains the most recent complete save. If <EM>file_path</EM>.xml
+ does not exist then <EM>file_path</EM>.000 contains the most recent complete
+ save. If neither of these files exist the saved topology information is not
+ available.
+ </P>
+ <H4>Topology_Factory Option: -backup_count count</H4>
+ <P>This option modifies the behavior described in the preceeding section to allow
+ additional backup copies of the topology file to be retained. The default
+ value, 1, means that only the <EM>file_path</EM>.000 file will be kept. If a
+ higher number is specified, then older versions will be kept. Rather than
+ deleting <EM>file_path</EM>.000, the system will rename it to be <EM>file_path.</EM>001.&nbsp;
+ Older versions will be named <EM>file_path</EM>.002, <EM>file_path</EM>.002 and
+ so on.
+ </P>
+ <P>Under normal circumstances only one backup file is required -- in fact these
+ additional backup files will not be used to restore the topoogy.&nbsp; However
+ setting this number to a larger value lets the system keep a brief history of
+ topology changes. Since the XML files are roughly human-readable this can be
+ used as a diagnostic tool for problems related to Notification Service
+ topology.
+ </P>
+ <H4>Topology_Factory Options: -save_base_path file_path and -load_base_path
+ file_path
+ </H4>
+ <P>These options are alternatives to the -base_path option. They allow the file
+ from which topology information is loaded at Notification Service startup time
+ to be different from the file to which this information is saved as the system
+ runs.
+ </P>
+ <P>This option is mostly used for developer testing, a system administrator may
+ find an interesting use for this option -- possibly involving script files that
+ rename the XML files during recovery from a Notification Service failure.
+ </P>
+ <H4>Topology_Factory Option: -no_timestamp</H4>
+ <P>The XML files include a timestamp to indicate when the information was saved.
+ The timestamp is for information only and is not needed for correct functioning
+ of the topology persistence. This option suppresses that timestamp. Doing so
+ makes it possible to compare XML files using a program like diff to see if the
+ files represent the same topology.
+ </P>
+ <P>This option is intended primarily for testing the persistent topology
+ implementation.
+ </P>
+ <h3>Configuring Event Reliability</h3>
+ <p>A service configuraton new object, "Event_Persistence", can be configured in
+ the service configuration file to enable and configure the Event Reliability.
+ An example of the line needed to configure the Event_Persistence object is:
+ </p>
+ <p><code>dynamic Event_Persistence Service_Object*
+ TAO_CosNotification_persist:_make_Standard_Event_Persistence() "-v -file_path
+ ./event_persist.db" </code>
+ </p>
+ <p><CODE></CODE>If this line does not appear in svc.conf, then event reliability
+ will not be supported. QoS parameters for reliable event delivery will be
+ silently ignored when Event Reliability is not configured. Event reliability
+ also requires topology reliability, so if this line appears there must also be
+ a "Topology_Factory" line in the file. If not, the Notification Service will
+ fail to start up.
+ </p>
+ <P>The beginning of this line, up to and including the parentheses, should appear
+ exactly as shown. For details on this syntax, see chapter 17 of the TAO
+ Developer's Guide. The quoted string at the end of the line contains options
+ for Event_Persistence.
+ </P>
+ <h4>Event_Persistence Option: -v</h4>
+ <p>This option and any option that appears after this option will be written to
+ the log (normally the console) as it is processed. This is intended to help
+ diagnose and document the Event Persistence settings. The default is to
+ configure Event Persistence silently.
+ </p>
+ <h4>Event_Persistence Option: -file_path path
+ </h4>
+ <p>This option gives the completely qualified name for the file in which
+ persistent event information will be stored. The file should be configured on a
+ reliable device that supports synchronized writes (i.e. flushing the operating
+ system's write cache.) A device that is suitable for storing a reliable
+ database would be appropriate for storing this file. The file will be subject
+ to a relatively high number of small (single block) write requests, but very
+ few, if any, read requests. If the file does not exist, then a new file will be
+ created. If the file does exist, and if topology is successfully loaded, the
+ events from this file will be reloaded and redelivered automatically. This is a
+ required option. There is no default value.
+ </p>
+ <h4>Event_Persistence Option: -block_size n
+ </h4>
+ <p>This option gives the block size in bytes for the device on which the event
+ reliability file is stored. For both performance and reliability reasons it is
+ important that the value matches the physical characteristics of the device.
+ The default value is 512.
+ </p>
+ <h2>Application Programming Changes to Support Reliability</h2>
+ <p>
+ &nbsp;When it is configured as described above, the Notification service
+ supports reliable connectivity and/or&nbsp; event delivery.&nbsp;&nbsp;&nbsp;
+ Actually achieving such reliability, however, requires cooperation from the
+ Notification service clients (Suppliers and Consumers).
+ <P>
+ There are a number of failure possibilities and different recovery techniques
+ are needed to handle them.&nbsp; The simplest case is when a client
+ fails&nbsp;and is restarted.&nbsp;
+ <P>
+ The Notification service will have maintained the connection points (Supplier
+ and Consumer Admins, Proxy Consumers, Proxy Admins, etc.) As each of these
+ connections was established, an&nbsp;ID returned by the notification
+ service.&nbsp; An application that wishes to be reconnected after a failure
+ should save a persistent copy of these IDs.&nbsp; For example, it could write
+ the IDs to a file, then read them back from the file after restarting.&nbsp;
+ Using these ID's the application can reconnect to the existing connection
+ points in the Notification service.&nbsp; The reconnection to the Proxy objects
+ will only work if the Notification service has been configured with the&nbsp;
+ -AllowReconnection option described above, but otherwise this process is fairly
+ straightforward.
+ <P>
+ As soon as a supplier has reconnected, it can resume sending events.&nbsp; As
+ soon as a consumer has reconnected, persistent events (if any) and new events
+ will start to arrive.
+ <P>
+ Notice that the identity of a consumer or supplier is determined by these saved
+ IDs.&nbsp; This is true even if the restarted client is running on a completely
+ different machine from the original client.
+ <P>
+ The case of the Notification service itself failing then being restarted on the
+ same or a different machine is somewhat more complicated.&nbsp; The
+ Notification service wasn't designed to initiate a connection to a
+ client.&nbsp; It must wait for the client to reconnect before it can start
+ accepting or delivering events.&nbsp; The difficulty is in having the client
+ know when to initiatie the reconnection, and to where the Notification service
+ is running in case it was necessary to move it to a new machine due to the
+ failure
+ <H3>Reconnection Registry</H3>
+ <p>The reconnection registry provides an answer to the question of how the client
+ knows where and when to reconnect to the Notification&nbsp; service.&nbsp; This
+ TAO-specific interface is implemented by the EventChannelFactory in the
+ reliable Notification Service.&nbsp; Clients can narrow the EventChannelFactory
+ object reference to a Reconnection Registery interface, then register a
+ Reconnection Callback object that will be notified when the Notification
+ service has restarted and is ready for reconections.&nbsp; The
+ EventChannelFactory passes its own object reference to the Reconnection
+ Callback object to inform the client where the Notification service is now
+ running.</p>
+ <P>The interfaces involved are defined in the NotifyExt.idl file (in
+ $TAO_ROOT/orbsvcs/orbsvcs) and are shown here:</P>
+ <pre>
+ /** * \brief An interface which gets registered with a
+ ReconnectionRegistry.
+ * * A supplier or consumer must implement this interface in order
+ to * allow the Notification Service to attempt to reconnect to it
+ after * a failure. The supplier or consumer must register its instance
+ of * this interface with the
+ ReconnectionRegistry.
+ */ interface
+ ReconnectionCallback
+ { /// Perform operations to reconnect to the Notification
+ Service /// after a
+ failure. void reconnect (in Object
+
+ new_connection); /// Check to see if the ReconnectionCallback is alive
+ boolean is_alive ();
+ };
+
+ /**
+ * \brief An interface that handles registration of suppliers and consumers.
+ *
+ * This registry should be implemented by an EventChannelFactory and
+ * will call the appropriate reconnect methods for all ReconnectionCallback
+ * objects registered with it.
+ */
+ interface ReconnectionRegistry
+ {
+ typedef unsigned long ReconnectionID;
+ ReconnectionID register_callback(in ReconnectionCallback reconection);
+
+ void unregister_callback (in ReconnectionID id);
+
+ /// Check to see if the ReconnectionRegistry is alive
+ boolean is_alive ();
+ };
+ </pre>
+ <H3>Using&nbsp;Event Reliability</H3>
+ <P>Configuring the Notification service for reliable event delivery is necessary,
+ but not sufficient to enable reliable handling of events.&nbsp; The application
+ code in either the client or the server must configure the EventChannel through
+ which the events are delivered to operate in the reliable mode.&nbsp; This is
+ done by setting the QoSProperties named "ConnectionReliabilty" and
+ "EventReliability" to the value "persistent" -- either at the time the channel
+ is created or at a later time useing&nbsp; the set_qos method.</P>
+ <P>Once an channel has been configured for reliable operation, persistence can be
+ disabled on an event by event basis using QoSProperties of the event
+ itself.&nbsp; This could be none, for examlpe, to avoid the overhead of
+ persistently storing events for which reliability is not needed.</P>
+ <P>The supplier sends events to the EventChannel using a push() method.&nbsp; For
+ persistent events, this call will not return to the supplier until the
+ Notification service is prepared to guarantee event delivery.&nbsp;
+ </P>
+ <P>Application code in the Consumer should be written with the knowledge that
+ events are guaranteed to be delivered, but during recovery from a failure there
+ is a possiblity that an event may arrive more than once.&nbsp; This could
+ happen, for example if the event was in the process of being delivered at the
+ time the failure occurred and the failure prevents the Notfication service from
+ determining if the delivery completed successfully.&nbsp; To meet its
+ committment that every event will be delivered, the Notification service will
+ retry the delivery in this canse which may result in a duplicate event.</P>
+ <P>As long as this situation is understood at the time the application is
+ designed, it should be possible for the application to handle this situation.</P>
+ </body>
+</html>
diff --git a/TAO/orbsvcs/orbsvcs/CosNotification.mpc b/TAO/orbsvcs/orbsvcs/CosNotification.mpc
index 103a53192cb..02ed4b8dc8b 100644
--- a/TAO/orbsvcs/orbsvcs/CosNotification.mpc
+++ b/TAO/orbsvcs/orbsvcs/CosNotification.mpc
@@ -47,8 +47,7 @@ project(CosNotification) : orbsvcslib, core, event {
Template_Files {
}
-
- // explicit Resource_Files to avoid including _Skel & _Serv rc files.
+
Resource_Files{
CosNotification.rc
}
@@ -151,6 +150,7 @@ project(CosNotification_Serv) : orbsvcslib, core, notification_skel, dynamicany,
Notify/Method_Request_Lookup.cpp
Notify/Method_Request_Shutdown.cpp
Notify/Method_Request_Updates.cpp
+ Notify/Name_Value_Pair.cpp
Notify/Notify_Constraint_Interpreter.cpp
Notify/Notify_Constraint_Visitors.cpp
Notify/Notify_Default_Collection_Factory.cpp
@@ -170,12 +170,16 @@ project(CosNotification_Serv) : orbsvcslib, core, notification_skel, dynamicany,
Notify/QoSProperties.cpp
Notify/Reactive_Task.cpp
Notify/Refcountable.cpp
+ Notify/Reconnection_Registry.cpp
Notify/Subscription_Change_Worker.cpp
Notify/Supplier.cpp
Notify/SupplierAdmin.cpp
Notify/ThreadPool_Task.cpp
Notify/Timer_Queue.cpp
Notify/Timer_Reactor.cpp
+ Notify/Topology_Loader.cpp
+ Notify/Topology_Object.cpp
+ Notify/Topology_Saver.cpp
Notify/Worker_Task.cpp
Notify/Any/AnyEvent.cpp
Notify/Any/CosEC_ProxyPushConsumer.cpp
@@ -200,3 +204,20 @@ project(CosNotification_Serv) : orbsvcslib, core, notification_skel, dynamicany,
Template_Files {
}
}
+
+//project(CosNotification_Persist) : orbsvcslib, core, notification, event_skel, portableserver, acexml {
+project(CosNotification_Persist) : notification_serv, acexml {
+ sharedname = TAO_CosNotification_Persist
+ dynamicflags = TAO_NOTIFY_PERSIST_BUILD_DLL
+
+ IDL_Files {
+ }
+ Source_Files {
+ Notify/XML_Loader.cpp
+ Notify/XML_Saver.cpp
+ Notify/XML_Topology_Factory.cpp
+ }
+
+ Template_Files {
+ }
+}
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Admin.cpp b/TAO/orbsvcs/orbsvcs/Notify/Admin.cpp
index c01902fea7e..fdfd7bb73c6 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Admin.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/Admin.cpp
@@ -14,11 +14,18 @@ ACE_RCSID (Notify,
#include "Container_T.h"
#include "Proxy.h"
#include "EventChannel.h"
-
-TAO_Notify_Admin::TAO_Notify_Admin (void)
+#include "Topology_Saver.h"
+#include "Save_Persist_Worker_T.h"
+#include "Reconnect_Worker_T.h"
+#include "tao/debug.h"
+//#define DEBUG_LEVEL 9
+#define DEBUG_LEVEL TAO_debug_level
+
+TAO_Notify_Admin::TAO_Notify_Admin ()
: ec_ (0)
, proxy_container_ (0)
, filter_operator_ (CosNotifyChannelAdmin::OR_OP)
+ , is_default_ (false)
{
// Initialize all Admin objects to initially be subscribed for all events.
// This is a reasonable default and is required to allow Cos Event consumers/suppliers to send/receive events,
@@ -37,7 +44,7 @@ TAO_Notify_Admin::init (TAO_Notify_EventChannel *ec ACE_ENV_ARG_DECL)
this->ec_->_incr_refcnt ();
- this->TAO_Notify_Object::init (ec);
+ this->TAO_NOTIFY::Topology_Object::init (ec);
ACE_NEW_THROW_EX (this->proxy_container_,
TAO_Notify_Proxy_Container (),
@@ -91,6 +98,104 @@ TAO_Notify_Admin::insert (TAO_Notify_Proxy* proxy ACE_ENV_ARG_DECL)
this->proxy_container_->insert (proxy ACE_ENV_ARG_PARAMETER);
}
+void
+TAO_Notify_Admin::save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL)
+{
+ bool changed = this->children_changed_;
+ this->children_changed_ = false;
+ this->self_changed_ = false;
+
+ if (is_persistent ())
+ {
+ TAO_NOTIFY::NVPList attrs;
+ this->save_attrs(attrs);
+
+ const char* type = this->get_admin_type_name();
+
+ bool want_all_children =
+ saver.begin_object(this->id(), type, attrs, changed ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ if (want_all_children || this->filter_admin_.is_changed ())
+ {
+ this->filter_admin_.save_persistent(saver ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+ if (want_all_children || this->subscribed_types_.is_changed ())
+ {
+ this->subscribed_types_.save_persistent(saver ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+
+ TAO_NOTIFY::Save_Persist_Worker<TAO_Notify_Proxy> wrk(saver, want_all_children);
+ this->proxy_container_->collection()->for_each(&wrk ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ saver.end_object(this->id(), type ACE_ENV_ARG_PARAMETER);
+ }
+}
+
+void
+TAO_Notify_Admin::save_attrs (TAO_NOTIFY::NVPList& attrs)
+{
+ TAO_Notify_Object::save_attrs(attrs);
+ attrs.push_back(TAO_NOTIFY::NVP("InterFilterGroupOperator", this->filter_operator_));
+ if (this->is_default_)
+ {
+ attrs.push_back (TAO_NOTIFY::NVP ("default", "yes"));
+ }
+}
+
+void
+TAO_Notify_Admin::load_attrs(const TAO_NOTIFY::NVPList& attrs)
+{
+ TAO_Notify_Object::load_attrs (attrs);
+ const char * value = 0;
+ if (attrs.find ("InterFilterGroupOperator", value))
+ {
+ this->filter_operator_ = static_cast <CosNotifyChannelAdmin::InterFilterGroupOperator> (ACE_OS::atoi (value));
+ }
+ if (attrs.find ("default", value))
+ {
+ this->is_default_ = ACE_OS::strcmp (value, "yes");
+ }
+}
+
+TAO_NOTIFY::Topology_Object*
+TAO_Notify_Admin::load_child (const ACE_CString &type,
+ CORBA::Long id, const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL)
+{
+ TAO_NOTIFY::Topology_Object* result = this;
+ if (type == "subscriptions")
+ {
+ if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Admin reload subscription %d\n")
+ , ACE_static_cast (int, id)
+ ));
+ // since we initialized our subscribed types to everything
+ // in the constructor. we have to clear it out first.
+ this->subscribed_types_.reset();
+ result = &this->subscribed_types_;
+ }
+ else if (type == "filter_admin")
+ {
+ if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Admin reload filter_admin %d\n")
+ , ACE_static_cast (int, id)
+ ));
+ result = & this->filter_admin_;
+ }
+ return result;
+}
+
+void
+TAO_Notify_Admin::reconnect (ACE_ENV_SINGLE_ARG_DECL)
+{
+ TAO_NOTIFY::Reconnect_Worker<TAO_Notify_Proxy> wrk;
+ this->proxy_container_->collection()->for_each(&wrk ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+}
+
#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
template class TAO_ESF_Shutdown_Proxy<TAO_Notify_Proxy>;
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Admin.h b/TAO/orbsvcs/orbsvcs/Notify/Admin.h
index c2c384df821..592c8481560 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Admin.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/Admin.h
@@ -22,7 +22,7 @@
#include "FilterAdmin.h"
#include "EventTypeSeq.h"
-#include "Object.h"
+#include "Topology_Object.h"
class TAO_Notify_Proxy;
class TAO_Notify_EventChannel;
@@ -35,7 +35,7 @@ template <class TYPE> class TAO_Notify_Container_T;
*
*/
-class TAO_Notify_Serv_Export TAO_Notify_Admin : public virtual TAO_Notify_Object
+class TAO_Notify_Serv_Export TAO_Notify_Admin : public TAO_NOTIFY::Topology_Parent
{
friend class TAO_Notify_Builder;
public:
@@ -43,7 +43,7 @@ public:
typedef CosNotifyChannelAdmin::AdminIDSeq_var SEQ_VAR;
/// Constuctor
- TAO_Notify_Admin (void);
+ TAO_Notify_Admin ();
/// Destructor
~TAO_Notify_Admin ();
@@ -69,14 +69,27 @@ public:
CosNotifyChannelAdmin::InterFilterGroupOperator filter_operator (void);
/// Obtain the Admin's subscribed types.
- void subscribed_types (TAO_Notify_EventTypeSeq& subscribed_types
+ void subscribed_types (TAO_Notify_EventTypeSeq& subscribed_types
ACE_ENV_ARG_DECL);
/// Shutdown
virtual int shutdown (ACE_ENV_SINGLE_ARG_DECL);
+ virtual void save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL);
+ virtual TAO_NOTIFY::Topology_Object* load_child (const ACE_CString &type,
+ CORBA::Long id, const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL);
+ virtual void reconnect (ACE_ENV_SINGLE_ARG_DECL);
+
+ void set_default (bool is_default);
+ bool is_default () const;
+ virtual void load_attrs(const TAO_NOTIFY::NVPList& attrs);
+
protected:
- typedef TAO_Notify_Container_T <TAO_Notify_Proxy>
+ void save_attrs (TAO_NOTIFY::NVPList& attrs);
+ virtual const char * get_admin_type_name (void) const = 0;
+
+protected:
+ typedef TAO_Notify_Container_T <TAO_Notify_Proxy>
TAO_Notify_Proxy_Container;
/// = Data Members
@@ -95,6 +108,8 @@ protected:
/// Filter operator
CosNotifyChannelAdmin::InterFilterGroupOperator filter_operator_;
+
+ bool is_default_;
};
#if defined (__ACE_INLINE__)
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Admin.inl b/TAO/orbsvcs/orbsvcs/Notify/Admin.inl
index 8b6d8641eeb..155f2743b5b 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Admin.inl
+++ b/TAO/orbsvcs/orbsvcs/Notify/Admin.inl
@@ -17,3 +17,17 @@ TAO_Notify_Admin::filter_operator (void)
{
return this->filter_operator_;
}
+
+ACE_INLINE
+void
+TAO_Notify_Admin::set_default (bool is_default)
+{
+ this->is_default_ = is_default;
+}
+
+ACE_INLINE
+bool
+TAO_Notify_Admin::is_default (void) const
+{
+ return this->is_default_;
+}
diff --git a/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.cpp b/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.cpp
index 1d373b8eac8..1c90b0e5248 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.cpp
@@ -6,8 +6,8 @@
#include "AdminProperties.inl"
#endif /* __ACE_INLINE__ */
-ACE_RCSID (Notify,
- TAO_Notify_AdminProperties,
+ACE_RCSID (Notify,
+ TAO_Notify_AdminProperties,
"$Id$")
#include "orbsvcs/CosNotificationC.h"
@@ -43,6 +43,38 @@ TAO_Notify_AdminProperties::init (const CosNotification::PropertySeq& prop_seq)
return 0;
}
+void
+TAO_Notify_AdminProperties::init ()
+{
+ // This method should only be called once, (during topo load)
+ ACE_ASSERT(this->size() == 0);
+
+ if (this->max_global_queue_length_.is_valid())
+ {
+ CORBA::Any a;
+ a <<= this->max_global_queue_length_.value();
+ this->add(this->max_global_queue_length_.name(), a);
+ }
+ if (this->max_consumers_.is_valid())
+ {
+ CORBA::Any a;
+ a <<= this->max_consumers_.value();
+ this->add(this->max_consumers_.name(), a);
+ }
+ if (this->max_suppliers_.is_valid())
+ {
+ CORBA::Any a;
+ a <<= this->max_suppliers_.value();
+ this->add(this->max_suppliers_.name(), a);
+ }
+ if (this->reject_new_events_.is_valid())
+ {
+ CORBA::Any a;
+ a <<= CORBA::Any::from_boolean(this->reject_new_events_.value());
+ this->add(this->reject_new_events_.name(), a);
+ }
+}
+
CORBA::Boolean
TAO_Notify_AdminProperties::queue_full (void)
{
diff --git a/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.h b/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.h
index e7f51ebc5a0..5594add39b6 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.h
@@ -37,7 +37,7 @@
* @brief The AdminProperties per EventChannel.
*
*/
-class TAO_Notify_Serv_Export TAO_Notify_AdminProperties
+class TAO_Notify_Serv_Export TAO_Notify_AdminProperties
: public TAO_Notify_PropertySeq
{
public:
@@ -50,12 +50,21 @@ public:
// Init
int init (const CosNotification::PropertySeq& prop_seq);
- // = Accessors
+ // finish initialization after values are set by topology load
+ void init ();
+
+ // = Const Accessors
const TAO_Notify_Property_Long& max_global_queue_length (void) const;
const TAO_Notify_Property_Long& max_consumers (void) const;
const TAO_Notify_Property_Long& max_suppliers (void) const;
const TAO_Notify_Property_Boolean& reject_new_events (void) const;
+ // = Non-const accessors
+ TAO_Notify_Property_Long & max_global_queue_length (void);
+ TAO_Notify_Property_Long & max_consumers (void);
+ TAO_Notify_Property_Long & max_suppliers (void);
+ TAO_Notify_Property_Boolean & reject_new_events (void);
+
CORBA::Long& global_queue_length (void);
TAO_SYNCH_MUTEX& global_queue_lock (void);
TAO_SYNCH_CONDITION& global_queue_not_full_condition (void);
@@ -109,8 +118,8 @@ protected:
TAO_Notify_Atomic_Property_Long suppliers_;
};
-typedef ACE_Refcounted_Auto_Ptr<TAO_Notify_AdminProperties,
- TAO_SYNCH_MUTEX>
+typedef ACE_Refcounted_Auto_Ptr<TAO_Notify_AdminProperties,
+ TAO_SYNCH_MUTEX>
TAO_Notify_AdminProperties_var;
#if defined (__ACE_INLINE__)
diff --git a/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.inl b/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.inl
index 0eea011af97..36743cc9dc1 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.inl
+++ b/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.inl
@@ -6,24 +6,48 @@ TAO_Notify_AdminProperties::max_global_queue_length (void) const
return this->max_global_queue_length_;
}
+ACE_INLINE TAO_Notify_Property_Long&
+TAO_Notify_AdminProperties::max_global_queue_length (void)
+{
+ return this->max_global_queue_length_;
+}
+
ACE_INLINE const TAO_Notify_Property_Long&
TAO_Notify_AdminProperties::max_consumers (void) const
{
return this->max_consumers_;
}
+ACE_INLINE TAO_Notify_Property_Long&
+TAO_Notify_AdminProperties::max_consumers (void)
+{
+ return this->max_consumers_;
+}
+
ACE_INLINE const TAO_Notify_Property_Long&
TAO_Notify_AdminProperties::max_suppliers (void) const
{
return this->max_suppliers_;
}
+ACE_INLINE TAO_Notify_Property_Long&
+TAO_Notify_AdminProperties::max_suppliers (void)
+{
+ return this->max_suppliers_;
+}
+
ACE_INLINE const TAO_Notify_Property_Boolean&
TAO_Notify_AdminProperties::reject_new_events (void) const
{
return this->reject_new_events_;
}
+ACE_INLINE TAO_Notify_Property_Boolean&
+TAO_Notify_AdminProperties::reject_new_events (void)
+{
+ return this->reject_new_events_;
+}
+
ACE_INLINE CORBA::Long&
TAO_Notify_AdminProperties::global_queue_length (void)
{
diff --git a/TAO/orbsvcs/orbsvcs/Notify/AllocTracker.h b/TAO/orbsvcs/orbsvcs/Notify/AllocTracker.h
new file mode 100644
index 00000000000..5568ce5e720
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/AllocTracker.h
@@ -0,0 +1,81 @@
+// $Id$
+#ifndef ALLOC_TRACKER_H
+#define ALLOC_TRACKER_H
+#include /**/"ace/pre.h"
+
+#include "notify_export.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+//#define DEBUG_MEMORY_USE
+#if defined(_MSC_VER) && defined (_DEBUG) && defined (DEBUG_MEMORY_USE)
+namespace CRT{
+
+/// \brief dump heap allocation stats
+///
+/// This works only on microsoft/windows compilers
+/// but it's handy to diagnose memory allocation problems.
+/// To use, add the following macro in the scope where you
+/// want to check memory usage.
+/// ACE_WIN32_HEAP_MONITOR(name);
+/// where name is a quoted string to label the stats.
+/// When the object created by this macro goes out of scope
+/// it will write a log message like:
+/// (10056|6396) name: New heap blocks: 39; bytes: 19550
+///
+/// For non-debug, or non-vc builds, the macro expands to nothing
+class CrtHeapDumper
+{
+public:
+ CrtHeapDumper(const char * name, bool verbose = false)
+ : name_ (name)
+ , verbose_ (verbose)
+ {
+ _CrtMemCheckpoint (&before_);
+ }
+
+ ~CrtHeapDumper()
+ {
+ dump();
+ }
+ void dump()
+ {
+ _CrtMemState after;
+ _CrtMemCheckpoint (&after);
+ _CrtMemState diff;
+ _CrtMemDifference (&diff, &before_, &after);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) %s: New heap blocks: %d; bytes: %d\n"),
+ name_.c_str (),
+ ACE_static_cast (int, diff.lCounts[_NORMAL_BLOCK]),
+ ACE_static_cast (int, diff.lSizes[_NORMAL_BLOCK])
+ ));
+ if (this->verbose_)
+ {
+ _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
+ _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
+ _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
+ _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
+ _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
+ _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );
+ _CrtMemDumpAllObjectsSince (&this->before_);
+ }
+ }
+
+private:
+ ACE_CString name_;
+ bool verbose_;
+ _CrtMemState before_;
+};
+} //namespace
+#define ACE_WIN32_HEAP_MONITOR(name) \
+ CrtHeapDumper heap_check___(name); \
+ ACE_UNUSED_ARG (heap_check___)
+#else // _MSC_VER etc
+ #define ACE_WIN32_HEAP_MONITOR(name)
+#endif // _MSC_VER etc
+#include /**/"ace/post.h"
+#endif // ALLOC_TRACKER_H
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Bit_Vector.cpp b/TAO/orbsvcs/orbsvcs/Notify/Bit_Vector.cpp
new file mode 100644
index 00000000000..1c4ebf58906
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Bit_Vector.cpp
@@ -0,0 +1,118 @@
+// $Id$
+
+#include "Bit_Vector.h"
+
+namespace TAO_NOTIFY
+{
+
+Bit_Vector::Bit_Vector()
+ : size_(0)
+ , first_set_bit_(0)
+ , first_cleared_bit_(0)
+{
+}
+
+Bit_Vector::~Bit_Vector()
+{
+}
+
+bool
+Bit_Vector::is_set(const size_t location) const
+{
+ bool result = false;
+ if (location < this->size_)
+ {
+ result = (0 != (this->bitvec_[location >> BPW_LOG_2] & (1 << (location % BITS_PER_WORD))));
+ }
+ return result;
+}
+
+void
+Bit_Vector::set_bit(const size_t location, bool set)
+{
+ if (location >= this->size_)
+ {
+ if ((location >> BPW_LOG_2) >= (this->size_ >> BPW_LOG_2))
+ {
+ size_t need = (location >> BPW_LOG_2) - (this->size_ >> BPW_LOG_2);
+ this->bitvec_.resize(this->bitvec_.size() + need + 1, 0);
+ }
+ this->size_ = location + 1;
+ }
+ if (set)
+ {
+ this->bitvec_[location >> BPW_LOG_2] |= (1 << (location % BITS_PER_WORD));
+ }
+ else
+ {
+ this->bitvec_[location >> BPW_LOG_2] &= ~(1 << (location % BITS_PER_WORD));
+ }
+ this->evaluate_firsts(location, set);
+}
+
+size_t
+Bit_Vector::find_first_bit(bool set) const
+{
+ size_t result = 0;
+ if (set)
+ {
+ result = this->first_set_bit_;
+ }
+ else
+ {
+ result = this->first_cleared_bit_;
+ }
+ return result;
+}
+
+void
+Bit_Vector::evaluate_firsts(const size_t location, bool set)
+{
+ if (set)
+ {
+ if (this->first_cleared_bit_ == location)
+ {
+ this->first_cleared_bit_ = this->find_first_bit_of(location, false);
+ }
+ if (this->first_set_bit_ > location)
+ {
+ this->first_set_bit_ = location;
+ }
+ }
+ else if (!set)
+ {
+ if (this->first_set_bit_ == location)
+ {
+ this->first_set_bit_ = this->find_first_bit_of(location, true);
+ }
+ if (this->first_cleared_bit_ > location)
+ {
+ this->first_cleared_bit_ = location;
+ }
+ }
+}
+
+size_t
+Bit_Vector::find_first_bit_of(const size_t location, bool set)
+{
+ size_t newloc = 0;
+ size_t idx = 0;
+ for (idx = location; (newloc == 0) && (idx < this->size_ + 1); idx++)
+ {
+ if (is_set(idx) == set)
+ {
+ newloc = idx;
+ }
+ }
+ return newloc;
+}
+
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Vector<ACE_UINT32>;
+template class ACE_Array_Base<ACE_UINT32>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Vector<ACE_UINT32>
+#pragma instantiate ACE_Array_Base<ACE_UINT32>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Bit_Vector.h b/TAO/orbsvcs/orbsvcs/Notify/Bit_Vector.h
new file mode 100644
index 00000000000..eb143b45e38
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Bit_Vector.h
@@ -0,0 +1,76 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Bit_Vector.h
+ *
+ * $Id$
+ *
+ * This is a basic bit vector class.
+ *
+ * @author Jonathan Pollack <pollack_j@ociweb.com>
+ */
+//=============================================================================
+
+#ifndef BIT_VECTOR_H
+#define BIT_VECTOR_H
+#include /**/ "ace/pre.h"
+#include /**/ "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "notify_export.h"
+
+#include "ace/Vector_T.h"
+#include "ace/Basic_Types.h"
+
+namespace TAO_NOTIFY
+{
+
+/// \brief Simple bit vector.
+///
+/// Written to support block allocation from persistent storage.
+/// Should be promoted to the ACE level to make it generally usable.
+class TAO_Notify_Export Bit_Vector
+{
+ typedef ACE_UINT32 BASIC_UINT_TYPE;
+ typedef ACE_Vector<BASIC_UINT_TYPE> VECTOR_TYPE;
+ enum {
+ BITS_PER_WORD = 32,
+ BPW_LOG_2 = 5
+ };
+public:
+
+ /// The constructor.
+ Bit_Vector();
+ /// The destructor.
+ ~Bit_Vector();
+
+ /// \brief Determine if a bit at location is set.
+ bool is_set(const size_t location) const;
+ /// \brief Set or unset a bit at location, growing the vector as needed.
+ void set_bit(const size_t location, bool set);
+
+ /// \brief Find the first bit that is either set or unset in an O(1).
+ size_t find_first_bit(bool set) const;
+
+private:
+ /// Update our first set and unset bits.
+ void evaluate_firsts(const size_t location, bool set);
+ /// Iterate from location to the end, finding the first bit that
+ /// matches the requested set or unset value.
+ size_t find_first_bit_of(const size_t location, bool set);
+
+private:
+ VECTOR_TYPE bitvec_;
+ size_t size_;
+ size_t first_set_bit_;
+ size_t first_cleared_bit_;
+};
+
+}
+
+#include /**/ "ace/post.h"
+#endif /* BIT_VECTOR_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Builder.cpp b/TAO/orbsvcs/orbsvcs/Notify/Builder.cpp
index be7c6fafeba..1c185e7dd4a 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Builder.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/Builder.cpp
@@ -5,8 +5,8 @@
#include "Builder.inl"
#endif /* __ACE_INLINE__ */
-ACE_RCSID (Notify,
- Builder,
+ACE_RCSID (Notify,
+ Builder,
"$Id$")
#include "ace/Dynamic_Service.h"
@@ -41,10 +41,10 @@ ACE_RCSID (Notify,
#include "ETCL_FilterFactory.h"
#include "Container_T.h"
-template <class PROXY_IMPL,
- class PROXY,
- class PROXY_PTR,
- class PROXY_VAR,
+template <class PROXY_IMPL,
+ class PROXY,
+ class PROXY_PTR,
+ class PROXY_VAR,
class PARENT>
class TAO_Notify_Proxy_Builder_T
{
@@ -83,6 +83,32 @@ public:
return proxy_ret._retn ();
}
+
+ PROXY_IMPL*
+ build (PARENT *parent, const CosNotifyChannelAdmin::ProxyID proxy_id
+ ACE_ENV_ARG_DECL)
+ {
+ TAO_Notify_Factory* factory = TAO_Notify_PROPERTIES::instance ()->factory ();
+
+ PROXY_IMPL* proxy = 0;
+ factory->create (proxy ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ PortableServer::ServantBase_var servant (proxy);
+
+ proxy->init (parent ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ proxy->activate (proxy, proxy_id ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ // insert proxy in admin container.
+ parent->insert (proxy ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ return proxy;
+ }
+
};
// define the ProxyConsumer Builders.
@@ -183,7 +209,7 @@ TAO_Notify_Builder::build_event_channel_factory (PortableServer::POA_ptr poa ACE
factory->create (ecf ACE_ENV_ARG_PARAMETER);
ACE_CHECK_RETURN (ecf_ret._retn ());
- PortableServer::ServantBase_var servant_var (ecf);
+// PortableServer::ServantBase_var servant_var (ecf);
ecf->TAO_Notify_EventChannelFactory::init (poa ACE_ENV_ARG_PARAMETER);
@@ -197,7 +223,11 @@ TAO_Notify_Builder::build_event_channel_factory (PortableServer::POA_ptr poa ACE
}
CosNotifyChannelAdmin::EventChannel_ptr
-TAO_Notify_Builder::build_event_channel (TAO_Notify_EventChannelFactory* ecf, const CosNotification::QoSProperties & initial_qos, const CosNotification::AdminProperties & initial_admin, CosNotifyChannelAdmin::ChannelID_out id ACE_ENV_ARG_DECL)
+TAO_Notify_Builder::build_event_channel (
+ TAO_Notify_EventChannelFactory* ecf,
+ const CosNotification::QoSProperties & initial_qos,
+ const CosNotification::AdminProperties & initial_admin,
+ CosNotifyChannelAdmin::ChannelID_out id ACE_ENV_ARG_DECL)
{
CosNotifyChannelAdmin::EventChannel_var ec_ret;
@@ -207,7 +237,7 @@ TAO_Notify_Builder::build_event_channel (TAO_Notify_EventChannelFactory* ecf, co
factory->create (ec ACE_ENV_ARG_PARAMETER);
ACE_CHECK_RETURN (ec_ret._retn ());
- PortableServer::ServantBase_var servant_var (ec);
+// PortableServer::ServantBase_var servant_var (ec);
ec->init (ecf, initial_qos, initial_admin ACE_ENV_ARG_PARAMETER);
ACE_CHECK_RETURN (ec_ret._retn ());
@@ -228,8 +258,35 @@ TAO_Notify_Builder::build_event_channel (TAO_Notify_EventChannelFactory* ecf, co
return ec_ret._retn ();
}
+TAO_Notify_EventChannel *
+TAO_Notify_Builder::build_event_channel (
+ TAO_Notify_EventChannelFactory* ecf,
+ const CosNotifyChannelAdmin::ChannelID id ACE_ENV_ARG_DECL)
+{
+ TAO_Notify_Factory* factory = TAO_Notify_PROPERTIES::instance ()->factory ();
+
+ TAO_Notify_EventChannel* ec = 0;
+ factory->create (ec ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ ec->init (ecf ACE_ENV_ARG_PARAMETER); //, initial_qos, initial_admin
+ ACE_CHECK_RETURN (0);
+
+ // insert ec in ec container.
+ ecf->ec_container_->insert (ec ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ ec->activate (ec, id ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ return ec;
+}
+
CosNotifyChannelAdmin::ConsumerAdmin_ptr
-TAO_Notify_Builder::build_consumer_admin (TAO_Notify_EventChannel* ec, CosNotifyChannelAdmin::InterFilterGroupOperator op, CosNotifyChannelAdmin::AdminID_out id ACE_ENV_ARG_DECL)
+TAO_Notify_Builder::build_consumer_admin (
+ TAO_Notify_EventChannel* ec,
+ CosNotifyChannelAdmin::InterFilterGroupOperator op,
+ CosNotifyChannelAdmin::AdminID_out id ACE_ENV_ARG_DECL)
{
CosNotifyChannelAdmin::ConsumerAdmin_var ca_ret;
@@ -239,7 +296,7 @@ TAO_Notify_Builder::build_consumer_admin (TAO_Notify_EventChannel* ec, CosNotify
factory->create (ca ACE_ENV_ARG_PARAMETER);
ACE_CHECK_RETURN (ca_ret._retn ());
- PortableServer::ServantBase_var servant_var (ca);
+// PortableServer::ServantBase_var servant_var (ca);
ca->init (ec ACE_ENV_ARG_PARAMETER);
ACE_CHECK_RETURN (ca_ret._retn ());
@@ -261,6 +318,31 @@ TAO_Notify_Builder::build_consumer_admin (TAO_Notify_EventChannel* ec, CosNotify
return ca_ret._retn ();
}
+TAO_Notify_ConsumerAdmin *
+TAO_Notify_Builder::build_consumer_admin (
+ TAO_Notify_EventChannel* ec,
+ const CosNotifyChannelAdmin::ChannelID id
+ ACE_ENV_ARG_DECL)
+{
+ TAO_Notify_Factory* factory = TAO_Notify_PROPERTIES::instance ()->factory ();
+ TAO_Notify_ConsumerAdmin * ca = 0;
+ factory->create (ca ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+// PortableServer::ServantBase_var servant_var (ca);
+
+ ca->init (ec ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ CORBA::Object_var obj = ca->activate (ca, id ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ // insert admin in CA container.
+ ec->ca_container_->insert (ca ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+ return ca;
+}
+
CosNotifyChannelAdmin::SupplierAdmin_ptr
TAO_Notify_Builder::build_supplier_admin (TAO_Notify_EventChannel* ec, CosNotifyChannelAdmin::InterFilterGroupOperator op, CosNotifyChannelAdmin::AdminID_out id ACE_ENV_ARG_DECL)
{
@@ -272,7 +354,7 @@ TAO_Notify_Builder::build_supplier_admin (TAO_Notify_EventChannel* ec, CosNotify
factory->create (sa ACE_ENV_ARG_PARAMETER);
ACE_CHECK_RETURN (sa_ret._retn ());
- PortableServer::ServantBase_var servant_var (sa);
+// PortableServer::ServantBase_var servant_var (sa);
sa->init (ec ACE_ENV_ARG_PARAMETER);
ACE_CHECK_RETURN (sa_ret._retn ());
@@ -294,6 +376,32 @@ TAO_Notify_Builder::build_supplier_admin (TAO_Notify_EventChannel* ec, CosNotify
return sa_ret._retn ();
}
+TAO_Notify_SupplierAdmin *
+TAO_Notify_Builder::build_supplier_admin (
+ TAO_Notify_EventChannel* ec,
+ const CosNotifyChannelAdmin::ChannelID id
+ ACE_ENV_ARG_DECL)
+{
+ TAO_Notify_Factory* factory = TAO_Notify_PROPERTIES::instance ()->factory ();
+ TAO_Notify_SupplierAdmin * sa = 0;
+ factory->create (sa ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+// PortableServer::ServantBase_var servant_var (ca);
+
+ sa->init (ec ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ CORBA::Object_var obj = sa->activate (sa, id ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ // insert admin in CA container.
+ ec->sa_container_->insert (sa ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ return sa;
+}
+
CosNotifyChannelAdmin::ProxyConsumer_ptr
TAO_Notify_Builder::build_proxy(TAO_Notify_SupplierAdmin* sa
, CosNotifyChannelAdmin::ClientType ctype
@@ -366,6 +474,76 @@ TAO_Notify_Builder::build_proxy(TAO_Notify_ConsumerAdmin* ca
}
}
+TAO_Notify_ProxyConsumer *
+TAO_Notify_Builder::build_proxy(TAO_Notify_SupplierAdmin* sa
+ , CosNotifyChannelAdmin::ClientType ctype
+ , const CosNotifyChannelAdmin::ProxyID proxy_id
+ ACE_ENV_ARG_DECL)
+{
+ switch (ctype)
+ {
+ case CosNotifyChannelAdmin::ANY_EVENT:
+ {
+ TAO_Notify_ProxyPushConsumer_Builder pb;
+ return pb.build (sa, proxy_id ACE_ENV_ARG_PARAMETER);
+ }
+ break;
+
+ case CosNotifyChannelAdmin::STRUCTURED_EVENT:
+ {
+ TAO_Notify_StructuredProxyPushConsumer_Builder pb;
+ return pb.build (sa, proxy_id ACE_ENV_ARG_PARAMETER);
+ }
+ break;
+
+ case CosNotifyChannelAdmin::SEQUENCE_EVENT:
+ {
+ TAO_Notify_SequenceProxyPushConsumer_Builder pb;
+ return pb.build (sa, proxy_id ACE_ENV_ARG_PARAMETER);
+ }
+ break;
+
+ default:
+ ACE_THROW_RETURN (CORBA::BAD_PARAM (),
+ 0);
+ }
+}
+
+TAO_Notify_ProxySupplier *
+TAO_Notify_Builder::build_proxy(TAO_Notify_ConsumerAdmin* ca
+ , CosNotifyChannelAdmin::ClientType ctype
+ , const CosNotifyChannelAdmin::ProxyID proxy_id
+ ACE_ENV_ARG_DECL)
+{
+ switch (ctype)
+ {
+ case CosNotifyChannelAdmin::ANY_EVENT:
+ {
+ TAO_Notify_ProxyPushSupplier_Builder pb;
+ return pb.build (ca, proxy_id ACE_ENV_ARG_PARAMETER);
+ }
+ break;
+
+ case CosNotifyChannelAdmin::STRUCTURED_EVENT:
+ {
+ TAO_Notify_StructuredProxyPushSupplier_Builder pb;
+ return pb.build (ca, proxy_id ACE_ENV_ARG_PARAMETER);
+ }
+ break;
+
+ case CosNotifyChannelAdmin::SEQUENCE_EVENT:
+ {
+ TAO_Notify_SequenceProxyPushSupplier_Builder pb;
+ return pb.build (ca, proxy_id ACE_ENV_ARG_PARAMETER);
+ }
+ break;
+
+ default:
+ ACE_THROW_RETURN (CORBA::BAD_PARAM (),
+ 0);
+ }
+}
+
CosEventChannelAdmin::ProxyPushSupplier_ptr
TAO_Notify_Builder::build_proxy (TAO_Notify_ConsumerAdmin* ca ACE_ENV_ARG_DECL)
{
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Builder.h b/TAO/orbsvcs/orbsvcs/Notify/Builder.h
index bcf5abd6bec..7dbce8fad0a 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Builder.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/Builder.h
@@ -26,6 +26,7 @@
#include "orbsvcs/NotifyExtC.h"
#include "AdminProperties.h"
+#include "Topology_Object.h"
class TAO_Notify_EventChannelFactory;
class TAO_Notify_EventChannel;
@@ -66,6 +67,13 @@ public:
, CosNotifyChannelAdmin::ChannelID_out id
ACE_ENV_ARG_DECL);
+
+ virtual TAO_Notify_EventChannel *
+ build_event_channel (TAO_Notify_EventChannelFactory* ecf
+ , const CosNotifyChannelAdmin::ChannelID id
+ ACE_ENV_ARG_DECL);
+
+
/// Build ConsumerAdmin
virtual CosNotifyChannelAdmin::ConsumerAdmin_ptr
build_consumer_admin (TAO_Notify_EventChannel* ec
@@ -73,13 +81,31 @@ public:
, CosNotifyChannelAdmin::AdminID_out id
ACE_ENV_ARG_DECL);
+ /// Build ConsumerAdmin during topology restore
+ /// TODO: this returns a reference to the actual type
+ /// to accomodate loadable builder/factory there should
+ /// be an appropriate base class for it to return.
+ virtual TAO_Notify_ConsumerAdmin *
+ build_consumer_admin (TAO_Notify_EventChannel* ec
+ , const CosNotifyChannelAdmin::AdminID id //CORBA::Long id // note: an in parameter!
+ ACE_ENV_ARG_DECL);
+
/// Build SupplierAdmin
virtual CosNotifyChannelAdmin::SupplierAdmin_ptr
- build_supplier_admin (TAO_Notify_EventChannel* ec
+ build_supplier_admin (TAO_Notify_EventChannel * ec
, CosNotifyChannelAdmin::InterFilterGroupOperator op
, CosNotifyChannelAdmin::AdminID_out id
ACE_ENV_ARG_DECL);
+ /// Build ConsumerAdmin during topology restore
+ /// TODO: this returns a reference to the actual type
+ /// to accomodate loadable builder/factory there should
+ /// be an appropriate base class for it to return.
+ virtual TAO_Notify_SupplierAdmin *
+ build_supplier_admin (TAO_Notify_EventChannel * ec
+ , const CosNotifyChannelAdmin::AdminID id //CORBA::Long id // note: an in parameter!
+ ACE_ENV_ARG_DECL);
+
/// Build ProxyConsumer
virtual CosNotifyChannelAdmin::ProxyConsumer_ptr
build_proxy (TAO_Notify_SupplierAdmin* sa
@@ -88,6 +114,13 @@ public:
, const CosNotification::QoSProperties & initial_qos
ACE_ENV_ARG_DECL);
+ /// Reload ProxyConsumer
+ virtual TAO_Notify_ProxyConsumer *
+ build_proxy (TAO_Notify_SupplierAdmin* sa
+ , CosNotifyChannelAdmin::ClientType ctype
+ , const CosNotifyChannelAdmin::ProxyID proxy_id
+ ACE_ENV_ARG_DECL);
+
/// Build ProxySupplier.
virtual CosNotifyChannelAdmin::ProxySupplier_ptr
build_proxy (TAO_Notify_ConsumerAdmin* ca
@@ -96,6 +129,13 @@ public:
, const CosNotification::QoSProperties & initial_qos
ACE_ENV_ARG_DECL);
+ /// Reload ProxySupplier.
+ virtual TAO_Notify_ProxySupplier *
+ build_proxy (TAO_Notify_ConsumerAdmin* ca
+ , CosNotifyChannelAdmin::ClientType ctype
+ , const CosNotifyChannelAdmin::ProxyID proxy_id
+ ACE_ENV_ARG_DECL);
+
/// Build CosEC style ProxySupplier.
virtual CosEventChannelAdmin::ProxyPushSupplier_ptr
build_proxy (TAO_Notify_ConsumerAdmin* ca ACE_ENV_ARG_DECL);
@@ -111,15 +151,15 @@ public:
/// Apply Thread Pools.
virtual void apply_thread_pool_concurrency (
- TAO_Notify_Object& object,
- const NotifyExt::ThreadPoolParams& tp_params
+ TAO_Notify_Object& object,
+ const NotifyExt::ThreadPoolParams& tp_params
ACE_ENV_ARG_DECL
);
/// Apply Thread Pools with Lanes.
virtual void apply_lane_concurrency (
- TAO_Notify_Object& object,
- const NotifyExt::ThreadPoolLanesParams& tpl_params
+ TAO_Notify_Object& object,
+ const NotifyExt::ThreadPoolLanesParams& tpl_params
ACE_ENV_ARG_DECL
);
};
diff --git a/TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.cpp b/TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.cpp
index 5552b0df58b..762b6be2c95 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.cpp
@@ -6,8 +6,8 @@
#include "ConsumerAdmin.inl"
#endif /* __ACE_INLINE__ */
-ACE_RCSID (RT_Notify,
- TAO_Notify_ConsumerAdmin,
+ACE_RCSID (RT_Notify,
+ TAO_Notify_ConsumerAdmin,
"$Id$")
#include "ace/Auto_Ptr.h"
@@ -20,6 +20,11 @@ ACE_RCSID (RT_Notify,
#include "Builder.h"
#include "Find_Worker_T.h"
#include "Seq_Worker_T.h"
+#include "ProxySupplier.h"
+
+#include "tao/debug.h"
+//#define DEBUG_LEVEL 9
+#define DEBUG_LEVEL TAO_debug_level
typedef TAO_Notify_Find_Worker_T<TAO_Notify_Proxy
, CosNotifyChannelAdmin::ProxySupplier
@@ -30,9 +35,18 @@ TAO_Notify_ProxySupplier_Find_Worker;
typedef TAO_Notify_Seq_Worker_T<TAO_Notify_Proxy> TAO_Notify_Proxy_Seq_Worker;
TAO_Notify_ConsumerAdmin::TAO_Notify_ConsumerAdmin (void)
+ : TAO_Notify_Admin ()
+{
+}
+
+const char *
+TAO_Notify_ConsumerAdmin::get_admin_type_name () const
{
+ return "consumer_admin";
}
+
+
TAO_Notify_ConsumerAdmin::~TAO_Notify_ConsumerAdmin ()
{
}
@@ -83,6 +97,76 @@ TAO_Notify_ConsumerAdmin::destroy (ACE_ENV_SINGLE_ARG_DECL)
ACE_CHECK;
}
+
+TAO_NOTIFY::Topology_Object*
+TAO_Notify_ConsumerAdmin::load_child (const ACE_CString &type,
+ CORBA::Long id, const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL)
+{
+ TAO_NOTIFY::Topology_Object* result = this;
+ if (type == "proxy_push_supplier")
+ {
+ if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Admin reload proxy %d\n")
+ , ACE_static_cast (int, id)
+ ));
+ result = this->load_proxy(id, CosNotifyChannelAdmin::ANY_EVENT, attrs ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+ }
+ else if (type == "structured_proxy_push_supplier")
+ {
+ if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Admin reload proxy %d\n")
+ , ACE_static_cast (int, id)
+ ));
+ result = this->load_proxy(id, CosNotifyChannelAdmin::STRUCTURED_EVENT, attrs ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+ }
+ else if (type == "sequence_proxy_push_supplier")
+ {
+ if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Admin reload proxy %d\n")
+ , ACE_static_cast (int, id)
+ ));
+ result = this->load_proxy(id, CosNotifyChannelAdmin::SEQUENCE_EVENT, attrs ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+ }
+#if 0
+ else if (type == "ec_proxy_push_supplier")
+ {
+ if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Admin reload proxy %d\n")
+ , ACE_static_cast (int, id)
+ ));
+ result = this->load_proxy(id, attrs ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+ }
+#endif
+ else
+ {
+ result = TAO_Notify_Admin::load_child (type, id, attrs ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+ }
+ return result;
+}
+
+TAO_NOTIFY::Topology_Object*
+TAO_Notify_ConsumerAdmin::load_proxy (
+ CORBA::Long id,
+ CosNotifyChannelAdmin::ClientType ctype,
+ const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL)
+{
+ TAO_Notify_Builder* bld = TAO_Notify_PROPERTIES::instance()->builder();
+ TAO_Notify_ProxySupplier * proxy =
+ bld->build_proxy (this
+ , ctype
+ , id
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ ACE_ASSERT(proxy != 0);
+ proxy->load_attrs (attrs);
+ return proxy;
+}
+
CosNotifyChannelAdmin::ProxySupplier_ptr
TAO_Notify_ConsumerAdmin::obtain_notification_push_supplier (CosNotifyChannelAdmin::ClientType ctype,
CosNotifyChannelAdmin::ProxyID_out proxy_id
@@ -95,11 +179,16 @@ TAO_Notify_ConsumerAdmin::obtain_notification_push_supplier (CosNotifyChannelAdm
{
CosNotification::QoSProperties initial_qos;
- return TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this
+ CosNotifyChannelAdmin::ProxySupplier_var proxy =
+ TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this
, ctype
, proxy_id
- , initial_qos
+ , initial_qos
ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (proxy._retn ());
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (proxy._retn ());
+ return proxy._retn ();
}
CosNotifyChannelAdmin::ProxySupplier_ptr
@@ -114,11 +203,16 @@ TAO_Notify_ConsumerAdmin::obtain_notification_push_supplier_with_qos (CosNotifyC
, CosNotification::UnsupportedQoS
))
{
- return TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this
+ CosNotifyChannelAdmin::ProxySupplier_var proxy =
+ TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this
, ctype
, proxy_id
, initial_qos
ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (proxy._retn ());
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (proxy._retn ());
+ return proxy._retn ();
}
CosEventChannelAdmin::ProxyPushSupplier_ptr
@@ -127,7 +221,12 @@ TAO_Notify_ConsumerAdmin::obtain_push_supplier (ACE_ENV_SINGLE_ARG_DECL)
CORBA::SystemException
))
{
- return TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this ACE_ENV_ARG_PARAMETER);
+ CosEventChannelAdmin::ProxyPushSupplier_var proxy =
+ TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (proxy._retn ());
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (proxy._retn ());
+ return proxy._retn ();
}
CosNotifyChannelAdmin::AdminID
@@ -223,6 +322,7 @@ TAO_Notify_ConsumerAdmin::subscription_change (const CosNotification::EventTypeS
this->proxy_container_->collection()->for_each (&worker ACE_ENV_ARG_PARAMETER);
}
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
}
CosNotifyFilter::FilterID
@@ -231,7 +331,12 @@ TAO_Notify_ConsumerAdmin::add_filter (CosNotifyFilter::Filter_ptr new_filter ACE
CORBA::SystemException
))
{
- return this->filter_admin_.add_filter (new_filter ACE_ENV_ARG_PARAMETER);
+ CosNotifyFilter::FilterID fid =
+ this->filter_admin_.add_filter (new_filter ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (fid);
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (fid);
+ return fid;
}
void
diff --git a/TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.h b/TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.h
index 99964a7cd11..880129fd4e1 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.h
@@ -57,7 +57,20 @@ public:
/// Release this object.
virtual void release (void);
+ virtual const char * get_admin_type_name () const;
+
+ virtual TAO_NOTIFY::Topology_Object* load_child (
+ const ACE_CString &type,
+ CORBA::Long id,
+ const TAO_NOTIFY::NVPList& attrs
+ ACE_ENV_ARG_DECL);
+
protected:
+ TAO_NOTIFY::Topology_Object *load_proxy (
+ CORBA::Long id,
+ CosNotifyChannelAdmin::ClientType ctype,
+ const TAO_NOTIFY::NVPList& attrs
+ ACE_ENV_ARG_DECL);
/// = NotifyExt::ConsumerAdmin methods
virtual CosNotifyChannelAdmin::ProxySupplier_ptr
diff --git a/TAO/orbsvcs/orbsvcs/Notify/CosNotify_Service.cpp b/TAO/orbsvcs/orbsvcs/Notify/CosNotify_Service.cpp
index 4fcfbe8081e..da6c7459da9 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/CosNotify_Service.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/CosNotify_Service.cpp
@@ -104,6 +104,11 @@ TAO_CosNotify_Service::init (int argc, char *argv[])
task_per_proxy = 1;
arg_shifter.consume_arg ();
}
+ else if (arg_shifter.cur_arg_strncasecmp (ACE_LIB_TEXT("-AllowReconnect")) == 0)
+ {
+ arg_shifter.consume_arg ();
+ TAO_Notify_PROPERTIES::instance()->allow_reconnect (true);
+ }
}
// Init the EC QoS
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method.cpp b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method.cpp
new file mode 100644
index 00000000000..26191c7920c
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method.cpp
@@ -0,0 +1,80 @@
+// $Id$
+
+#include "Delivery_Method.h"
+
+#if ! defined (__ACE_INLINE__)
+#include "Delivery_Method.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "orbsvcs/Time_Utilities.h"
+#include "tao/debug.h"
+#include "ace/OS_NS_sys_time.h"
+
+//#define DEBUG_LEVEL 9
+#define DEBUG_LEVEL TAO_debug_level
+
+ACE_RCSID(RT_Notify, TAO_Notify_Method_Request, "$Id$")
+
+namespace TAO_NOTIFY
+{
+
+//////////////////
+// Delivery Method
+Delivery_Method::Delivery_Method (const TAO_NOTIFY::Delivery_Request_Ptr & delivery_request)
+ : TAO_Notify_Method_Request ()
+ , delivery_request_ (delivery_request)
+{
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Delivery Method: constructor\n")
+ ));
+ // Set the parameters that affect queuing in the message queue.
+ // The ACE_Message_Block priorities go from 0 (lowest) to ULONG_MAX
+ // (highest), while the Notification Events go from -32767 (lowest,
+ // even though CORBA::Short goes to -32768) to 32767 (highest).
+
+ // Convert to CORBA::Long to preserve the sign. Conversion to
+ // unsigned long will happen automatically and we do not have to worry
+ // about losing the number in the addition since priority () returns a
+ // CORBA::Short.
+ const TAO_Notify_Event_Ptr pevent = this->delivery_request_->event ();
+ this->msg_priority ((CORBA::Long)pevent->priority ().value () +
+ PRIORITY_BASE);
+
+ // The deadline time for the message block is absolute, while the
+ // timeout for the event is relative to the time it was received.
+ // So, we do a little conversion and set it on the message block (us)
+
+ TAO_Notify_Property_Time& timeout = pevent->timeout ();
+
+ if (timeout.is_valid () && timeout.value() != 0)
+ {
+ ACE_Time_Value tv = ACE_OS::gettimeofday();
+ tv += ORBSVCS_Time::to_Time_Value(timeout.value());
+ this->msg_deadline_time (tv);
+ }
+}
+
+Delivery_Method::Delivery_Method (const Delivery_Method & rhs)
+ : TAO_Notify_Method_Request ()
+ , delivery_request_ (rhs.delivery_request_)
+{
+}
+
+Delivery_Method::~Delivery_Method ()
+{
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Delivery Method: destructor\n")
+ ));
+}
+
+const TAO_Notify_Event&
+Delivery_Method::event (void) const
+{
+ return * this->delivery_request_->event ();
+}
+
+} //namespace TAO_NOTIFY
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#endif /*ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method.h b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method.h
new file mode 100644
index 00000000000..d5f43275eac
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method.h
@@ -0,0 +1,78 @@
+/* -*- C++ -*- */
+/**
+ * @file Delivery_Method.h
+ *
+ * $Id$
+ *
+ *
+ */
+
+#ifndef TAO_NOTIFY_DELIVERY_METHOD_H
+#define TAO_NOTIFY_DELIVERY_METHOD_H
+#include "ace/pre.h"
+
+#include "notify_export.h"
+#include "Method_Request.h"
+#include "Event.h"
+#include "Routing_Slip.h"
+#include "Types.h"
+#include "Refcountable.h"
+
+#include "ace/Message_Block.h"
+#include <ace/Vector_T.h>
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+namespace TAO_NOTIFY
+{
+
+/**
+ * @class Delivery_Method
+ *
+ * @brief Base class for requests to deliver events to destinations.
+ *
+ */
+class TAO_Notify_Export Delivery_Method : public TAO_Notify_Method_Request
+{
+public:
+ /// Constructor
+ Delivery_Method (const Delivery_Request_Ptr & delivery_request);
+
+ /// Destructor
+ virtual ~Delivery_Method ();
+
+ /// Obtain the event.
+ const TAO_Notify_Event& event (void) const;
+
+protected:
+ // derived classes can copy themselves, but
+ // you cant copy-construct a Delivery_Method
+ Delivery_Method (const Delivery_Method & rhs);
+
+ Delivery_Request_Ptr delivery_request_;
+};
+
+/// Exception/surprise return safe completion notification to the Delivery Request.
+class TAO_Notify_Export Delivery_Method_Complete
+{
+public:
+ /// Construct with the Delivery Request to be notified.
+ Delivery_Method_Complete (const Delivery_Request_Ptr & delivery_request);
+ /// The distructor sends the notification
+ ~Delivery_Method_Complete ();
+ /// Abandon if notification should not be sent (unlikely!)
+ void abandon ();
+private:
+ Delivery_Request_Ptr delivery_request_;
+ bool abandoned_;
+};
+} //namespace TAO_NOTIFY
+
+#if defined (__ACE_INLINE__)
+#include "Delivery_Method.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* TAO_NOTIFY_DELIVERY_METHOD_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.cpp b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.cpp
new file mode 100644
index 00000000000..e0eec8bb5a6
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.cpp
@@ -0,0 +1,192 @@
+// $Id$
+
+#include "Delivery_Method_Dispatch.h"
+
+#if ! defined (__ACE_INLINE__)
+#include "Delivery_Method_Dispatch.inl"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(RT_Notify, Delivery_Method_Dispatch, "$Id$")
+
+#include "Delivery_Request.h"
+#include "ProxySupplier.h"
+#include "Consumer.h"
+#include "tao/debug.h"
+//#define DEBUG_LEVEL 9
+#define DEBUG_LEVEL TAO_debug_level
+
+//////////////////////////////////////////////////////////
+
+namespace TAO_NOTIFY
+{
+
+Delivery_Method_Dispatch::Delivery_Method_Dispatch (
+ const TAO_NOTIFY::Delivery_Request_Ptr& delivery_request,
+ TAO_Notify_ProxySupplier* proxy_supplier,
+ bool filtering)
+ : Delivery_Method (delivery_request)
+ , proxy_supplier_ (proxy_supplier)
+ , refcountable_guard_ (*proxy_supplier)
+ , filtering_ (filtering)
+{
+ delivery_request->set_delivery_type (1);
+ IdVec ids(3);
+ proxy_supplier->get_id_path (ids);
+ delivery_request->set_destination_id (ids);
+}
+
+Delivery_Method_Dispatch::Delivery_Method_Dispatch (
+ const Delivery_Method_Dispatch & rhs)
+ : Delivery_Method (rhs.delivery_request_)
+ , proxy_supplier_ (rhs.proxy_supplier_)
+ , refcountable_guard_ (*rhs.proxy_supplier_)
+ , filtering_ (rhs.filtering_)
+{
+}
+
+Delivery_Method_Dispatch::~Delivery_Method_Dispatch ()
+{
+}
+
+//static
+Delivery_Method_Dispatch *
+Delivery_Method_Dispatch::create (
+ const Delivery_Request_Ptr& delivery_request,
+ TAO_Notify_EventChannelFactory &ecf,
+ TAO_InputCDR & cdr
+ ACE_ENV_ARG_DECL)
+{
+ bool ok = true;
+ Delivery_Method_Dispatch * result = 0;
+ ACE_CString textpath;
+ CORBA::ULong count;
+ if (cdr.read_ulong (count))
+ {
+ IdVec id_path (count);
+ for (size_t nid = 0; ok && nid < count; ++nid)
+ {
+ TAO_Notify_Object_Id id = 0;
+ if ( cdr.read_long (id))
+ {
+ id_path.push_back (id);
+ char idbuf[20];
+ ACE_OS::snprintf (idbuf, sizeof(idbuf)-1, "/%d", ACE_static_cast (int, id));
+ textpath += idbuf;
+ }
+ else
+ {
+ ok = false;
+ }
+ }
+
+ if (ok)
+ {
+ TAO_Notify_ProxySupplier* proxy_supplier = ecf.find_proxy_supplier (id_path,
+ 0 ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ if (proxy_supplier != 0)
+ {
+ if (DEBUG_LEVEL > 6) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Delivery_Method reload event for %s\n")
+ , textpath.c_str()
+ ));
+ ACE_NEW_NORETURN (result,
+ Delivery_Method_Dispatch (delivery_request, proxy_supplier, true));
+ }
+ else
+ {
+ TAO_Notify_ProxyConsumer * proxy_consumer = ecf.find_proxy_consumer (id_path, 0 ACE_ENV_ARG_PARAMETER); //@@todo
+ if (proxy_consumer == 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Delivery_Method_Dispatch::unmarshal: unknown proxy id %s\n")
+ , textpath.c_str()
+ ));
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Delivery_Method_Dispatch::unmarshal: wrong type of proxy id %s\n")
+ , textpath.c_str()
+ ));
+ }
+ }
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Delivery_Method_Dispatch::unmarshal: Cant read proxy id path\n")
+ ));
+ }
+ }
+ return result;
+}
+
+
+TAO_Notify_Method_Request*
+Delivery_Method_Dispatch::copy (void)
+{
+ return new Delivery_Method_Dispatch (*this);
+}
+
+int
+Delivery_Method_Dispatch::execute (ExecuteOption eo ACE_ENV_ARG_DECL)
+{
+ ACE_ASSERT(this->proxy_supplier_ != 0);
+ ACE_ASSERT(this->delivery_request_ != 0);
+ ACE_ASSERT(! this->delivery_request_->event().null());
+
+ if (eo == TAO_Notify_Method_Request::DISCARD)
+ {
+ this->delivery_request_->complete();
+ return 0;
+ }
+ // Note : Unlike suppliers, if the consumer has shutdown() then we can safely discard the
+ // event.
+ if (this->proxy_supplier_->has_shutdown())
+ {
+ if (DEBUG_LEVEL > 0)ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Delivery_Method_Dispatch: proxy_supplier is shut down. Discard delivery.\n")
+ ));
+ this->delivery_request_->complete();
+ return 0;
+ }
+
+ // Same logic as above
+ TAO_Notify_Consumer* consumer = this->proxy_supplier_->consumer ();
+ if (consumer == 0)
+ {
+ if (DEBUG_LEVEL > 0)ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Delivery_Method_Dispatch: consumer is null. Discard delivery.\n")
+ ));
+ this->delivery_request_->complete();
+ return 0;
+ }
+
+ if (this->filtering_)
+ {
+ CORBA::Boolean val = this->proxy_supplier_->check_filters (* this->delivery_request_->event() ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ if (! val)
+ {
+ if (DEBUG_LEVEL > 0)ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Delivery_Method_Dispatch: Proxysupplier %d filter discards delivery.\n"),
+ ACE_static_cast (int, this->proxy_supplier_->id ())
+ ));
+
+ this->delivery_request_->complete();
+ return 0;
+ }
+ }
+
+ if (DEBUG_LEVEL > 0)ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Delivery_Method_Dispatch: Push event to Proxysupplier %d.\n"),
+ ACE_static_cast (int, this->proxy_supplier_->id ())
+ ));
+
+ consumer->push (this->delivery_request_); // calls delivery_request_->complete()
+
+ return 0;
+}
+
+} //namespace TAO_NOTIFY
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.h b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.h
new file mode 100644
index 00000000000..4378e0149c6
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.h
@@ -0,0 +1,78 @@
+/* -*- C++ -*- */
+/**
+ * @file Delivery_Method_Dispatch.h
+ *
+ * $Id$
+ *
+ * @author Pradeep Gore <pradeep@oomworks.com>
+ *
+ *
+ */
+
+#ifndef TAO_NOTIFY_DELIVERY_METHOD_DISPATCH_H
+#define TAO_NOTIFY_DELIVERY_METHOD_DISPATCH_H
+#include "ace/pre.h"
+
+#include "notify_export.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "Delivery_Method.h"
+#include "Types.h"
+
+namespace TAO_NOTIFY
+{
+/**
+ * @class Delivery_Method_Dispatch
+ *
+ * @brief Dispatchs an event to a proxy supplier.
+ *
+ */
+class TAO_Notify_Export Delivery_Method_Dispatch : public Delivery_Method
+{
+public:
+ /// an arbitrary code (Octet) to identify this delivery method type in persistent storage
+ enum {persistence_code = 1};
+ /// Constructor
+ Delivery_Method_Dispatch (
+ const Delivery_Request_Ptr& delivery_request,
+ TAO_Notify_ProxySupplier* proxy_supplier,
+ bool filtering = true);
+
+ Delivery_Method_Dispatch (const Delivery_Method_Dispatch & rhs);
+
+ static Delivery_Method_Dispatch * create (
+ const Delivery_Request_Ptr& delivery_request,
+ TAO_Notify_EventChannelFactory &ecf,
+ TAO_InputCDR & cdr
+ ACE_ENV_ARG_DECL);
+
+ /// Destructor
+ ~Delivery_Method_Dispatch ();
+
+ /// Create a copy of this object.
+ TAO_Notify_Method_Request* copy (void);
+
+ /// Execute the Request
+ virtual int execute (ExecuteOption eo ACE_ENV_ARG_DECL);
+
+private:
+ /// Proxy Supplier that we use.
+ TAO_Notify_ProxySupplier* proxy_supplier_;
+
+ /// Guard to automatically inc/decr ref count on the proxy.
+ TAO_Notify_Refcountable_Guard refcountable_guard_;
+
+ bool filtering_;
+};
+
+} //namespace TAO_NOTIFY
+
+#if defined (__ACE_INLINE__)
+#include "Delivery_Method_Dispatch.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* TAO_NOTIFY_DELIVERY_METHOD_DISPATCH_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.cpp b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.cpp
new file mode 100644
index 00000000000..8cfe9b0d53a
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.cpp
@@ -0,0 +1,179 @@
+// $Id$
+
+#include "Delivery_Method_Lookup.h"
+
+#if ! defined (__ACE_INLINE__)
+#include "Delivery_Method_Lookup.inl"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(RT_Notify, TAO_Notify_Method_Request_Lookup, "$Id$")
+
+#include "Event_Map_T.h"
+#include "ProxySupplier.h"
+#include "ProxyConsumer.h"
+
+#include "orbsvcs/ESF/ESF_Proxy_Collection.h"
+
+#include "tao/debug.h"
+
+namespace TAO_NOTIFY
+{
+
+//////////////////
+// Delivery Request
+Delivery_Method_Lookup::Delivery_Method_Lookup (const TAO_NOTIFY::Delivery_Request_Ptr & delivery_request,
+ TAO_Notify_ProxyConsumer* proxy_consumer)
+ : Delivery_Method (delivery_request)
+ , TAO_ESF_Worker<TAO_Notify_ProxySupplier> () // gcc 3.2 makes me do this
+ , proxy_consumer_ (proxy_consumer)
+ , refcountable_guard_ (*proxy_consumer)
+{
+ delivery_request->set_delivery_type (persistence_code);
+ IdVec ids(3);
+ proxy_consumer->get_id_path (ids);
+ delivery_request->set_destination_id (ids);
+}
+
+Delivery_Method_Lookup::Delivery_Method_Lookup( const Delivery_Method_Lookup & rhs)
+ : Delivery_Method (rhs.delivery_request_)
+ , TAO_ESF_Worker<TAO_Notify_ProxySupplier> () // gcc 3.2 makes me do this
+ , proxy_consumer_ (rhs.proxy_consumer_)
+ , refcountable_guard_ (*rhs.proxy_consumer_)
+{
+}
+
+Delivery_Method_Lookup::~Delivery_Method_Lookup ()
+{
+}
+
+//static
+Delivery_Method_Lookup *
+Delivery_Method_Lookup::create (
+ const Delivery_Request_Ptr& delivery_request,
+ TAO_Notify_EventChannelFactory &ecf,
+ TAO_InputCDR & cdr
+ ACE_ENV_ARG_DECL)
+{
+ bool ok = true;
+ Delivery_Method_Lookup * result = 0;
+ CORBA::ULong count;
+ if (cdr.read_ulong (count))
+ {
+ IdVec id_path (count);
+ for (size_t nid = 0; ok && nid < count; ++nid)
+ {
+ TAO_Notify_Object_Id id = 0;
+ if ( cdr.read_long (id))
+ {
+ id_path.push_back (id);
+ }
+ else
+ {
+ ok = false;
+ }
+ }
+
+ if (ok)
+ {
+ TAO_Notify_ProxyConsumer * proxy_consumer = ecf.find_proxy_consumer (id_path,
+ 0 ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ if (proxy_consumer != 0)
+ {
+ ACE_NEW_NORETURN (result,
+ Delivery_Method_Lookup (delivery_request, proxy_consumer));
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Delivery_Method_Lookup::unmarshal: unknown proxy id\n")
+ ));
+ }
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Delivery_Method_Lookup::unmarshal: Cant read proxy id path\n")
+ ));
+ }
+ }
+ return result;
+}
+
+
+TAO_Notify_Method_Request*
+Delivery_Method_Lookup::copy (void)
+{
+ return new Delivery_Method_Lookup (*this);
+}
+
+int
+Delivery_Method_Lookup::execute (ExecuteOption eo ACE_ENV_ARG_DECL)
+{
+ ACE_UNUSED_ARG (eo);
+ ACE_ASSERT(this->delivery_request_ != 0);
+ ACE_ASSERT(this->proxy_consumer_ != 0);
+ ACE_ASSERT(! this->delivery_request_->event().null());
+ ACE_ASSERT(eo == TAO_Notify_Method_Request::EXECUTE);
+
+ // Report request complete when this method exits. If the request isn't filtered
+ // then a new request will be created for each destination consumer.
+ Delivery_Method_Complete complete (this->delivery_request_);
+
+ // Note : The ProxyConsumer may very well shutdown() before we get here. It should still be
+ // usable for checking filters, and we still want to deliver the events that were pushed.
+
+ TAO_Notify_Event_Ptr pevent = this->delivery_request_->event ();
+ CORBA::Boolean val = this->proxy_consumer_->check_filters (*pevent ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+
+ if (TAO_debug_level > 1)
+ ACE_DEBUG ((LM_DEBUG, "Proxyconsumer %x filter eval result = %d\n",this->proxy_consumer_ , val));
+
+ // Filter failed - do nothing.
+ if (val == 0)
+ {
+ return 0;
+ }
+
+ TAO_Notify_Consumer_Map* map = this->proxy_consumer_->map();
+ ACE_ASSERT(map != 0);
+
+ TAO_Notify_Consumer_Map::ENTRY* entry = map->find (pevent->type () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ TAO_Notify_ProxySupplier_Collection* consumers = 0;
+
+ if (entry != 0)
+ {
+ consumers = entry->collection ();
+
+ if (consumers != 0)
+ {
+ consumers->for_each (this ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ }
+
+ map->release (entry);
+ }
+
+ // Get the consumers subscribed to all events.
+ consumers = map->broadcast_collection ();
+
+ if (consumers != 0)
+ {
+ consumers->for_each (this ACE_ENV_ARG_PARAMETER);
+ }
+ return 0;
+}
+
+void
+Delivery_Method_Lookup::work (TAO_Notify_ProxySupplier* proxy ACE_ENV_ARG_DECL_NOT_USED)
+{
+ ACE_ASSERT(proxy != 0);
+ ACE_ASSERT(this->delivery_request_ != 0);
+ ACE_ASSERT(this->delivery_request_->routing_slip() != 0);
+ this->delivery_request_->routing_slip()->dispatch (proxy, true);
+}
+
+} //namespace TAO_NOTIFY
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.h b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.h
new file mode 100644
index 00000000000..cfbf5699dc8
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.h
@@ -0,0 +1,71 @@
+/* -*- C++ -*- */
+/**
+ * @file Delivery_Method_Lookup.h
+ *
+ * $Id$
+ *
+ * @author Pradeep Gore <pradeep@oomworks.com>
+ *
+ *
+ */
+
+#ifndef TAO_Notify_LOOKUP_METHOD_REQUEST_H
+#define TAO_Notify_LOOKUP_METHOD_REQUEST_H
+#include "ace/pre.h"
+
+#include "notify_export.h"
+#include "Delivery_Method.h"
+#include "Types.h"
+#include "orbsvcs/ESF/ESF_Worker.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+namespace TAO_NOTIFY
+{
+class TAO_Notify_Export Delivery_Method_Lookup
+ : public Delivery_Method
+ , public TAO_ESF_Worker<TAO_Notify_ProxySupplier>
+{
+public:
+ /// an arbitrary code (Octet) to identify this type of event in persistent storage
+ enum {persistence_code = 2};
+ /// Constructor
+ Delivery_Method_Lookup(const TAO_NOTIFY::Delivery_Request_Ptr & delivery_request, TAO_Notify_ProxyConsumer* proxy_consumer);
+ Delivery_Method_Lookup(const Delivery_Method_Lookup & rhs);
+
+ /// Destructor
+ ~Delivery_Method_Lookup ();
+
+ /// Create a copy of this object.
+ TAO_Notify_Method_Request* copy (void);
+
+ static Delivery_Method_Lookup * create (
+ const Delivery_Request_Ptr& delivery_request,
+ TAO_Notify_EventChannelFactory &ecf,
+ TAO_InputCDR & cdr
+ ACE_ENV_ARG_DECL);
+
+ /// Execute the Request
+ virtual int execute (ExecuteOption eo ACE_ENV_ARG_DECL);
+
+ ///= TAO_ESF_Worker method
+ void work (TAO_Notify_ProxySupplier* proxy_supplier ACE_ENV_ARG_DECL);
+
+private:
+ /// ProxyConsumer supplying event.
+ TAO_Notify_ProxyConsumer* proxy_consumer_;
+
+ /// Guard to automatically inc/decr ref count on the proxy.
+ TAO_Notify_Refcountable_Guard refcountable_guard_;
+};
+
+} // namespace TAO_NOTIFY
+
+#if defined (__ACE_INLINE__)
+#include "Delivery_Method_Lookup.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* TAO_Notify_LOOKUP_METHOD_REQUEST_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Delivery_Request.cpp b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Request.cpp
new file mode 100644
index 00000000000..62e6aa24a63
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Request.cpp
@@ -0,0 +1,87 @@
+// $Id$
+
+#include "Delivery_Request.h"
+
+#if ! defined (__ACE_INLINE__)
+#include "Delivery_Request.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "Routing_Slip.h"
+#include "tao/debug.h"
+
+//#define DEBUG_LEVEL 9
+#define DEBUG_LEVEL TAO_debug_level
+
+namespace TAO_NOTIFY
+{
+
+///////////////////
+// Delivery_Request
+Delivery_Request::Delivery_Request (const Routing_Slip_Ptr & routing_slip, size_t request_id)
+ : routing_slip_ (routing_slip)
+ , request_id_ (request_id)
+ , delivery_type_ (0)
+{
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Delivery_Request:: constructor\n")
+ ));
+}
+
+Delivery_Request::~Delivery_Request ()
+{
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Delivery_Request:: destructor\n")
+ ));
+}
+
+// DO NOT INLINE THIS. It uses the Routing_Slip_Ptr which cannot be declared at
+// the time Delivery_Request.inl is compiled.
+void
+Delivery_Request::complete ()
+{
+ routing_slip_->delivery_request_complete (this->request_id_);
+}
+
+// DO NOT INLINE THIS. It uses the Routing_Slip_Ptr which cannot be declared at
+// the time Delivery_Request.inl is compiled.
+const TAO_Notify_Event_Ptr &
+Delivery_Request::event () const
+{
+ return this->routing_slip_->event ();
+}
+
+void
+Delivery_Request::marshal (TAO_OutputCDR & cdr)
+{
+ if (this->delivery_type_ != 0)
+ {
+ cdr.write_octet (this->delivery_type_);
+ size_t dest_count = this->destination_id_.size ();
+ cdr.write_ulong (dest_count);
+ for (size_t ndest = 0; ndest < dest_count; ++ ndest)
+ {
+ cdr.write_ulong (this->destination_id_ [ndest]);
+ }
+ }
+}
+
+} // namespace
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+//template class ACE_Auto_Basic_Ptr<TAO_NOTIFY::Routing_Slip>;
+//template class ACE_Strong_Bound_Ptr<TAO_NOTIFY::Routing_Slip, TAO_SYNCH_MUTEX>;
+//template class ACE_Auto_Basic_Ptr<TAO_NOTIFY::Delivery_Request>;
+//template class ACE_Strong_Bound_Ptr<TAO_NOTIFY::Delivery_Request,TAO_SYNCH_MUTEX>;
+// Duplicated in Routing_Slip.cpp
+//template class ACE_Vector <TAO_NOTIFY::Delivery_Request_Ptr>;
+//template class ACE_Array_Base<ACE_Strong_Bound_Ptr<TAO_NOTIFY::Delivery_Request,TAO_SYNCH_MUTEX> >;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+//#pragma instantiate ACE_Auto_Basic_Ptr<TAO_NOTIFY::Routing_Slip>
+//#pragma instantiate ACE_Strong_Bound_Ptr<TAO_NOTIFY::Routing_Slip,TAO_SYNCH_MUTEX>
+//#pragma instantiate ACE_Auto_Basic_Ptr<TAO_NOTIFY::Delivery_Request>
+//#pragma instantiate ACE_Strong_Bound_Ptr<TAO_NOTIFY::Delivery_Request,TAO_SYNCH_MUTEX>
+// Duplicated in Routing_Slip.cpp
+//#pragma instantiate ACE_Vector <TAO_NOTIFY::Delivery_Request_Ptr>
+//#pragma instantiate ACE_Array_Base<ACE_Strong_Bound_Ptr<TAO_NOTIFY::Delivery_Request,TAO_SYNCH_MUTEX> >
+#endif /*ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Delivery_Request.h b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Request.h
new file mode 100644
index 00000000000..6f6a4a7a945
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Request.h
@@ -0,0 +1,121 @@
+/* -*- C++ -*- */
+// $Id$
+
+#ifndef TAO_NOTIFY_DELIVERY_REQUEST_H
+#define TAO_NOTIFY_DELIVERY_REQUEST_H
+#include /**/ "ace/pre.h"
+
+#include "notify_export.h"
+#include "Object.h"
+#include "Event.h"
+#include <ace/Vector_T.h>
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+
+// Forward declarations of classes/pointers/collections referenced
+// in this header
+class TAO_Notify_EventChannelFactory;
+
+namespace TAO_NOTIFY
+{
+
+// Forward declarations of TAO_NOTIFY classes/pointers/collections declared
+// in this header
+class Delivery_Request;
+/// A reference-counted smart pointer to a Delivery_Request.
+typedef ACE_Strong_Bound_Ptr<Delivery_Request, TAO_SYNCH_MUTEX> Delivery_Request_Ptr;
+
+// Forward declarations of TAO_NOTIFY classes/pointers/collections referenced
+// in this header
+
+class Routing_Slip;
+typedef ACE_Strong_Bound_Ptr<Routing_Slip, TAO_SYNCH_MUTEX> Routing_Slip_Ptr;
+
+/// \brief Represents a request to deliver an event to a particular destination.
+///
+/// A Routing Slip contains a collection of Delivery Requests.
+/// A Delivery Request is associated with a Delivery Method. Delivery Methods
+/// should be lightweight objects because they are copied, queued, and otherwise
+/// passed around while they are waiting to be executed. The Delivery Request is
+/// more stable.
+class TAO_Notify_Export Delivery_Request
+{
+public:
+ /// Normal constructor
+ /// \param routing_slip the routing slip that owns this Delivery Request.
+ /// \param request_id an id that identifies this Delivery Request to the Routing Slip.
+ Delivery_Request (const Routing_Slip_Ptr & routing_slip, size_t request_id);
+
+ /// \brief A static "factory" method for use during restart.
+ ///
+ /// \param routing_slip. The routing slip to which the new Delivery Request should be attached.
+ /// \param request_id The id used to identify this Delivery Request to the Routing Slip.
+ /// \param ecf The EventChannelFactory responsible for reloading this Delivery Method.
+ /// \param cdr A CDR stream from which the peristent information for this Delivery Requect can be retrieved.
+ /// \return a pointer to the newly-allocated Delivery Request
+ static Delivery_Request_Ptr create (
+ const Routing_Slip_Ptr & routing_slip,
+ size_t request_id,
+ TAO_Notify_EventChannelFactory & ecf,
+ TAO_InputCDR & cdr);
+
+ /// a normal destructor.
+ ~Delivery_Request ();
+
+ /// \brief A method to indicate the delivery is complete.
+ ///
+ /// To be called by the delivery method associated with this delivery request.
+ void complete ();
+
+ /// \brief An accessor method for the event associated with the Routing Slip that owns this Delivery request.
+ const TAO_Notify_Event_Ptr & event () const;
+
+ /// \brief An accessor method for the routing slip that owns this request.
+ const Routing_Slip_Ptr & routing_slip ()const;
+
+ /// \brief Capture Delivery Type for the Delivery Method
+ ///
+ /// Called by the delivery method to capture information that should be persisted.
+ void set_delivery_type (ACE_CDR::Octet type);
+
+ /// \brief Capture destination ID for the Delivery Request.
+ ///
+ /// Called by the delivery method to capture information that should be persisted.
+ void set_destination_id (IdVec & destination_id);
+
+ /// \brief Marshal peristent information for this delivery request and its delivery methods into a CDR stream.
+ ///
+ /// Called during persistent event storage.
+ void marshal (TAO_OutputCDR & cdr);
+
+ // Meaningless, but needed by ACE_Vector on some platforms (gcc2.x LynxOS)
+ bool operator == (const Delivery_Request & rhs) const;
+ // Meaningless, but needed by ACE_Vector on some platforms
+ bool operator != (const Delivery_Request & rhs) const;
+
+private:
+ /// No null constructor.
+ Delivery_Request ();
+ /// No copy constructor.
+ Delivery_Request (const Delivery_Request & rhs);
+ /// no assignment operator
+ Delivery_Request & operator = (const Delivery_Request & rhs);
+
+private:
+ Routing_Slip_Ptr routing_slip_;
+ size_t request_id_;
+ ACE_CDR::Octet delivery_type_;
+ IdVec destination_id_;
+};
+
+} // namespace
+
+#if defined (__ACE_INLINE__)
+#include "Delivery_Request.inl"
+#endif /* __ACE_INLINE__ */
+
+#include /**/ "ace/post.h"
+#endif /* TAO_NOTIFY_DELIVERY_REQUEST_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/EventChannel.cpp b/TAO/orbsvcs/orbsvcs/Notify/EventChannel.cpp
index 3985ef9d899..411f9fad2e6 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/EventChannel.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/EventChannel.cpp
@@ -16,6 +16,13 @@
#include "Builder.h"
#include "Find_Worker_T.h"
#include "Seq_Worker_T.h"
+#include "Topology_Saver.h"
+#include "Save_Persist_Worker_T.h"
+#include "Reconnect_Worker_T.h"
+
+#include "tao/debug.h"
+//#define DEBUG_LEVEL 9
+#define DEBUG_LEVEL TAO_debug_level
ACE_RCSID(Notify, TAO_Notify_EventChannel, "$Id$")
@@ -54,7 +61,7 @@ TAO_Notify_EventChannel::init (TAO_Notify_EventChannelFactory* ecf
, const CosNotification::AdminProperties & initial_admin
ACE_ENV_ARG_DECL)
{
- this->TAO_Notify_Object::init (ecf);
+ this->TAO_NOTIFY::Topology_Object::init (ecf);
this->ecf_ = ecf;
@@ -109,16 +116,69 @@ TAO_Notify_EventChannel::init (TAO_Notify_EventChannelFactory* ecf
this->set_admin (initial_admin ACE_ENV_ARG_PARAMETER);
ACE_CHECK;
- CosNotifyChannelAdmin::AdminID id;
+ // Note originally default admins were allocated here, bt this caused problems
+ // attempting to save the topology changes before the Event Channel was completely
+ // constructed and linked to the ECF.
+ // Lazy evaluation also avoids creating unneded admins.
+}
+
+
+void
+TAO_Notify_EventChannel::init (TAO_Notify_EventChannelFactory* ecf
+ ACE_ENV_ARG_DECL)
+{
+ this->TAO_NOTIFY::Topology_Object::init (ecf);
+
+ this->ecf_ = ecf;
+
+ this->ecf_->_incr_refcnt ();
+
+ // Init ca_container_
+ ACE_NEW_THROW_EX (this->ca_container_,
+ TAO_Notify_ConsumerAdmin_Container (),
+ CORBA::INTERNAL ());
+ ACE_CHECK;
+
+ this->ca_container_->init (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+
+ // Init ca_container_
+ ACE_NEW_THROW_EX (this->sa_container_,
+ TAO_Notify_SupplierAdmin_Container (),
+ CORBA::INTERNAL ());
+ ACE_CHECK;
+
+ this->sa_container_->init (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+
+ TAO_Notify_AdminProperties* admin_properties = 0;
+
+ // Set the admin properties.
+ ACE_NEW_THROW_EX (admin_properties,
+ TAO_Notify_AdminProperties (),
+ CORBA::NO_MEMORY ());
+ ACE_CHECK;
+
+ this->admin_properties_ = admin_properties;
+
+ // create the event manager. @@ use factory
+ ACE_NEW_THROW_EX (this->event_manager_,
+ TAO_Notify_Event_Manager (),
+ CORBA::INTERNAL ());
+ ACE_CHECK;
+
+ this->event_manager_->init (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
- // Set the default ConsumerAdmin.
- this->default_consumer_admin_ = this->new_for_consumers (CosNotifyChannelAdmin::OR_OP, id ACE_ENV_ARG_PARAMETER);
+ const CosNotification::QoSProperties &default_ec_qos =
+ TAO_Notify_PROPERTIES::instance ()->default_event_channel_qos_properties ();
+
+ this->set_qos (default_ec_qos ACE_ENV_ARG_PARAMETER);
ACE_CHECK;
- // Set the default SupplierAdmin.
- this->default_supplier_admin_ = this->new_for_suppliers (CosNotifyChannelAdmin::OR_OP, id ACE_ENV_ARG_PARAMETER);
}
+
void
TAO_Notify_EventChannel::_add_ref (ACE_ENV_SINGLE_ARG_DECL_NOT_USED)
{
@@ -214,20 +274,63 @@ TAO_Notify_EventChannel::MyFactory (ACE_ENV_SINGLE_ARG_DECL)
}
CosNotifyChannelAdmin::ConsumerAdmin_ptr
-TAO_Notify_EventChannel::default_consumer_admin (ACE_ENV_SINGLE_ARG_DECL_NOT_USED)
+TAO_Notify_EventChannel::default_consumer_admin (ACE_ENV_SINGLE_ARG_DECL)
ACE_THROW_SPEC ((
CORBA::SystemException
))
{
+ if (CORBA::is_nil (default_consumer_admin_.in ()))
+ {
+ ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, guard, this->default_admin_mutex_, CosNotifyChannelAdmin::ConsumerAdmin::_nil());
+ if (CORBA::is_nil (default_consumer_admin_.in ()))
+ {
+ CosNotifyChannelAdmin::AdminID id;
+ this->default_consumer_admin_ = this->new_for_consumers (CosNotifyChannelAdmin::OR_OP, id ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (CosNotifyChannelAdmin::ConsumerAdmin::_nil());
+ // Wish there was a better way to do this!
+ PortableServer::ServantBase * admin_servant =
+ this->poa_->reference_to_servant (
+ this->default_consumer_admin_.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (CosNotifyChannelAdmin::ConsumerAdmin::_nil());
+ TAO_Notify_Admin * pAdmin = dynamic_cast <TAO_Notify_Admin *> (admin_servant);
+ ACE_ASSERT (pAdmin != 0); // if this assert triggers, we have mixed implementations?
+ if (pAdmin != 0)
+ {
+ pAdmin->set_default (true);
+ }
+ }
+ }
return CosNotifyChannelAdmin::ConsumerAdmin::_duplicate (this->default_consumer_admin_.in ());
}
CosNotifyChannelAdmin::SupplierAdmin_ptr
-TAO_Notify_EventChannel::default_supplier_admin (ACE_ENV_SINGLE_ARG_DECL_NOT_USED)
+TAO_Notify_EventChannel::default_supplier_admin (ACE_ENV_SINGLE_ARG_DECL)
ACE_THROW_SPEC ((
CORBA::SystemException
))
{
+ if (CORBA::is_nil (default_supplier_admin_.in ()))
+ {
+ ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, guard, this->default_admin_mutex_, CosNotifyChannelAdmin::SupplierAdmin::_nil());
+ if (CORBA::is_nil (default_supplier_admin_.in ()))
+ {
+ CosNotifyChannelAdmin::AdminID id;
+ this->default_supplier_admin_ = this->new_for_suppliers (CosNotifyChannelAdmin::OR_OP, id ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (CosNotifyChannelAdmin::SupplierAdmin::_nil());
+ PortableServer::ServantBase * admin_servant =
+ this->poa_->poa()->reference_to_servant (
+ this->default_supplier_admin_.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+ TAO_Notify_Admin * pAdmin = dynamic_cast <TAO_Notify_Admin *> (admin_servant);
+ ACE_ASSERT (pAdmin != 0); // if this assert triggers, we have mixed implementations?
+ if (pAdmin != 0)
+ {
+ pAdmin->set_default (true);
+ }
+ }
+ }
return CosNotifyChannelAdmin::SupplierAdmin::_duplicate (this->default_supplier_admin_.in ());
}
@@ -248,7 +351,12 @@ TAO_Notify_EventChannel::new_for_consumers (CosNotifyChannelAdmin::InterFilterGr
))
{
- return TAO_Notify_PROPERTIES::instance()->builder()->build_consumer_admin (this, op, id ACE_ENV_ARG_PARAMETER);
+ ::CosNotifyChannelAdmin::ConsumerAdmin_var ca =
+ TAO_Notify_PROPERTIES::instance()->builder()->build_consumer_admin (this, op, id ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (ca._retn ());
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (ca._retn ());
+ return ca._retn ();
}
::CosNotifyChannelAdmin::SupplierAdmin_ptr
@@ -260,7 +368,12 @@ TAO_Notify_EventChannel::new_for_suppliers (CosNotifyChannelAdmin::InterFilterGr
CORBA::SystemException
))
{
- return TAO_Notify_PROPERTIES::instance()->builder()->build_supplier_admin (this, op, id ACE_ENV_ARG_PARAMETER);
+ ::CosNotifyChannelAdmin::SupplierAdmin_var sa =
+ TAO_Notify_PROPERTIES::instance()->builder()->build_supplier_admin (this, op, id ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (sa._retn ());
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (sa._retn ());
+ return sa._retn ();
}
CosNotifyChannelAdmin::ConsumerAdmin_ptr
@@ -337,21 +450,21 @@ TAO_Notify_EventChannel::get_admin (ACE_ENV_SINGLE_ARG_DECL)
}
CosEventChannelAdmin::ConsumerAdmin_ptr
-TAO_Notify_EventChannel::for_consumers (ACE_ENV_SINGLE_ARG_DECL_NOT_USED)
+TAO_Notify_EventChannel::for_consumers (ACE_ENV_SINGLE_ARG_DECL)
ACE_THROW_SPEC ((
CORBA::SystemException
))
{
- return CosEventChannelAdmin::ConsumerAdmin::_duplicate (this->default_consumer_admin_.in ());
+ return this->default_consumer_admin(ACE_ENV_SINGLE_ARG_PARAMETER);
}
CosEventChannelAdmin::SupplierAdmin_ptr
-TAO_Notify_EventChannel::for_suppliers (ACE_ENV_SINGLE_ARG_DECL_NOT_USED)
+TAO_Notify_EventChannel::for_suppliers (ACE_ENV_SINGLE_ARG_DECL)
ACE_THROW_SPEC ((
CORBA::SystemException
))
{
- return CosEventChannelAdmin::SupplierAdmin::_duplicate (this->default_supplier_admin_.in ());
+ return this->default_supplier_admin (ACE_ENV_SINGLE_ARG_PARAMETER);
}
void
@@ -367,6 +480,154 @@ TAO_Notify_EventChannel::validate_qos (const CosNotification::QoSProperties & /*
ACE_THROW (CORBA::NO_IMPLEMENT ());
}
+void
+TAO_Notify_EventChannel::save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL)
+{
+ bool changed = this->self_changed_;
+ this->self_changed_ = false;
+ this->children_changed_ = false;
+
+ if (is_persistent ())
+ {
+ TAO_NOTIFY::NVPList attrs;
+ this->save_attrs(attrs);
+
+ bool want_all_children = saver.begin_object(
+ this->id(), "channel", attrs, changed ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ TAO_NOTIFY::Save_Persist_Worker<TAO_Notify_ConsumerAdmin> ca_wrk(saver, want_all_children);
+
+ ACE_ASSERT(this->ca_container_ != 0);
+ this->ca_container_->collection()->for_each(&ca_wrk ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ TAO_NOTIFY::Save_Persist_Worker<TAO_Notify_SupplierAdmin> sa_wrk(saver, want_all_children);
+ ACE_ASSERT(this->sa_container_ != 0);
+ this->sa_container_->collection()->for_each(&sa_wrk ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ saver.end_object(this->id(), "channel" ACE_ENV_ARG_PARAMETER);
+ }
+}
+
+namespace {
+ template<class T>
+ void add_attr(TAO_NOTIFY::NVPList& attrs, const T& prop) {
+ if (prop.is_valid())
+ {
+ attrs.push_back(TAO_NOTIFY::NVP (prop));
+ }
+ }
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template void add_attr<TAO_NS_Property_Boolean>(TAO_NOTIFY::NVPList&,
+ const TAO_NS_Property_Boolean&);
+template void add_attr<TAO_NS_Property_T<int> >(TAO_NOTIFY::NVPList&,
+ const TAO_NS_Property_T<int>&);
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate void add_attr<TAO_NS_Property_Boolean>(\
+ TAO_NOTIFY::NVPList&, const TAO_NS_Property_Boolean&)
+#pragma instantiate void add_attr<TAO_NS_Property_T<int> >(\
+ TAO_NOTIFY::NVPList&, const TAO_NS_Property_T<int>&)
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+}
+
+void
+TAO_Notify_EventChannel::save_attrs(TAO_NOTIFY::NVPList& attrs)
+{
+ TAO_Notify_Object::save_attrs(attrs);
+ add_attr(attrs, this->admin_properties_->max_global_queue_length());
+ add_attr(attrs, this->admin_properties_->max_consumers());
+ add_attr(attrs, this->admin_properties_->max_suppliers());
+ add_attr(attrs, this->admin_properties_->reject_new_events());
+}
+
+void
+TAO_Notify_EventChannel::load_attrs(const TAO_NOTIFY::NVPList& attrs)
+{
+ TAO_Notify_Object::load_attrs(attrs);
+ attrs.load(this->admin_properties_->max_global_queue_length());
+ attrs.load(this->admin_properties_->max_consumers());
+ attrs.load(this->admin_properties_->max_suppliers());
+ attrs.load(this->admin_properties_->reject_new_events());
+ this->admin_properties_->init();
+}
+
+TAO_NOTIFY::Topology_Object *
+TAO_Notify_EventChannel::load_child (const ACE_CString &type,
+ CORBA::Long id,
+ const TAO_NOTIFY::NVPList& attrs
+ ACE_ENV_ARG_DECL)
+{
+ TAO_NOTIFY::Topology_Object* result = this;
+ if (type == "consumer_admin")
+ {
+ if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) EventChannel reload consumer_admin %d\n")
+ , ACE_static_cast (int, id)
+ ));
+
+ // call special builder method to reload
+ TAO_Notify_Builder* bld = TAO_Notify_PROPERTIES::instance()->builder();
+ TAO_Notify_ConsumerAdmin * ca = bld->build_consumer_admin (
+ this,
+ id
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ ca->load_attrs (attrs);
+ if (ca->is_default ())
+ {
+ CORBA::Object_var caob = this->poa_->servant_to_reference (ca ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ this->default_consumer_admin_ =
+ CosNotifyChannelAdmin::ConsumerAdmin::_narrow (
+ caob.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ }
+ result = ca;
+ }
+ else if (type == "supplier_admin")
+ {
+ if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) EventChannel reload supplier_admin %d\n")
+ , ACE_static_cast (int, id)
+ ));
+ TAO_Notify_Builder* bld = TAO_Notify_PROPERTIES::instance()->builder();
+
+ TAO_Notify_SupplierAdmin * sa = bld->build_supplier_admin (
+ this,
+ id
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ sa->load_attrs (attrs);
+ if (sa->is_default ())
+ {
+ CORBA::Object_var saob = this->poa_->servant_to_reference (sa ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ this->default_supplier_admin_ =
+ CosNotifyChannelAdmin::SupplierAdmin::_narrow (
+ saob.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ }
+ result = sa;
+ }
+ return result;
+}
+
+void
+TAO_Notify_EventChannel::reconnect (ACE_ENV_SINGLE_ARG_DECL)
+{
+ TAO_NOTIFY::Reconnect_Worker<TAO_Notify_ConsumerAdmin> ca_wrk;
+ ACE_ASSERT(this->ca_container_ != 0);
+ this->ca_container_->collection()->for_each(&ca_wrk ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ TAO_NOTIFY::Reconnect_Worker<TAO_Notify_SupplierAdmin> sa_wrk;
+ ACE_ASSERT(this->sa_container_ != 0);
+ this->sa_container_->collection()->for_each(&sa_wrk ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+}
+
#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
template class TAO_Notify_Find_Worker_T<TAO_Notify_ConsumerAdmin
@@ -387,6 +648,11 @@ template class TAO_Notify_Container_T <TAO_Notify_SupplierAdmin>;
template class TAO_ESF_Shutdown_Proxy<TAO_Notify_ConsumerAdmin>;
template class TAO_ESF_Shutdown_Proxy<TAO_Notify_SupplierAdmin>;
+template class Save_Persist_Worker<TAO_Notify_ConsumerAdmin>;
+template class Save_Persist_Worker<TAO_Notify_SupplierAdmin>;
+template class TAO_NOTIFY::Reconnect_Worker<TAO_Notify_ConsumerAdmin>;
+template class TAO_NOTIFY::Reconnect_Worker<TAO_Notify_SupplierAdmin>;
+
#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
#pragma instantiate TAO_Notify_Find_Worker_T<TAO_Notify_ConsumerAdmin
@@ -407,4 +673,9 @@ template class TAO_ESF_Shutdown_Proxy<TAO_Notify_SupplierAdmin>;
#pragma instantiate TAO_ESF_Shutdown_Proxy<TAO_Notify_ConsumerAdmin>
#pragma instantiate TAO_ESF_Shutdown_Proxy<TAO_Notify_SupplierAdmin>
+#pragma instantiate Save_Persist_Worker<TAO_Notify_ConsumerAdmin>
+#pragma instantiate Save_Persist_Worker<TAO_Notify_SupplierAdmin>
+#pragma instantiate TAO_NOTIFY::Reconnect_Worker<TAO_Notify_ConsumerAdmin>
+#pragma instantiate TAO_NOTIFY::Reconnect_Worker<TAO_Notify_SupplierAdmin>
+
#endif /*ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/EventChannel.h b/TAO/orbsvcs/orbsvcs/Notify/EventChannel.h
index e334a2f03e5..68297ad2b0d 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/EventChannel.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/EventChannel.h
@@ -21,7 +21,7 @@
#endif /* ACE_LACKS_PRAGMA_ONCE */
#include "orbsvcs/CosNotifyChannelAdminS.h"
-
+#include "Topology_Object.h"
#include "Object.h"
class TAO_Notify_ConsumerAdmin;
@@ -30,7 +30,7 @@ class TAO_Notify_EventChannelFactory;
template <class TYPE> class TAO_Notify_Container_T;
#if defined(_MSC_VER)
-#if (_MSC_VER >= 1200)
+ #if (_MSC_VER >= 1200)
#pragma warning(push)
#endif /* _MSC_VER >= 1200 */
#pragma warning(disable:4250)
@@ -42,9 +42,9 @@ template <class TYPE> class TAO_Notify_Container_T;
* @brief Implementation of CosNotifyChannelAdmin::EventChannel
*
*/
-class TAO_Notify_Serv_Export TAO_Notify_EventChannel
- : public POA_CosNotifyChannelAdmin::EventChannel,
- public virtual TAO_Notify_Object
+class TAO_Notify_Serv_Export TAO_Notify_EventChannel
+ : public POA_CosNotifyChannelAdmin::EventChannel,
+ public TAO_NOTIFY::Topology_Parent
{
friend class TAO_Notify_Builder;
@@ -64,6 +64,10 @@ public:
, const CosNotification::AdminProperties & initial_admin
ACE_ENV_ARG_DECL);
+ /// Init (for reload)
+ void init (TAO_Notify_EventChannelFactory* ecf
+ ACE_ENV_ARG_DECL);
+
/// Remove ConsumerAdmin from its container.
void remove (TAO_Notify_ConsumerAdmin* consumer_admin ACE_ENV_ARG_DECL);
@@ -74,11 +78,29 @@ public:
virtual void _add_ref (ACE_ENV_SINGLE_ARG_DECL);
virtual void _remove_ref (ACE_ENV_SINGLE_ARG_DECL);
+ // TAO_NOTIFY::Topology_Parent
+
+ virtual void save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL);
+ virtual TAO_NOTIFY::Topology_Object* load_child (const ACE_CString &type,
+ CORBA::Long id,
+ const TAO_NOTIFY::NVPList& attrs
+ ACE_ENV_ARG_DECL);
+ virtual void reconnect (ACE_ENV_SINGLE_ARG_DECL);
+
+ virtual TAO_Notify_Object_Id get_id () const {return id();}
+
+ TAO_Notify_ProxyConsumer * find_proxy_consumer (TAO_NOTIFY::IdVec & id_path, size_t position ACE_ENV_ARG_DECL);
+ TAO_Notify_ProxySupplier * find_proxy_supplier (TAO_NOTIFY::IdVec & id_path, size_t position ACE_ENV_ARG_DECL);
+
/// Release
virtual void release (void);
/// Shutdown
virtual int shutdown (ACE_ENV_SINGLE_ARG_DECL);
+ virtual void load_attrs(const TAO_NOTIFY::NVPList& attrs);
+
+protected:
+ virtual void save_attrs(TAO_NOTIFY::NVPList& attrs);
protected:
typedef TAO_Notify_Container_T <TAO_Notify_ConsumerAdmin> TAO_Notify_ConsumerAdmin_Container;
@@ -94,6 +116,8 @@ protected:
/// SupplierAdmin Container.
TAO_Notify_SupplierAdmin_Container *sa_container_;
+ TAO_SYNCH_MUTEX default_admin_mutex_;
+
// Default Consumer Admin
CosNotifyChannelAdmin::ConsumerAdmin_var default_consumer_admin_;
diff --git a/TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.cpp b/TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.cpp
index debe138d960..a241b822ce8 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.cpp
@@ -12,11 +12,22 @@ ACE_RCSID(Notify, TAO_Notify_EventChannelFactory, "$Id$")
#include "Properties.h"
#include "Factory.h"
#include "Builder.h"
+#include "Topology_Saver.h"
+#include "Topology_Loader.h"
+#include "Save_Persist_Worker_T.h"
+#include "Reconnect_Worker_T.h"
+#include "Event_Persistence_Strategy.h"
+#include "Routing_Slip_Persistence_Manager.h"
+
#include "EventChannel.h"
#include "Container_T.h"
#include "Find_Worker_T.h"
#include "Seq_Worker_T.h"
+#include "tao/debug.h"
+#define DEBUG_OFFSET 0
+#define DEBUG_LEVEL (TAO_debug_level + DEBUG_OFFSET)
+
typedef TAO_Notify_Find_Worker_T<TAO_Notify_EventChannel
, CosNotifyChannelAdmin::EventChannel
, CosNotifyChannelAdmin::EventChannel_ptr
@@ -26,7 +37,12 @@ TAO_Notify_EventChannel_Find_Worker;
typedef TAO_Notify_Seq_Worker_T<TAO_Notify_EventChannel> TAO_Notify_EventChannel_Seq_Worker;
TAO_Notify_EventChannelFactory::TAO_Notify_EventChannelFactory (void)
- :ec_container_ (0)
+ : ec_container_ (0)
+ , topology_save_seq_ (0)
+ , topology_factory_(0)
+ , reconnect_registry_(*this)
+ , loading_topology_ (false)
+
{
}
@@ -95,6 +111,17 @@ TAO_Notify_EventChannelFactory::init (PortableServer::POA_ptr poa ACE_ENV_ARG_DE
// Make the Proxys acivate in this same POA.
this->proxy_poa_ = this->object_poa_;
+
+ // Note topology factory is configured separately from the "builder" mediated
+ // objects since it is independant of the "style" of Notification Service.
+ this->topology_factory_ =
+ ACE_Dynamic_Service <TAO_NOTIFY::Topology_Factory>::instance ("Topology_Factory");
+
+ this->load_topology (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+
+ this->load_event_persistence (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
}
void
@@ -121,6 +148,7 @@ TAO_Notify_EventChannelFactory::remove (TAO_Notify_EventChannel* event_channel A
{
this->ec_container_->remove (event_channel ACE_ENV_ARG_PARAMETER);
ACE_CHECK;
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
}
int
@@ -152,11 +180,16 @@ TAO_Notify_EventChannelFactory::get_default_filter_factory (ACE_ENV_SINGLE_ARG_D
, CosNotification::UnsupportedAdmin
))
{
- return TAO_Notify_PROPERTIES::instance()->builder()->build_event_channel (this
+ CosNotifyChannelAdmin::EventChannel_var ec =
+ TAO_Notify_PROPERTIES::instance()->builder()->build_event_channel (this
, initial_qos
, initial_admin
, id
ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (ec._retn ());
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (ec._retn ());
+ return ec._retn ();
}
CosNotifyChannelAdmin::ChannelIDSeq*
@@ -182,6 +215,260 @@ TAO_Notify_EventChannelFactory::get_event_channel (CosNotifyChannelAdmin::Channe
return find_worker.resolve (id, *this->ec_container_ ACE_ENV_ARG_PARAMETER);
}
+void
+TAO_Notify_EventChannelFactory::set_topology_factory(TAO_NOTIFY::Topology_Factory* f)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) Debug Topology_Factory installed in EventChannelFactory.\n")
+ ));
+ // If the above meessage appears when you don't expect it
+ // use svc.conf to install the topology factory rather
+ // than calling this method.
+ this->topology_factory_ = f;
+}
+
+void
+TAO_Notify_EventChannelFactory::load_topology (ACE_ENV_SINGLE_ARG_DECL)
+{
+ this->loading_topology_ = true;
+ if (this->topology_factory_ != 0)
+ {
+ auto_ptr<TAO_NOTIFY::Topology_Loader> tl(this->topology_factory_->create_loader());
+ if (tl.get () != 0)
+ {
+ tl->load (this ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+ }
+ else
+ {
+ if (TAO_debug_level > 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Topology persistence disabled.\n")));
+ }
+ this->loading_topology_ = false;
+}
+bool
+TAO_Notify_EventChannelFactory::is_persistent () const
+{
+ return true;
+}
+
+void
+TAO_Notify_EventChannelFactory::save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL)
+{
+ bool changed = this->self_changed_;
+ this->self_changed_ = false;
+ this->children_changed_ = false;
+
+ TAO_NOTIFY::NVPList attrs; // ECF has no attributes
+
+ bool want_all_children =
+ saver.begin_object(0, "channel_factory", attrs, changed ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ // for each deleted child
+ // delete_child // if the child has persistence.
+
+ TAO_NOTIFY::Save_Persist_Worker<TAO_Notify_EventChannel> wrk(saver, want_all_children);
+
+ ACE_ASSERT(this->ec_container_ != 0);
+ this->ec_container_->collection()->for_each(&wrk ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ if (want_all_children || this->reconnect_registry_.is_changed ())
+ {
+ this->reconnect_registry_.save_persistent(saver ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+ saver.end_object(0, "channel_factory" ACE_ENV_ARG_PARAMETER);
+}
+
+void
+TAO_Notify_EventChannelFactory::load_event_persistence (ACE_ENV_SINGLE_ARG_DECL)
+{
+#ifdef EVENT_PERISISTENCE_SUPPORT //@@todo
+ TAO_NOTIFY::Event_Persistence_Strategy * strategy =
+ ACE_Dynamic_Service <TAO_NOTIFY::Event_Persistence_Strategy>::instance ("Event_Persistence");
+ if (strategy != 0)
+ {
+ if (this->topology_factory_ != 0)
+ {
+ Event_Persistence_Factory * factory = strategy->get_factory ();
+ if (factory != 0)
+ {
+ for (
+ Routing_Slip_Persistence_Manager * rspm = factory->first_reload_manager();
+ rspm != 0;
+ rspm = rspm->load_next ())
+ {
+ TAO_NOTIFY::Routing_Slip_Ptr routing_slip = Routing_Slip::create (*this, rspm);
+ if (!routing_slip.null ())
+ {
+ this->routing_slip_restart_set_.insert (routing_slip);
+ }
+ else
+ {
+ //@@todo: tell the rspm it's an orphan, but we can't during reload
+ // we need collect these and come back later to remove them
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Reload persistent event failed.\n")
+ ));
+ }
+ }
+ }
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Notify Service: Configuration error. Event Persistence requires Topology Persistence.\n")
+ ));
+ ACE_THROW (CORBA::PERSIST_STORE());
+ ACE_CHECK;
+ }
+ }
+#else //EVENT_PERISISTENCE_SUPPORT //@@todo
+#pragma message ("TODO: EVENT_PERISISTENCE_SUPPORT")
+#endif //EVENT_PERISISTENCE_SUPPORT //@@todo
+}
+
+bool
+TAO_Notify_EventChannelFactory::change_to_parent (ACE_ENV_SINGLE_ARG_DECL)
+{
+ bool saving = false;
+ if (! this->loading_topology_)
+ {
+ // A null pointer means that saving of topology is disabled.
+ if (this->topology_factory_ != 0)
+ {
+ saving = true;
+ // seq is used to check save-in-progress
+ // if it changes while we're waiting for the lock
+ // then our change may have already been saved, so
+ // just return. Caller will signal change again if necessary.
+ short seq = this->topology_save_seq_;
+ ACE_GUARD_THROW_EX (TAO_SYNCH_MUTEX, ace_mon, this->topology_save_lock_, CORBA::INTERNAL ());
+ ACE_CHECK_RETURN(false);
+ if (seq == this->topology_save_seq_)
+ {
+ auto_ptr<TAO_NOTIFY::Topology_Saver> saver(this->topology_factory_->create_saver());
+ if (saver.get() != 0)
+ {
+ this->save_persistent(*saver ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(false);
+ saver->close (ACE_ENV_SINGLE_ARG_PARAMETER);
+ }
+ this->topology_save_seq_ += 1;
+ }
+ }
+ }
+ return saving;
+}
+
+TAO_NOTIFY::Topology_Object*
+TAO_Notify_EventChannelFactory::load_child (const ACE_CString& type,
+ CORBA::Long id,
+ const TAO_NOTIFY::
+ NVPList& attrs
+ ACE_ENV_ARG_DECL)
+{
+ // ignore anything but our valid children (ie channel)
+ TAO_NOTIFY::Topology_Object * result = this;
+ if (type == "channel")
+ {
+ if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) EventChannelFactory reload channel %d\n")
+ , ACE_static_cast (int, id)
+ ));
+
+ TAO_Notify_Builder* bld = TAO_Notify_PROPERTIES::instance()->builder();
+ TAO_Notify_EventChannel * ec = bld->build_event_channel(
+ this ,
+ id
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+
+ ec->load_attrs (attrs);
+
+ result = ec;
+ }
+ else if (type == TAO_NOTIFY::REGISTRY_TYPE)
+ {
+ result = & this->reconnect_registry_;
+ }
+ return result;
+}
+
+void
+TAO_Notify_EventChannelFactory::reconnect (ACE_ENV_SINGLE_ARG_DECL)
+{
+ // Reconnect all children first
+ TAO_NOTIFY::Reconnect_Worker<TAO_Notify_EventChannel> wrk;
+
+ this->ec_container_->collection()->for_each(&wrk ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ // Then send reconnection announcement to registered clients
+ CORBA::Object_var obj = this->poa()->id_to_reference (this->id () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ CosNotifyChannelAdmin::EventChannelFactory_var this_reference = CosNotifyChannelAdmin::EventChannelFactory::_narrow (obj.in ());
+ ACE_ASSERT (CORBA::is_nil (this_reference.in ()));
+ // todo: Is there an easier way?
+ this->reconnect_registry_.send_reconnect (this_reference.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+#ifdef TODO_EVENT_PERSISTENCE //
+ // reactivate events in-progress
+ Routing_Slip_Set::CONST_ITERATOR iter (this->routing_slip_restart_set_);
+ Routing_Slip_Ptr * routing_slip;
+ for (iter.first(); iter.next(routing_slip); iter.advance())
+ {
+ (*routing_slip)->reconnect(ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+ this->routing_slip_restart_set_.reset ();
+#else
+ int TODO_Event_Persistence;
+#endif
+}
+
+NotifyExt::ReconnectionRegistry::ReconnectionID
+TAO_Notify_EventChannelFactory::register_callback (
+ NotifyExt::ReconnectionCallback_ptr reconnection
+ ACE_ENV_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ return this->reconnect_registry_.register_callback (
+ reconnection
+ ACE_ENV_ARG_PARAMETER);
+}
+
+void
+TAO_Notify_EventChannelFactory::unregister_callback (
+ NotifyExt::ReconnectionRegistry::ReconnectionID id
+ ACE_ENV_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ this->reconnect_registry_.unregister_callback (
+ id
+ ACE_ENV_ARG_PARAMETER);
+}
+
+CORBA::Boolean
+TAO_Notify_EventChannelFactory::is_alive (ACE_ENV_SINGLE_ARG_DECL_NOT_USED)
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ return CORBA::Boolean (1);
+}
+
+void
+TAO_Notify_EventChannelFactory::save_topology (ACE_ENV_SINGLE_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+}
+
#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
template class TAO_Notify_Find_Worker_T<TAO_Notify_EventChannel
diff --git a/TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.h b/TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.h
index c93fffd92a2..df2578bd4ea 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.h
@@ -22,8 +22,10 @@
#include "orbsvcs/CosNotifyChannelAdminS.h"
#include "orbsvcs/NotifyExtS.h"
-
-#include "Object.h"
+#include "Topology_Object.h"
+#include "Topology_Factory.h"
+#include "Reconnection_Registry.h"
+//@@todo #include "Routing_Slip.h"
class TAO_Notify_EventChannel;
template <class TYPE> class TAO_Notify_Container_T;
@@ -41,11 +43,13 @@ template <class TYPE> class TAO_Notify_Container_T;
* @brief Implementation of CosNotifyChannelAdmin::EventChannelFactory
*
*/
-class TAO_Notify_Serv_Export TAO_Notify_EventChannelFactory
- : public virtual POA_NotifyExt::EventChannelFactory,
- public virtual TAO_Notify_Object
+class TAO_Notify_Serv_Export TAO_Notify_EventChannelFactory
+ : public virtual POA_NotifyExt::EventChannelFactory
+ , public TAO_NOTIFY::Topology_Parent
+
{
friend class TAO_Notify_Builder;
+//@@todo typedef ACE_Unbounded_Set <TAO_NOTIFY::Routing_Slip_Ptr> Routing_Slip_Set;
public:
/// Constuctor
@@ -72,11 +76,42 @@ public:
ACE_ENV_SINGLE_ARG_DECL
);
- /// shutdown
- virtual int shutdown (ACE_ENV_SINGLE_ARG_DECL);
+
+ //////////////////////////
+ // The following methods are for
+ // unit testing and debugging
+
+ /// Use the registered Topology_Factory to create a loader, and
+ /// load the topology. If no Topology_Factory is registered
+ /// then nothing will be loaded.
+ void load_topology (ACE_ENV_SINGLE_ARG_DECL);
+
+ /// Use the passed in saver factory to generate topology saver objects.
+ /// Does not take ownership.
+ void set_topology_factory(TAO_NOTIFY::Topology_Factory* sf);
+
+ //-- Topology_Parent
+
+ virtual bool is_persistent () const;
+
+ virtual void save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL);
+ virtual bool change_to_parent (ACE_ENV_SINGLE_ARG_DECL);
+ virtual TAO_NOTIFY::Topology_Object* load_child (const ACE_CString &type,
+ CORBA::Long id,
+ const TAO_NOTIFY::NVPList& attrs
+ ACE_ENV_ARG_DECL);
+ virtual void reconnect (ACE_ENV_SINGLE_ARG_DECL);
+
+ /// handle change notifications
+ bool handle_change (ACE_ENV_SINGLE_ARG_DECL);
+
+ void load_event_persistence (ACE_ENV_SINGLE_ARG_DECL);
+
+ virtual void save_topology (ACE_ENV_SINGLE_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException));
protected:
- typedef TAO_Notify_Container_T<TAO_Notify_EventChannel>
+ typedef TAO_Notify_Container_T<TAO_Notify_EventChannel>
TAO_Notify_EventChannel_Container;
/// = Data Members
@@ -86,21 +121,38 @@ public:
/// The default filter factory.
CosNotifyFilter::FilterFactory_var default_filter_factory_;
- /// = NotifyExt method
+ /// = NotifyExt methods
virtual void destroy (ACE_ENV_SINGLE_ARG_DECL)
ACE_THROW_SPEC ((
CORBA::SystemException
));
+ /// shutdown
+ virtual int shutdown (ACE_ENV_SINGLE_ARG_DECL);
+
+ virtual
+ NotifyExt::ReconnectionRegistry::ReconnectionID register_callback (
+ NotifyExt::ReconnectionCallback_ptr reconnection
+ ACE_ENV_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException));
+
+ virtual void unregister_callback (
+ NotifyExt::ReconnectionRegistry::ReconnectionID id
+ ACE_ENV_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException));
+
+ virtual CORBA::Boolean is_alive (ACE_ENV_SINGLE_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException));
+
/// = CosNotifyChannelAdmin Methods
virtual ::CosNotifyChannelAdmin::EventChannel_ptr create_channel (
const CosNotification::QoSProperties & initial_qos,
const CosNotification::AdminProperties & initial_admin,
- CosNotifyChannelAdmin::ChannelID_out id
+ CosNotifyChannelAdmin::ChannelID_out id
ACE_ENV_ARG_DECL
)
- ACE_THROW_SPEC ((CORBA::SystemException,
+ ACE_THROW_SPEC ((CORBA::SystemException,
CosNotification::UnsupportedQoS,
CosNotification::UnsupportedAdmin));
@@ -115,6 +167,17 @@ public:
)
ACE_THROW_SPEC ((CORBA::SystemException,
CosNotifyChannelAdmin::ChannelNotFound));
+
+private:
+ TAO_SYNCH_MUTEX topology_save_lock_;
+ /// change-in-progress detector to avoid duplicates
+ short topology_save_seq_;
+ TAO_NOTIFY::Topology_Factory* topology_factory_;
+ TAO_NOTIFY::Reconnection_Registry reconnect_registry_;
+ bool loading_topology_;
+
+//@@todo Routing_Slip_Set routing_slip_restart_set_;
+
};
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
diff --git a/TAO/orbsvcs/orbsvcs/Notify/EventType.cpp b/TAO/orbsvcs/orbsvcs/Notify/EventType.cpp
index bcfae54e616..3f51adfdaf8 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/EventType.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/EventType.cpp
@@ -10,6 +10,8 @@
#include "EventType.inl"
#endif /* __ACE_INLINE__ */
+#include "Topology_Saver.h"
+
ACE_RCSID (Notify,
TAO_Notify_EventType,
"$Id$")
@@ -139,3 +141,36 @@ TAO_Notify_EventType::dump (void) const
this->event_type_.domain_name.in (),
this->event_type_.type_name.in ()));
}
+
+/// Initialize from an NVPList, return false on failure
+bool TAO_Notify_EventType::init(const TAO_NOTIFY::NVPList& attrs)
+{
+ bool result = false;
+
+ ACE_CString domain;
+ ACE_CString type;
+ if (attrs.load("Domain", domain) && attrs.load("Type", type))
+ {
+ this->init_i(domain.c_str(), type.c_str());
+ result = true;
+ }
+ return result;
+
+}
+
+ // TAO_NOTIFY::Topology_Object
+
+void
+TAO_Notify_EventType::save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL)
+{
+ TAO_NOTIFY::NVPList attrs;
+ bool changed = true;
+
+ attrs.push_back(TAO_NOTIFY::NVP("Domain", this->event_type_.domain_name.in()));
+ attrs.push_back(TAO_NOTIFY::NVP("Type", this->event_type_.type_name.in()));
+ saver.begin_object(0, "subscription", attrs, changed ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ saver.end_object(0, "subscription" ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+}
diff --git a/TAO/orbsvcs/orbsvcs/Notify/EventType.h b/TAO/orbsvcs/orbsvcs/Notify/EventType.h
index 3fcd875060d..7b76d7c78b0 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/EventType.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/EventType.h
@@ -21,6 +21,7 @@
#endif /* ACE_LACKS_PRAGMA_ONCE */
#include "orbsvcs/CosNotificationC.h"
+#include "Topology_Object.h"
/**
* @class TAO_Notify_EventType
@@ -31,7 +32,7 @@
* It is used by the Event Manager as a key to find subscription lists.
*
*/
-class TAO_Notify_Serv_Export TAO_Notify_EventType
+class TAO_Notify_Serv_Export TAO_Notify_EventType : public TAO_NOTIFY::Topology_Savable
{
public:
/// Constuctor
@@ -70,6 +71,13 @@ public:
/// Helper to print contents.
void dump (void) const;
+ /// Initialize from an NVPList, return false on failure
+ bool init(const TAO_NOTIFY::NVPList& attrs);
+
+ // TAO_NOTIFY::Topology_Object
+
+ virtual void save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL);
+
protected:
/// Init this object.
void init_i (const char* domain_name, const char* type_name);
diff --git a/TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.cpp b/TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.cpp
index 5161da17add..b0fe9d65c53 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.cpp
@@ -6,6 +6,12 @@
#include "EventTypeSeq.inl"
#endif /* __ACE_INLINE__ */
+#include "Topology_Saver.h"
+
+#include "TAO/debug.h"
+//#define DEBUG_LEVEL 9
+#define DEBUG_LEVEL TAO_debug_level
+
ACE_RCSID(Notify, TAO_Notify_EventTypeSeq, "$Id$")
TAO_Notify_EventTypeSeq::TAO_Notify_EventTypeSeq (void)
@@ -238,3 +244,71 @@ TAO_Notify_EventTypeSeq::dump (void) const
ACE_DEBUG ((LM_DEBUG, ", "));
}
}
+
+ // TAO_NOTIFY::Topology_Object
+void
+TAO_Notify_EventTypeSeq::save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL)
+{
+ bool changed = this->self_changed_;
+ this->self_changed_ = false;
+ this->children_changed_ = false;
+ TAO_NOTIFY::NVPList attrs;
+
+ TAO_Notify_EventTypeSeq::ITERATOR iter (*this);
+ TAO_Notify_EventType* event_type;
+
+ if (this->size() != 0)
+ {
+ saver.begin_object(0, "subscriptions", attrs, changed ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ for (iter.first (); iter.next (event_type) != 0; iter.advance ())
+ {
+ event_type->save_persistent(saver ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+// todo:
+// for all deleted children
+// {
+// saver.delete_child(child_type, child_id);
+// }
+ saver.end_object(0, "subscriptions" ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+}
+
+TAO_NOTIFY::Topology_Object*
+TAO_Notify_EventTypeSeq::load_child (const ACE_CString &type, CORBA::Long id,
+ const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL)
+{
+ TAO_NOTIFY::Topology_Object *result = this;
+ TAO_Notify_EventType et;
+
+ if ((type == "subscription") && et.init(attrs))
+ {
+ if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Event_Type reload subscription\n")
+ ));
+ inherited::insert(et);
+ }
+ return result;
+}
+
+void
+TAO_Notify_EventTypeSeq::release (void)
+{
+ delete this;
+}
+
+TAO_Notify_EventTypeSeq &
+TAO_Notify_EventTypeSeq::operator = (const TAO_Notify_EventTypeSeq & rhs)
+{
+ ACE_Unbounded_Set <TAO_Notify_EventType>::operator = (rhs);
+ return *this;
+}
+
+TAO_Notify_EventTypeSeq::TAO_Notify_EventTypeSeq (const TAO_Notify_EventTypeSeq & rhs)
+ : ACE_Unbounded_Set <TAO_Notify_EventType> (rhs)
+{
+}
+
+
diff --git a/TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.h b/TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.h
index 9f492e605e7..09e0b0ca3c9 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.h
@@ -28,7 +28,10 @@
* @brief Allows operations using the CosNotification::EventTypeSeq type.
*
*/
-class TAO_Notify_Serv_Export TAO_Notify_EventTypeSeq : public ACE_Unbounded_Set <TAO_Notify_EventType>
+class TAO_Notify_Serv_Export TAO_Notify_EventTypeSeq
+ : public ACE_Unbounded_Set <TAO_Notify_EventType>
+ , public TAO_NOTIFY::Topology_Object
+
{
typedef ACE_Unbounded_Set <TAO_Notify_EventType> inherited;
@@ -36,6 +39,8 @@ public:
/// Constructor
TAO_Notify_EventTypeSeq (void);
TAO_Notify_EventTypeSeq (const CosNotification::EventTypeSeq& event_type_seq);
+ TAO_Notify_EventTypeSeq (const TAO_Notify_EventTypeSeq & rhs);
+ TAO_Notify_EventTypeSeq & operator = (const TAO_Notify_EventTypeSeq & rhs);
/// Preprocess the types added and removed.
void init (TAO_Notify_EventTypeSeq& added, TAO_Notify_EventTypeSeq& removed);
@@ -64,6 +69,14 @@ public:
/// Print the contents.
void dump (void) const;
+
+ // TAO_NOTIFY::Topology_Object
+
+ virtual void save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL);
+ virtual TAO_NOTIFY::Topology_Object* load_child (const ACE_CString &type, CORBA::Long id,
+ const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL);
+ virtual void release (void);
+
};
#if defined (__ACE_INLINE__)
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Event_Manager.cpp b/TAO/orbsvcs/orbsvcs/Notify/Event_Manager.cpp
index 9a03b6c3c96..ef8c778aa9d 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Event_Manager.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/Event_Manager.cpp
@@ -76,7 +76,7 @@ void
TAO_Notify_Event_Manager::connect (TAO_Notify_ProxyConsumer* proxy_consumer ACE_ENV_ARG_DECL)
{
this->supplier_map_->connect (proxy_consumer ACE_ENV_ARG_PARAMETER);
-
+ ACE_CHECK;
// Inform about subscription types.
TAO_Notify_EventTypeSeq removed;
proxy_consumer->types_changed (this->subscription_types (), removed ACE_ENV_ARG_PARAMETER);
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Event_Persistence_Factory.h b/TAO/orbsvcs/orbsvcs/Notify/Event_Persistence_Factory.h
new file mode 100644
index 00000000000..61134f2d30e
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Event_Persistence_Factory.h
@@ -0,0 +1,52 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Event_Persistence_Factory.h
+ *
+ * $Id$
+ *
+ * A factory class that creates a Routing_Slip_Persistence_Manager.
+ *
+ * @author Jonathan Pollack <pollack_j@ociweb.com>
+ */
+//=============================================================================
+
+#ifndef EVENT_PERSISTENCE_FACTORY_H
+#define EVENT_PERSISTENCE_FACTORY_H
+#include /**/ "ace/pre.h"
+#include /**/ "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "notify_export.h"
+
+//#include "Event_Persistence_Strategy.h"
+//#include "Persistent_File_Allocator.h"
+//#include "Routing_Slip_Persistence_Manager.h"
+//#include <ace/SString.h>
+
+namespace TAO_NOTIFY
+{
+ class Routing_Slip_Persistence_Manager;
+ class Persistent_Callback;
+
+ /// interface to be implemented by specific Event_Persistence_Factories
+ class TAO_Notify_Export Event_Persistence_Factory
+ {
+ public:
+ /// Create a Persistence Manager
+ virtual Routing_Slip_Persistence_Manager *
+ create_routing_slip_persistence_manager (Persistent_Callback * callback) = 0;
+
+ /// Begin the reload process by returning the first Routing_Slip_Persistence_Manager
+ /// to continue call Routing_Slip_Persistence_Manager::load_next ()
+ virtual Routing_Slip_Persistence_Manager * first_reload_manager () = 0;
+
+ };
+} // namespace TAO_NOTIFY
+
+#include /**/ "ace/post.h"
+#endif /* EVENT_PERSISTENCE_FACTORY_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Event_Persistence_Strategy.h b/TAO/orbsvcs/orbsvcs/Notify/Event_Persistence_Strategy.h
new file mode 100644
index 00000000000..d2fcacf03c6
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Event_Persistence_Strategy.h
@@ -0,0 +1,47 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Event_Persistence_Strategy.h
+ *
+ * $Id$
+ *
+ * A factory class that creates a Routing_Slip_Persistence_Manager.
+ *
+ * @author Jonathan Pollack <pollack_j@ociweb.com>
+ */
+//=============================================================================
+
+#ifndef EVENT_PERSISTENCE_STRATEGY_H
+#define EVENT_PERSISTENCE_STRATEGY_H
+#include /**/ "ace/pre.h"
+#include /**/ "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "notify_export.h"
+
+#include "ace/Service_Object.h"
+
+namespace TAO_NOTIFY
+{
+ class Event_Persistence_Factory;
+
+ /// Interface to be implemented by specific strategies
+ class TAO_Notify_Export Event_Persistence_Strategy: public ACE_Service_Object
+ {
+ public:
+
+ // get the current factory, creating it if necessary
+ virtual Event_Persistence_Factory * get_factory () = 0;
+
+ // release the current factory so a new one can be created
+ virtual void reset () = 0;
+ };
+
+} // namespace TAO_NOTIFY
+
+#include /**/ "ace/post.h"
+#endif /* EVENT_PERSISTENCE_STRATEGY_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.cpp b/TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.cpp
index d6b64275843..9ec4a1099de 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.cpp
@@ -8,6 +8,8 @@
ACE_RCSID(Notify, FilterAdmin, "$Id$")
+#include "Topology_Saver.h"
+#include "Properties.h"
#include "ace/Refcounted_Auto_Ptr.h"
// Implementation skeleton constructor
@@ -128,6 +130,76 @@ TAO_Notify_FilterAdmin::remove_all_filters (ACE_ENV_SINGLE_ARG_DECL)
this->filter_list_.unbind_all ();
}
+void
+TAO_Notify_FilterAdmin::save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL)
+{
+ if (this->filter_list_.current_size() == 0)
+ return;
+
+ bool changed = true;
+
+ TAO_NOTIFY::NVPList attrs;
+ bool want_children = saver.begin_object(0, "filter_admin", attrs, changed ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ if (want_children)
+ {
+ FILTER_LIST::ITERATOR iter (this->filter_list_);
+ FILTER_LIST::ENTRY* entry;
+
+ TAO_Notify_Properties* properties = TAO_Notify_PROPERTIES::instance();
+ CORBA::ORB_var orb = properties->orb();
+ ACE_ASSERT(! CORBA::is_nil(orb.in()));
+
+ for (; iter.next(entry) != 0; iter.advance())
+ {
+ TAO_NOTIFY::NVPList fattrs;
+ CORBA::Long id = entry->ext_id_;
+ CORBA::String_var ior = orb->object_to_string(entry->int_id_.in() ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ fattrs.push_back(TAO_NOTIFY::NVP("IOR", ior.in()));
+ saver.begin_object(id, "filter", fattrs, changed ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ saver.end_object(id, "filter" ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+ }
+
+ saver.end_object(0, "filter_admin" ACE_ENV_ARG_PARAMETER);
+}
+
+TAO_NOTIFY::Topology_Object*
+TAO_Notify_FilterAdmin::load_child (const ACE_CString &type, CORBA::Long id,
+ const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL)
+{
+ if (type == "filter")
+ {
+ TAO_Notify_Properties* properties = TAO_Notify_PROPERTIES::instance();
+ CORBA::ORB_var orb = properties->orb();
+ ACE_ASSERT(! CORBA::is_nil(orb.in()));
+ ACE_CString ior;
+ attrs.load("IOR", ior);
+
+ CORBA::Object_var obj = orb->string_to_object(ior.c_str() ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ CosNotifyFilter::Filter_var filter = CosNotifyFilter::Filter::_unchecked_narrow(obj.in() ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ if (! CORBA::is_nil(filter.in()))
+ {
+ this->filter_ids_.set_last_used(id);
+ if (this->filter_list_.bind (id, filter) != 0)
+ ACE_THROW_RETURN (CORBA::INTERNAL (), 0);
+ }
+ }
+ return this;
+}
+
+void
+TAO_Notify_FilterAdmin::release (void)
+{
+ delete this;
+}
+
+
#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
template class ACE_Hash_Map_Entry<CosNotifyFilter::FilterID,CosNotifyFilter::Filter_var>;
template class ACE_Hash_Map_Manager<CosNotifyFilter::FilterID,CosNotifyFilter::Filter_var,ACE_Null_Mutex>;
diff --git a/TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.h b/TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.h
index 4e40b0b5ac9..04507e52599 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.h
@@ -22,6 +22,7 @@
#include "ID_Factory.h"
#include "Event.h"
#include "notify_serv_export.h"
+#include "Topology_Object.h"
/**
* @class TAO_Notify_FilterAdmin
@@ -30,6 +31,7 @@
*
*/
class TAO_Notify_Serv_Export TAO_Notify_FilterAdmin
+ : public TAO_NOTIFY::Topology_Object
{
public:
@@ -80,6 +82,13 @@ class TAO_Notify_Serv_Export TAO_Notify_FilterAdmin
CORBA::SystemException
));
+
+ // TAO_NOTIFY::Topology_Object
+
+ virtual void save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL);
+ virtual TAO_NOTIFY::Topology_Object* load_child (const ACE_CString &type, CORBA::Long id,
+ const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL);
+ virtual void release (void);
private:
typedef ACE_Hash_Map_Manager <CosNotifyFilter::FilterID, CosNotifyFilter::Filter_var, ACE_SYNCH_NULL_MUTEX> FILTER_LIST;
diff --git a/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.cpp b/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.cpp
index 8e021520caf..b8bec81f68c 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.cpp
@@ -9,6 +9,7 @@
ACE_RCSID(Notify, TAO_Notify_ID_Factory, "$Id$")
TAO_Notify_ID_Factory::TAO_Notify_ID_Factory (void)
+ : seed_ (0)
{
}
diff --git a/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.h b/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.h
index f3f6e3127b0..b9f0bd8aef5 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.h
@@ -41,8 +41,12 @@ public:
TAO_Notify_Object::ID id (void);
+ void set_last_used (const TAO_Notify_Object::ID id);
+
private:
- ACE_Atomic_Op<TAO_SYNCH_MUTEX, TAO_Notify_Object::ID> seed_;
+ // Can't use atomic op, because we added the set_last_used() method.
+ TAO_Notify_Object::ID seed_;
+ TAO_SYNCH_MUTEX mtx_;
};
diff --git a/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.inl b/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.inl
index 74a2d8582d6..f9fb1f5e89b 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.inl
+++ b/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.inl
@@ -3,5 +3,16 @@
ACE_INLINE TAO_Notify_Object::ID
TAO_Notify_ID_Factory::id (void)
{
+ ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, ace_mon, this->mtx_, 0);
return ++seed_;
}
+
+ACE_INLINE void
+TAO_Notify_ID_Factory::set_last_used (const TAO_Notify_Object::ID id)
+{
+ ACE_GUARD (TAO_SYNCH_MUTEX, ace_mon, this->mtx_);
+ if (this->seed_ < id)
+ {
+ this->seed_ = id;
+ }
+}
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.cpp b/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.cpp
new file mode 100644
index 00000000000..95baf13ee69
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.cpp
@@ -0,0 +1,227 @@
+// $Id$
+
+#include "Name_Value_Pair.h"
+
+#if ! defined (__ACE_INLINE__)
+#include "Name_Value_Pair.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "Property_T.h"
+#include "ace/OS_String.h"
+#include "ace/OS_NS_stdio.h"
+
+namespace
+{
+ ACE_UINT64 string_to_uint64(const char * s)
+ {
+ size_t len = ACE_OS::strlen (s);
+ if (len == 0)
+ return 0;
+ if (! isdigit(s[0]))
+ return 0;
+
+ ACE_UINT64 t = 0;
+ for (size_t i = 0; i < len; ++i)
+ {
+ if (isdigit(s[i]) == 0)
+ {
+ break;
+ }
+ t *= 10;
+ t += (s[i] - '0');
+ }
+ return t;
+ }
+}
+
+namespace TAO_NOTIFY
+{
+ NVP::NVP()
+ {
+ }
+
+ NVP::NVP(const TAO_Notify_Property_Short& p)
+ : name(p.name())
+ {
+ char buf[64];
+ ACE_OS::sprintf (buf, "%d", p.value ());
+ value = buf;
+ }
+
+ NVP::NVP(const TAO_Notify_Property_Long& p)
+ : name(p.name())
+ {
+ char buf[64];
+ long temp = ACE_static_cast (long, p.value ());
+ ACE_OS::sprintf (buf, "%ld", temp);
+ value = buf;
+ }
+
+ NVP::NVP(const TAO_Notify_Property_Time& p)
+ : name(p.name())
+ {
+ char buf[128];
+ ACE_UINT64 us = p.value();
+#ifdef ACE_LACKS_LONGLONG_T
+ us.as_string(buf);
+#else
+ ACE_OS::sprintf(buf, ACE_UINT64_FORMAT_SPECIFIER, us);
+#endif /* ACE_LACKS_LONGLONG_T */
+ value = buf;
+ }
+
+ NVP::NVP(const TAO_Notify_Property_Boolean& p)
+ : name(p.name())
+ {
+ value = p.value() ? "true" : "false";
+ }
+
+ NVP::NVP(const char * n, CORBA::Long v)
+ : name(n)
+ {
+ char buf[64];
+ long temp = v;
+ ACE_OS::sprintf (buf, "%ld", temp);
+ value = buf;
+ }
+
+ NVP::NVP(const char * n, const char * v)
+ : name(n), value(v)
+ {
+ }
+
+ NVP::NVP(const char * n, const ACE_CString & v)
+ : name(n), value(v)
+ {
+ }
+
+ bool NVP::operator==(const NVP& rhs) const
+ {
+ return (this->name == rhs.name) != 0;
+ }
+
+ bool NVP::operator!=(const NVP& rhs) const
+ {
+ return ! (rhs == *this);
+ }
+
+ bool NVPList::find (const char * name, ACE_CString& val) const
+ {
+ for (size_t i = 0; i < list_.size(); ++i)
+ {
+ if (list_[i].name == name)
+ {
+ val = list_[i].value;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool NVPList::find (const char * name, const char *& val) const
+ {
+ for (size_t i = 0; i < list_.size(); ++i)
+ {
+ if (list_[i].name == name)
+ {
+ val = list_[i].value.c_str ();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void NVPList::load(TAO_Notify_Property_Short& p) const
+ {
+ const char * v;
+ if (find(p.name(), v))
+ {
+ p.assign (static_cast<CORBA::Short> (ACE_OS::atoi(v)));
+ }
+ }
+
+ void NVPList::load(TAO_Notify_Property_Long& p) const
+ {
+ const char * v;
+ if (find(p.name(), v))
+ {
+ p.assign (static_cast<CORBA::Long> (ACE_OS::atoi(v)));
+ }
+ }
+
+ void NVPList::load(TAO_Notify_Property_Time& p) const
+ {
+ const char * v;
+ if (find(p.name (), v))
+ {
+ p.assign (ACE_static_cast(TimeBase::TimeT, string_to_uint64(v)));
+ }
+ }
+
+ void NVPList::load(TAO_Notify_Property_Boolean& p) const
+ {
+ ACE_CString v;
+ if (find(p.name (), v))
+ {
+ if (v == "true")
+ {
+ p = 1;
+ }
+ else
+ {
+ p = 0;
+ }
+ }
+ }
+
+ bool NVPList::load(const char * n, CORBA::Long& v) const
+ {
+ const char * val;
+ if (find(n, val))
+ {
+ v = ACE_static_cast(CORBA::Long, ACE_OS::atoi(val));
+ return true;
+ }
+ return false;
+ }
+
+ bool NVPList::load(const char * n, ACE_CString& v) const
+ {
+ return find(n, v);
+ }
+
+ void NVPList::push_back(const NVP& v)
+ {
+ for (size_t i = 0; i < list_.size(); ++i)
+ {
+ if (list_[i].name == v.name)
+ {
+ list_[i].value = v.value;
+ return;
+ }
+ }
+ list_.push_back(v);
+ }
+
+ size_t NVPList::size() const
+ {
+ return list_.size();
+ }
+
+ const NVP& NVPList::operator[](size_t ndx) const
+ {
+ ACE_ASSERT(ndx < list_.size());
+ return list_[ndx];
+ }
+
+} // namespace TAO_NOTIFY
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Array_Base<TAO_NOTIFY::NVP>;
+template class ACE_Array<TAO_NOTIFY::NVP>;
+template class ACE_Vector<TAO_NOTIFY::NVP>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Array_Base<TAO_NOTIFY::NVP>
+#pragma instantiate ACE_Array<TAO_NOTIFY::NVP>
+#pragma instantiate ACE_Vector<TAO_NOTIFY::NVP>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.h b/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.h
new file mode 100644
index 00000000000..59ee9b41b18
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.h
@@ -0,0 +1,102 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+* @file Name_Value_Pair.h
+*
+* $Id$
+*
+* @author Jonathan Pollack <pollack_j@ociweb.com>
+*/
+//=============================================================================
+
+#ifndef NAME_VALUE_PAIR_H
+#define NAME_VALUE_PAIR_H
+#include /**/ "ace/pre.h"
+
+#include "Property.h"
+#include "Property_Boolean.h"
+#include "notify_export.h"
+
+#include "ace/SString.h"
+#include "ace/Vector_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+namespace TAO_NOTIFY
+{
+ /**
+ * \brief Name/Value Pair
+ *
+ * Associates a name (character string) with a value (encoded into a character string)
+ * For use in managing properties.
+ */
+ class TAO_Notify_Serv_Export NVP {
+ public:
+ /// Construct an undefined name/value (to allow use in collections)
+ NVP();
+ /// Construct from a property containing a short value.
+ explicit NVP(const TAO_Notify_Property_Short& p);
+ /// Construct from a property containing a long value.
+ explicit NVP(const TAO_Notify_Property_Long& p);
+ /// Construct from a property containing a time value
+ explicit NVP(const TAO_Notify_Property_Time& p);
+ /// Construct from a property containing a boolean value
+ explicit NVP(const TAO_Notify_Property_Boolean& p);
+
+ /// Construct from name and long value.
+ NVP(const char * n, CORBA::Long v);
+ /// Construct from name and string value.
+ NVP(const char * n, const char * v);
+ /// Construct from name and string value.
+ NVP(const char * n, const ACE_CString & v);
+
+ /// Assignment operator
+ bool operator==(const NVP& rhs) const;
+ /// Comparison operator compares only name (not value)
+ bool operator!=(const NVP& rhs) const;
+ ACE_CString name;
+ ACE_CString value;
+ };
+
+ /**
+ * \brief Collection of Name/Value Pairs
+ */
+ class TAO_Notify_Serv_Export NVPList {
+ public:
+ /// Find the NVP with the same name as the property, copy the value.
+ void load(TAO_Notify_Property_Short& p) const;
+ /// Find the NVP with the same name as the property, copy the value.
+ void load(TAO_Notify_Property_Long& p) const;
+ /// Find the NVP with the same name as the property, copy the value.
+ void load(TAO_Notify_Property_Time& p) const;
+ /// Find the NVP with the same name as the property, copy the value.
+ void load(TAO_Notify_Property_Boolean& p) const;
+ /// Find the NVP with specified name, copy the value to a string.
+ bool load(const char * n, CORBA::Long& v) const;
+ /// Find the NVP with specified name, copy the value to a long.
+ bool load(const char * n, ACE_CString& v) const;
+ /// add a new name/value pair.
+ void push_back(const NVP& v);
+ /// size of the collection.
+ size_t size() const;
+ /// access NVP via numeric index.
+ const NVP& operator[](size_t ndx) const;
+ /// low level access: find
+ bool find (const char * name, ACE_CString& val) const;
+ /// low level access: use this when you don't need a CString
+ bool find (const char * name, const char *& val) const;
+
+ private:
+ ACE_Vector<NVP> list_;
+ };
+} // namespace TAO_NOTIFY
+
+#if defined (__ACE_INLINE__)
+#include "Name_Value_Pair.inl"
+#endif /* __ACE_INLINE__ */
+
+#include /**/ "ace/post.h"
+#endif /* NAME_VALUE_PAIR_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.inl b/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.inl
new file mode 100644
index 00000000000..cfa1da318d3
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.inl
@@ -0,0 +1 @@
+// $Id$
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Object.cpp b/TAO/orbsvcs/orbsvcs/Notify/Object.cpp
index 49c9b9b07a1..6ad873f70ab 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Object.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/Object.cpp
@@ -15,6 +15,8 @@
ACE_RCSID(Notify, TAO_Notify_Object, "$Id$")
+
+
TAO_Notify_Object::TAO_Notify_Object (void)
: event_manager_ (0)
, admin_properties_ (0)
@@ -66,6 +68,18 @@ TAO_Notify_Object::activate (PortableServer::Servant servant ACE_ENV_ARG_DECL)
return this->poa_->activate (servant, this->id_ ACE_ENV_ARG_PARAMETER);
}
+/// Activate with existing id
+CORBA::Object_ptr
+TAO_Notify_Object::activate (
+ PortableServer::Servant servant,
+ CORBA::Long id
+ ACE_ENV_ARG_DECL)
+{
+ this->id_ = id;
+ return this->poa_->activate_with_id (servant, this->id_ ACE_ENV_ARG_PARAMETER);
+}
+
+
void
TAO_Notify_Object::deactivate (ACE_ENV_SINGLE_ARG_DECL)
{
@@ -77,10 +91,10 @@ TAO_Notify_Object::deactivate (ACE_ENV_SINGLE_ARG_DECL)
ACE_CATCHANY
{
if (TAO_debug_level > 2)
- {
- ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, "(%P|%t)\n");
- ACE_DEBUG ((LM_DEBUG, "Could not deactivate object %d\n", this->id_));
- }
+ {
+ ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, "(%P|%t)\n");
+ ACE_DEBUG ((LM_DEBUG, "Could not deactivate object %d\n", this->id_));
+ }
// Do not propagate any exceptions
}
ACE_ENDTRY;
@@ -133,7 +147,7 @@ TAO_Notify_Object::shutdown_proxy_poa (void)
{
this->proxy_poa_->destroy (ACE_ENV_SINGLE_ARG_PARAMETER);
ACE_TRY_CHECK;
-
+
delete this->proxy_poa_;
}
ACE_CATCHANY
@@ -268,6 +282,15 @@ TAO_Notify_Object::get_qos (ACE_ENV_SINGLE_ARG_DECL)
return properties._retn ();
}
+bool
+TAO_Notify_Object::find_qos_property_value (
+ const char * name,
+ CosNotification::PropertyValue & value) const
+{
+ return this->qos_properties_.find (name, value);
+}
+
+
void
TAO_Notify_Object::qos_changed (const TAO_Notify_QoSProperties& /*qos_properties*/)
{
@@ -279,3 +302,60 @@ TAO_Notify_Object::timer (void)
{
return this->worker_task_->timer ();
}
+
+namespace {
+ template<class T>
+ void add_qos_attr(TAO_NOTIFY::NVPList& attrs, const T& prop) {
+ if (prop.is_valid())
+ {
+ attrs.push_back(TAO_NOTIFY::NVP (prop));
+ }
+ }
+// Note : These instantiations have to be here because each namespace {}
+// is unique.
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template void add_qos_attr<TAO_Notify_Property_Boolean>(
+ TAO_NOTIFY::NVPList&, const TAO_Notify_Property_Boolean&);
+template void add_qos_attr<TAO_Notify_Property_T<int> >(
+ TAO_NOTIFY::NVPList&, const TAO_Notify_Property_T<int>&);
+template void add_qos_attr<TAO_Notify_Property_T<unsigned long long> >(
+ TAO_NOTIFY::NVPList&, const TAO_Notify_Property_T<unsigned long long>&);
+template void add_qos_attr<TAO_Notify_Property_T<short> >(
+ TAO_NOTIFY::NVPList&, const TAO_Notify_Property_T<short>&);
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate void add_qos_attr<TAO_Notify_Property_Boolean>(\
+ TAO_NOTIFY::NVPList&, const TAO_Notify_Property_Boolean&)
+#pragma instantiate void add_qos_attr<TAO_Notify_Property_T<int> >(\
+ TAO_NOTIFY::NVPList&, const TAO_Notify_Property_T<int>&)
+#pragma instantiate void add_qos_attr<TAO_Notify_Property_T<unsigned long long> >(\
+ TAO_NOTIFY::NVPList&, const TAO_Notify_Property_T<unsigned long long>&)
+#pragma instantiate void add_qos_attr<TAO_Notify_Property_T<short> >(\
+ TAO_NOTIFY::NVPList&, const TAO_Notify_Property_T<short>&)
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+} // namespace
+
+void
+TAO_Notify_Object::save_attrs (TAO_NOTIFY::NVPList& attrs)
+{
+ add_qos_attr(attrs, this->qos_properties_.event_reliability ());
+ add_qos_attr(attrs, this->qos_properties_.connection_reliability ());
+ add_qos_attr(attrs, this->qos_properties_.priority ());
+ add_qos_attr(attrs, this->qos_properties_.timeout ());
+ add_qos_attr(attrs, this->qos_properties_.stop_time_supported ());
+ add_qos_attr(attrs, this->qos_properties_.maximum_batch_size ());
+ add_qos_attr(attrs, this->qos_properties_.pacing_interval ());
+}
+
+void
+TAO_Notify_Object::load_attrs(const TAO_NOTIFY::NVPList& attrs)
+{
+ attrs.load (this->qos_properties_.event_reliability ());
+ attrs.load (this->qos_properties_.connection_reliability ());
+ attrs.load (this->qos_properties_.priority ());
+ attrs.load (this->qos_properties_.timeout ());
+ attrs.load (this->qos_properties_.stop_time_supported ());
+ attrs.load (this->qos_properties_.maximum_batch_size ());
+ attrs.load (this->qos_properties_.pacing_interval ());
+ this->qos_properties_.init ();
+}
+
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Object.h b/TAO/orbsvcs/orbsvcs/Notify/Object.h
index cf1f1044fac..7c95ea99c07 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Object.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/Object.h
@@ -27,6 +27,7 @@
#include "QoSProperties.h"
#include "AdminProperties.h"
#include "Refcountable.h"
+#include "Name_Value_Pair.h"
class TAO_Notify_POA_Helper;
class TAO_Notify_Worker_Task;
@@ -54,11 +55,17 @@ public:
virtual ~TAO_Notify_Object (void);
/// This Object's ID
- ID id (void);
+ ID id (void) const;
/// Activate
virtual CORBA::Object_ptr activate (PortableServer::Servant servant ACE_ENV_ARG_DECL);
+ /// Activate with existing id
+ virtual CORBA::Object_ptr activate (
+ PortableServer::Servant servant,
+ CORBA::Long id
+ ACE_ENV_ARG_DECL);
+
/// Deactivate
void deactivate (ACE_ENV_SINGLE_ARG_DECL);
@@ -98,6 +105,10 @@ public:
/// Get the QoS Properties.
CosNotification::QoSProperties* get_qos (ACE_ENV_SINGLE_ARG_DECL);
+ bool find_qos_property_value (
+ const char * name,
+ CosNotification::PropertyValue & value)const;
+
/// Obtain the Timer manager associated with this object.
virtual TAO_Notify_Timer* timer (void);
@@ -107,6 +118,10 @@ public:
/// Accessor for the Event Manager
TAO_Notify_Event_Manager* event_manager (void);
+ /// Load our attributes. Each derived type should call the superclass
+ /// load first before loading its own attributes.
+ virtual void load_attrs(const TAO_NOTIFY::NVPList& attrs);
+
protected:
/// Init this object with data from <rhs>.
void init (TAO_Notify_Object* parent);
@@ -123,6 +138,11 @@ protected:
/// Notification that can be overridden by subclasses to be informed that <qos_properties_> have been modified.
virtual void qos_changed (const TAO_Notify_QoSProperties& qos_properties);
+ /// Called by derived types to save their attributes. Each
+ /// derived type should call its superclass version before
+ /// saving its own attrs.
+ virtual void save_attrs(TAO_NOTIFY::NVPList& attrs);
+
///= Protected data members.
/// The event manager.
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Object.inl b/TAO/orbsvcs/orbsvcs/Notify/Object.inl
index 9ba8797906a..3a20131bbec 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Object.inl
+++ b/TAO/orbsvcs/orbsvcs/Notify/Object.inl
@@ -1,7 +1,7 @@
// $Id$
ACE_INLINE CORBA::Long
-TAO_Notify_Object::id (void)
+TAO_Notify_Object::id (void) const
{
return id_;
}
diff --git a/TAO/orbsvcs/orbsvcs/Notify/POA_Helper.cpp b/TAO/orbsvcs/orbsvcs/Notify/POA_Helper.cpp
index fd0182a8dfc..95817d46083 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/POA_Helper.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/POA_Helper.cpp
@@ -148,6 +148,26 @@ TAO_Notify_POA_Helper::activate (PortableServer::Servant servant, CORBA::Long& i
ACE_ENV_ARG_PARAMETER);
}
+CORBA::Object_ptr
+TAO_Notify_POA_Helper::activate_with_id (PortableServer::Servant servant, CORBA::Long id ACE_ENV_ARG_DECL)
+{
+ if (TAO_debug_level > 0)
+ ACE_DEBUG ((LM_DEBUG, "Activating object with existing id = %d in POA : %s\n", id, this->poa_->the_name ()));
+
+ // Convert CORBA::Long to ObjectId
+ PortableServer::ObjectId_var oid =
+ this->long_to_ObjectId (id ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (CORBA::Object::_nil ());
+
+ poa_->activate_object_with_id (oid.in (),
+ servant
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (CORBA::Object::_nil ());
+
+ return poa_->id_to_reference (oid.in ()
+ ACE_ENV_ARG_PARAMETER);
+}
+
void
TAO_Notify_POA_Helper::deactivate (CORBA::Long id ACE_ENV_ARG_DECL) const
{
@@ -171,6 +191,20 @@ TAO_Notify_POA_Helper::id_to_reference (CORBA::Long id ACE_ENV_ARG_DECL) const
ACE_ENV_ARG_PARAMETER);
}
+PortableServer::ServantBase *
+TAO_Notify_POA_Helper::reference_to_servant (CORBA::Object_ptr ptr ACE_ENV_ARG_DECL) const
+{
+ return poa_->reference_to_servant (ptr ACE_ENV_ARG_PARAMETER);
+}
+
+CORBA::Object_ptr
+TAO_Notify_POA_Helper::servant_to_reference (
+ PortableServer::ServantBase * servant ACE_ENV_ARG_DECL) const
+{
+ return poa_->servant_to_reference (servant ACE_ENV_ARG_PARAMETER);
+}
+
+
void
TAO_Notify_POA_Helper::destroy (ACE_ENV_SINGLE_ARG_DECL)
{
diff --git a/TAO/orbsvcs/orbsvcs/Notify/POA_Helper.h b/TAO/orbsvcs/orbsvcs/Notify/POA_Helper.h
index 831b0dc163d..bd3e0ed6a38 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/POA_Helper.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/POA_Helper.h
@@ -54,12 +54,20 @@ public:
/// Activate Object, the POA will assign an ID and return its value.
CORBA::Object_ptr activate (PortableServer::Servant servant, CORBA::Long& id ACE_ENV_ARG_DECL);
+ /// Activate Object, using existing ID
+ CORBA::Object_ptr activate_with_id (PortableServer::Servant servant, CORBA::Long id ACE_ENV_ARG_DECL);
+
/// Deactivate Object with ID
void deactivate (CORBA::Long id ACE_ENV_ARG_DECL) const;
/// Convert ID to reference.
CORBA::Object_ptr id_to_reference (CORBA::Long id ACE_ENV_ARG_DECL) const;
+ /// Convert reference to pointer to servant
+ PortableServer::ServantBase * reference_to_servant (CORBA::Object_ptr ptr ACE_ENV_ARG_DECL) const;
+
+ CORBA::Object_ptr servant_to_reference (PortableServer::ServantBase * servant ACE_ENV_ARG_DECL) const;
+
protected:
/// Set default POA policies.
virtual void set_policy (PortableServer::POA_ptr parent_poa, CORBA::PolicyList &policy_list ACE_ENV_ARG_DECL);
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Peer.h b/TAO/orbsvcs/orbsvcs/Notify/Peer.h
index deaf6fc66ea..5778281bc71 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Peer.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/Peer.h
@@ -66,6 +66,9 @@ public:
/// Handle dispatch exceptions.
void handle_dispatch_exception (ACE_ENV_SINGLE_ARG_DECL);
+ /// Retrieve the ior of this peer
+ virtual bool get_ior (ACE_CString & iorstr) const = 0;
+
protected:
/// Implementation of Peer specific dispatch_updates
virtual void dispatch_updates_i (const CosNotification::EventTypeSeq& added,
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Persistent_File.cpp b/TAO/orbsvcs/orbsvcs/Notify/Persistent_File.cpp
new file mode 100644
index 00000000000..e133e60c671
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Persistent_File.cpp
@@ -0,0 +1,158 @@
+// $Id$
+
+#include "Persistent_File.h"
+
+#include "ace/OS.h"
+#include <tao/debug.h>
+//#define DEBUG_LEVEL 9 // uncomment to force debug messages
+#define DEBUG_LEVEL TAO_debug_level // coment to force debug messages
+
+namespace TAO_NOTIFY
+{
+
+Persistent_File::Persistent_File()
+ : block_size_(512)
+{
+}
+
+Persistent_File::~Persistent_File()
+{
+ this->close();
+}
+
+size_t
+Persistent_File::block_size() const
+{
+ return this->block_size_;
+}
+
+size_t
+Persistent_File::size() const
+{
+ Persistent_File * mutable_this = ACE_const_cast (Persistent_File *, this);
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, mutable_this->lock_, 0);
+ size_t original_pos = mutable_this->tell ();
+ mutable_this->ACE_FILE::seek(0, SEEK_END);
+ size_t cursize = mutable_this->tell();
+ mutable_this->ACE_FILE::seek (original_pos, SEEK_SET);
+ if ((cursize % this->block_size_) != 0)
+ {
+ cursize += this->block_size_;
+ }
+ return cursize / this->block_size_;
+}
+
+bool
+Persistent_File::open(const char* filename, size_t block_size)
+{
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->lock_, false);
+ this->block_size_ = block_size;
+ bool result = (this->close() == 0);
+
+ if (result)
+ {
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Opening file %s\n")
+ , filename
+ ));
+ ACE_HANDLE handle = ACE_OS::open(filename,
+ O_CREAT | O_RDWR | O_BINARY,
+ ACE_DEFAULT_FILE_PERMS);
+
+ if (handle == ACE_INVALID_HANDLE)
+ {
+ result = false;
+ }
+ else
+ {
+ this->set_handle(handle);
+ if (this->get_handle() == 0)
+ {
+ result = false;
+ }
+ else
+ {
+ result = (this->addr_.set(filename) == 0);
+ }
+ }
+ }
+ return result;
+}
+
+bool
+Persistent_File::write(const size_t block_number, void* buf, bool atomic)
+{
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->lock_, false);
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Write block %d %c\n"),
+ ACE_static_cast (int, block_number),
+ (atomic ? '*' : ' ')
+ ));
+ bool result = this->seek(block_number);
+ if (result)
+ {
+ if (atomic)
+ {
+ // sync before so that any block pointed to from this block
+ // will be there when this block is written.
+ result = sync();
+ }
+ // ACE uses an ssize_t for buffer size, so we do this to make it happy.
+ ssize_t block_size = this->block_size_;
+ if (result && (block_size !=
+ ACE_OS::write(this->get_handle(), buf, block_size)))
+ {
+ result = false;
+ }
+ if (result && atomic)
+ {
+ // sync after to provide the caller with a guarantee that
+ // this block is physically written to the storage device.
+ result = sync();
+ }
+ }
+ return result;
+}
+
+bool
+Persistent_File::read(const size_t block_number, void* buf)
+{
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->lock_, false);
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Read block %d\n"),
+ ACE_static_cast (int, block_number)
+ ));
+ bool result = this->seek(block_number);
+ if (result)
+ {
+ ssize_t block_size = this->block_size_;
+ if (block_size !=
+ ACE_OS::read(this->get_handle(), buf, block_size))
+ {
+ result = false;
+ }
+ }
+ return result;
+}
+
+bool
+Persistent_File::seek(const size_t block_number)
+{
+ ssize_t destloc = block_number * this->block_size_;
+ bool result = (destloc == this->ACE_FILE::seek(destloc, SEEK_SET));
+ return result;
+}
+
+bool
+Persistent_File::sync()
+{
+ bool result = false;
+ result = (0 == ACE_OS::fsync(this->get_handle()));
+ return result;
+}
+
+} /* namespace TAO_NOTIFY */
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Persistent_File.h b/TAO/orbsvcs/orbsvcs/Notify/Persistent_File.h
new file mode 100644
index 00000000000..f04ce0108ab
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Persistent_File.h
@@ -0,0 +1,89 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Persistent_File.h
+ *
+ * $Id$
+ *
+ * This class implements a a random-access file containing
+ * fixed-size blocks.
+ *
+ * @author Jonathan Pollack <pollack_j@ociweb.com>
+ */
+//=============================================================================
+
+#ifndef PERSISTENT_FILE_H
+#define PERSISTENT_FILE_H
+#include /**/ "ace/pre.h"
+#include /**/ "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "notify_export.h"
+#include "ace/FILE.h"
+#include "ace/streams.h"
+#include "ace/Synch_T.h"
+
+namespace TAO_NOTIFY
+{
+
+/**
+ * \brief A persistent file class.
+ *
+ * Derived from ACE_FILE, this class provides access to a
+ * file of fixed-size blocks.
+ *
+ */
+class TAO_Notify_Export Persistent_File : public ACE_FILE
+{
+public:
+ /// The constructor.
+ Persistent_File();
+
+ /// The destructor, which closes the open file.
+ ~Persistent_File();
+
+ /// Open a file with default permissions.
+ bool open(const char* filename, size_t block_size = 512);
+
+ /// Accessor for the block size.
+ /// Note signed size_t is used to be compatible with
+ /// ACE_FILE.
+ size_t block_size() const;
+
+ /// Return the current file size, in number of blocks.
+ size_t size() const;
+
+ /// Write a block to our file, potentially as an "atomic" write.
+ /// If the atomic argument is true, then the operating system's
+ /// write-through cache for this file is flushed both before and
+ /// after the write.
+ /// The flush before ensures that any record pointers in this block
+ /// will point to records that actually appear in the file.
+ /// The flush after provides the caller with a guarantee that
+ /// the data will appear in the file even if the system fails
+ /// immediately after this method returns.
+ bool write(const size_t block_number, void* buffer, bool atomic = false);
+
+ /// Read a block from our file.
+ bool read(const size_t block_number, void* buffer);
+
+private:
+ /// Seek to a given block number, used by reads and writes.
+ bool seek(const size_t block_number);
+
+ /// Synchronize the file to disk, used to implement atomic.
+ bool sync();
+
+private:
+ size_t block_size_;
+ ACE_SYNCH_MUTEX lock_;
+};
+
+} /* namespace TAO_NOTIFY */
+
+#include /**/ "ace/post.h"
+#endif /* PERSISTENT_FILE_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.cpp b/TAO/orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.cpp
new file mode 100644
index 00000000000..d5206fd5042
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.cpp
@@ -0,0 +1,401 @@
+// $Id$
+
+#include "Persistent_File_Allocator.h"
+
+#include <tao/debug.h>
+#include "ace/OS_NS_string.h"
+
+//#define DEBUG_LEVEL 9
+#define DEBUG_LEVEL TAO_debug_level
+
+namespace TAO_NOTIFY
+{
+
+Persistent_Storage_Block::Persistent_Storage_Block(const size_t block_number,
+ const size_t block_size)
+ : block_number_(block_number)
+ , no_write_(false)
+ , sync_(false)
+ , block_size_(block_size)
+ , callback_(0)
+ , allocator_owns_(true)
+{
+ ACE_NEW(this->data_, unsigned char[this->block_size_]);
+ ACE_OS::memset(this->data_, 0, this->block_size_);
+
+}
+
+Persistent_Storage_Block::Persistent_Storage_Block(
+ const Persistent_Storage_Block& psb)
+ : block_number_(psb.block_number_)
+ , no_write_(psb.no_write_)
+ , sync_(psb.sync_)
+ , block_size_(psb.block_size_)
+ , callback_(psb.callback_)
+ , allocator_owns_(psb.allocator_owns_)
+{
+ ACE_NEW(this->data_, unsigned char[this->block_size_]);
+ ACE_OS::memcpy(this->data_, psb.data(), this->block_size_);
+}
+
+Persistent_Storage_Block::~Persistent_Storage_Block()
+{
+ delete [] this->data_;
+ this->data_ = 0;
+}
+
+void
+Persistent_Storage_Block::set_no_write()
+{
+ this->no_write_ = true;
+ this->reassign_data(0, true);
+}
+
+bool
+Persistent_Storage_Block::get_no_write()
+{
+ return this->no_write_;
+}
+
+void
+Persistent_Storage_Block::set_sync()
+{
+ this->sync_ = true;
+}
+
+bool
+Persistent_Storage_Block::get_sync() const
+{
+ return this->sync_;
+}
+
+size_t
+Persistent_Storage_Block::block_number() const
+{
+ return this->block_number_;
+}
+
+unsigned char*
+Persistent_Storage_Block::data() const
+{
+ return this->data_;
+}
+
+void
+Persistent_Storage_Block::reassign_data(unsigned char* newptr,
+ bool delete_old)
+{
+ if (delete_old)
+ {
+ delete [] this->data_;
+ }
+ this->data_ = newptr;
+}
+
+void
+Persistent_Storage_Block::set_callback(Persistent_Callback* callback)
+{
+ this->callback_ = callback;
+}
+
+Persistent_Callback*
+Persistent_Storage_Block::get_callback() const
+{
+ return this->callback_;
+}
+
+void
+Persistent_Storage_Block::set_allocator_owns(bool allocator_owns)
+{
+ this->allocator_owns_ = allocator_owns;
+}
+
+bool
+Persistent_Storage_Block::get_allocator_owns() const
+{
+ return this->allocator_owns_;
+}
+
+Persistent_File_Allocator::Persistent_File_Allocator()
+ : pstore_()
+ , terminate_thread_(false)
+ , thread_active_(false)
+ , wake_up_thread_(queue_lock_)
+{
+}
+
+Persistent_File_Allocator::~Persistent_File_Allocator()
+{
+ this->shutdown_thread();
+}
+
+bool
+Persistent_File_Allocator::open (const char* filename,
+ const size_t block_size)
+{
+ bool file_opened = this->pstore_.open(filename, block_size);
+ if (file_opened)
+ {
+ this->thread_active_ = true;
+ this->thread_manager_.spawn(this->thr_func, this);
+ }
+ return file_opened;
+}
+
+void
+Persistent_File_Allocator::shutdown()
+{
+ this->shutdown_thread();
+}
+
+Persistent_Storage_Block*
+Persistent_File_Allocator::allocate()
+{
+ Persistent_Storage_Block* result = 0;
+ size_t block_number = 0;
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->lock_, 0);
+ if (!this->allocate_block(block_number))
+ {
+ //@@todo: this should never happen
+ // why not. What if the disk is full? Oh, I see we
+ // allocate non-existent blocks. FIX this
+ }
+ if (DEBUG_LEVEL > 0) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Persistent_File_Allocator::allocate: %d\n"),
+ ACE_static_cast (int, block_number)
+ ));
+ result = this->allocate_at(block_number);
+ return result;
+}
+
+Persistent_Storage_Block*
+Persistent_File_Allocator::allocate_at(size_t block_number)
+{
+ Persistent_Storage_Block* result = 0;
+ this->used(block_number);
+ if (DEBUG_LEVEL > 0) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Persistent_File_Allocator::allocate at : %d\n"),
+ ACE_static_cast (int, block_number)
+ ));
+ ACE_NEW_RETURN(result, Persistent_Storage_Block(
+ block_number,
+ this->block_size()),
+ 0);
+ return result;
+}
+
+Persistent_Storage_Block*
+Persistent_File_Allocator::allocate_nowrite()
+{
+ Persistent_Storage_Block* result = 0;
+ ACE_NEW_RETURN(result, Persistent_Storage_Block(~0, 0), 0);
+ result->set_no_write();
+ return result;
+}
+
+void
+Persistent_File_Allocator::used(size_t block_number)
+{
+ ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->free_blocks_lock_);
+ if (DEBUG_LEVEL > 0) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Persistent_File_Allocator::used: %d\n"),
+ ACE_static_cast (int, block_number)
+ ));
+ ACE_ASSERT (!this->free_blocks_.is_set (block_number));
+ this->free_blocks_.set_bit(block_number, true);
+}
+
+void
+Persistent_File_Allocator::free(size_t block_number)
+{
+ if (DEBUG_LEVEL > 0) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Persistent_File_Allocator::free: %d\n"),
+ ACE_static_cast (int, block_number)
+ ));
+ ACE_ASSERT (this->free_blocks_.is_set (block_number));
+ this->free_block(block_number);
+}
+
+size_t
+Persistent_File_Allocator::block_size() const
+{
+ return pstore_.block_size();
+}
+
+bool
+Persistent_File_Allocator::read(Persistent_Storage_Block* psb)
+{
+ bool result = this->thread_active_;
+ bool cached = false;
+ if (result)
+ {
+ Persistent_Storage_Block** psbtemp = 0;
+ {
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->queue_lock_, false);
+ size_t queue_size = this->block_queue_.size();
+ for (size_t idx = 0; !cached && (idx < queue_size); ++idx)
+ {
+ // We want to start at the end of the queue and work backwards...
+ size_t actual_block = (queue_size - idx) - 1;
+ if (0 == this->block_queue_.get(psbtemp, actual_block))
+ {
+ cached = ((*psbtemp)->block_number() == psb->block_number());
+ }
+ }
+ // this needs to be done in the guarded section
+ if (cached && (0 != psbtemp))
+ {
+ ACE_OS::memcpy(psb->data(), (*psbtemp)->data(), this->block_size());
+ }
+ }
+ if (!cached)
+ {
+ result = pstore_.read(psb->block_number(), psb->data());
+ }
+ }
+ return result;
+}
+
+bool
+Persistent_File_Allocator::write(Persistent_Storage_Block* psb)
+{
+ bool result = this->thread_active_;
+ if (result)
+ {
+ Persistent_Storage_Block* ourpsb = psb;
+ if (!psb->get_allocator_owns())
+ {
+ if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Copy PSB %d\n")
+ , ACE_static_cast (int, psb->block_number ())
+ ));
+ ACE_NEW_RETURN(ourpsb, Persistent_Storage_Block(*psb), false);
+ ourpsb->set_allocator_owns(true);
+ }
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->queue_lock_, false);
+ if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Queueing PSB to write block %d\n")
+ , ACE_static_cast (int, psb->block_number ())
+ ));
+ result = (0 == this->block_queue_.enqueue_tail(ourpsb));
+ this->wake_up_thread_.signal();
+ }
+ return result;
+}
+
+void
+Persistent_File_Allocator::free_block(const size_t block_number)
+{
+ ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->free_blocks_lock_);
+ ACE_ASSERT (this->free_blocks_.is_set (block_number));
+ this->free_blocks_.set_bit(block_number, false);
+}
+
+bool
+Persistent_File_Allocator::allocate_block(size_t& block_number)
+{
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->free_blocks_lock_, 0);
+ block_number = this->free_blocks_.find_first_bit(false);
+ return true;
+}
+
+ACE_THR_FUNC_RETURN
+Persistent_File_Allocator::thr_func(void * arg)
+{
+ Persistent_File_Allocator* pfa = ACE_static_cast (Persistent_File_Allocator*,
+ arg);
+ pfa->run();
+ return 0;
+}
+
+size_t
+Persistent_File_Allocator::file_size () const
+{
+ return this->pstore_.size ();
+}
+
+void
+Persistent_File_Allocator::shutdown_thread()
+{
+ if (this->thread_active_)
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->queue_lock_);
+ this->terminate_thread_ = true;
+ this->wake_up_thread_.signal();
+ ace_mon.release();
+ this->thread_manager_.close();
+ ACE_ASSERT (!this->terminate_thread_);
+ ACE_ASSERT (!this->thread_active_);
+ }
+}
+
+void
+Persistent_File_Allocator::run()
+{
+ // We need this because we could be working on writing data
+ // when a call to terminate comes in!
+ bool do_more_work = true;
+ while (do_more_work)
+ {
+ do_more_work = false;
+ Persistent_Storage_Block * blk = 0;
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->queue_lock_);
+ while (this->block_queue_.is_empty() && !terminate_thread_)
+ {
+ this->wake_up_thread_.wait();
+ }
+ // Awkward interface to peek at head of unbounded queue
+ Persistent_Storage_Block ** pblk = 0;
+ if (0 == this->block_queue_.get(pblk))
+ {
+ do_more_work = true;
+ blk = *pblk;
+ }
+ }
+ if (0 != blk)
+ {
+ Persistent_Callback *callback = blk->get_callback();
+ if (!blk->get_no_write())
+ {
+ pstore_.write(blk->block_number(), blk->data(), blk->get_sync());
+ }
+ {
+ Persistent_Storage_Block * blk2 = 0;
+ ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->queue_lock_);
+ this->block_queue_.dequeue_head (blk2);
+ // if this triggers, someone pushed onto the head of the queue
+ // or removed the head from the queue without telling ME.
+ ACE_ASSERT (blk2 == blk);
+ }
+ // If we own the block, then delete it.
+ if (blk->get_allocator_owns())
+ {
+ delete blk;
+ blk = 0;
+ }
+ if (0 != callback)
+ {
+ callback->persist_complete();
+ }
+ }
+ }
+ this->terminate_thread_ = false;
+ this->thread_active_ = false;
+}
+
+} /* namespace TAO_NOTIFY */
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Node<size_t>;
+template class ACE_Unbounded_Stack<size_t>;
+template class ACE_Node<TAO_NOTIFY::Persistent_Storage_Block*>;
+template class ACE_Unbounded_Queue<TAO_NOTIFY::Persistent_Storage_Block*>;
+template class ACE_Unbounded_Queue_Iterator<TAO_NOTIFY::Persistent_Storage_Block*>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Node<size_t>
+#pragma instantiate ACE_Unbounded_Stack<size_t>
+#pragma instantiate ACE_Node<TAO_NOTIFY::Persistent_Storage_Block*>
+#pragma instantiate ACE_Unbounded_Queue<TAO_NOTIFY::Persistent_Storage_Block*>
+#pragma instantiate ACE_Unbounded_Queue_Iterator<TAO_NOTIFY::Persistent_Storage_Block*>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.h b/TAO/orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.h
new file mode 100644
index 00000000000..28c461643ed
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.h
@@ -0,0 +1,203 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Persistent_File_Allocator.h
+ *
+ * $Id$
+ *
+ * A Persistent_File_Allocator manages a free list and allocates and
+ * deallocates blocks from a Persistent_File. There should be only one
+ * Persistent_File_Allocator for each Persistent_File.
+ *
+ * @author Jonathan Pollack <pollack_j@ociweb.com>
+ */
+//=============================================================================
+
+#ifndef PERSISTENT_FILE_ALLOCATOR_H
+#define PERSISTENT_FILE_ALLOCATOR_H
+#include /**/ "ace/pre.h"
+#include /**/ "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "notify_export.h"
+#include "Persistent_File.h"
+#include "Bit_Vector.h"
+#include "ace/Containers_T.h"
+#include "ace/Unbounded_Queue.h"
+#include "ace/Thread_Manager.h"
+
+namespace TAO_NOTIFY
+{
+
+
+/// \brief An interface to allow callbacks on completion of persistent storage
+/// requests.
+class TAO_Notify_Export Persistent_Callback
+{
+public:
+ /// \brief Called by a Persistent_File_Allocator when a write request has
+ /// completed.
+ virtual void persist_complete() = 0;
+};
+
+/**
+ * \brief A class to represent a block on disk.
+ *
+ * Contains the raw data to be written on disk as well as
+ * positioning information, synchronization information, and a pointer
+ * to a callback.
+ */
+class TAO_Notify_Export Persistent_Storage_Block
+{
+public:
+ /// The constructor. Initializes the callback to NULL.
+ Persistent_Storage_Block(
+ const size_t block_number,
+ const size_t block_size);
+ /// The copy constructor. Makes a deep copy of the passed in PSB.
+ Persistent_Storage_Block(const Persistent_Storage_Block& psb);
+ /// The destructor.
+ ~Persistent_Storage_Block();
+
+ /// Set our block to not have any data at all - a no-op. This can be
+ /// used to implement a checkpoint in the write stream.
+ void set_no_write();
+ /// Find out whether we have data to be written.
+ bool get_no_write();
+
+ /// Set our block to be written as a near-atomic operation.
+ void set_sync();
+ /// Find out whether this block should be written near-atomically.
+ bool get_sync() const;
+
+ /// Find out our physical block number.
+ size_t block_number() const;
+
+ /// Return our data to the user.
+ unsigned char* data() const;
+ /// Set our data pointer, and optionally delete it.
+ void reassign_data(unsigned char* newptr, bool delete_old = false);
+
+ /// Return block number and relinquish ownership.
+ size_t detach ();
+
+ /// Set our callback.
+ void set_callback(Persistent_Callback* callback);
+ /// Get our callback.
+ Persistent_Callback* get_callback() const;
+
+ /// Set ownership of this PSB.
+ void set_allocator_owns(bool allocator_owns = true);
+ /// Get ownership status of this PSB.
+ bool get_allocator_owns() const;
+
+private:
+ /// Our raw data.
+ unsigned char* data_;
+ /// The block number corresponding to our data.
+ size_t block_number_;
+ /// Are we a no-op with just a callback?
+ bool no_write_;
+ /// Write in near-atomic fashion.
+ bool sync_;
+ /// The size of our block.
+ size_t block_size_;
+ /// Our optional callback function, to be used in such things as state
+ /// transitions.
+ Persistent_Callback* callback_;
+ /// Does the allocator obtain ownership of our block?
+ bool allocator_owns_;
+};
+
+/**
+ * \brief A class that manages the details of persistent storage.
+ *
+ * Maintains a free list, write queue, allocations of new
+ * blocks, reads, and writes. This class also manages a thread that performs
+ * background updating of a Persistent_File.
+ * @@todo this is too much for one class to do. It should be refactored.
+ */
+class TAO_Notify_Export Persistent_File_Allocator
+{
+public:
+ /// The constructor.
+ Persistent_File_Allocator();
+ /// The destructor.
+ ~Persistent_File_Allocator();
+
+ bool open (const char* filename,
+ const size_t block_size = 512);
+
+ /// \brief Wait for pending I/O and terminate our work thread.
+ void shutdown();
+
+ /// Allocate a new Persistent_Storage_Block and initialize it to an unused
+ /// block of storage.
+ Persistent_Storage_Block* allocate();
+
+ /// \brief Allocate a new Persistent_Storage_Block at a given address
+ Persistent_Storage_Block* allocate_at(size_t block_number);
+
+ /// \brief Allocate a PSB that is marked to not persist
+ Persistent_Storage_Block* allocate_nowrite();
+
+ /// \brief Mark a block as used, removing it from the free list.
+ void used(size_t block_number);
+
+ /// \brief Mark a block number as able to be used again.
+ void free(size_t block_number);
+
+ /// \brief Access block size.
+ size_t block_size() const;
+
+ /// \brief Read data into a PSB.
+ ///
+ /// Data will come either from the queue of blocks to be written, or
+ /// it will be read from the file if there are no queued write requests for
+ /// this block.
+ bool read(Persistent_Storage_Block* psb);
+
+ /// \brief Write this block to the file,
+ ///
+ /// Add the Persistent_Storage_Block to our write queue and let the
+ /// worker thread handle writing this to the Persistent_File.
+ bool write(Persistent_Storage_Block* psb);
+
+ /// for information (unit test) only.
+ size_t file_size () const;
+
+private:
+ /// Free a previously assigned block.
+ void free_block(const size_t block_number);
+ /// Find and allocate a free block.
+ bool allocate_block(size_t& block_number);
+
+ /// Used during thread startup to cast us back to ourselves and call the
+ /// run() method.
+ static ACE_THR_FUNC_RETURN thr_func(void * arg);
+ /// Wait for pending I/O to complete and shut our worker thread down safely.
+ void shutdown_thread();
+ /// The worker's execution thread.
+ void run();
+
+private:
+ ACE_Thread_Manager thread_manager_;
+ Persistent_File pstore_;
+ Bit_Vector free_blocks_;
+ ACE_Unbounded_Queue<Persistent_Storage_Block*> block_queue_;
+ ACE_SYNCH_MUTEX lock_;
+ ACE_SYNCH_MUTEX free_blocks_lock_;
+ ACE_SYNCH_MUTEX queue_lock_;
+ bool terminate_thread_;
+ bool thread_active_;
+ ACE_SYNCH_CONDITION wake_up_thread_;
+};
+
+} /* namespace TAO_NOTIFY */
+
+#include /**/ "ace/post.h"
+#endif /* PERSISTENT_FILE_ALLOCATOR_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Properties.h b/TAO/orbsvcs/orbsvcs/Notify/Properties.h
index 4542a14bff6..7801ed6dc99 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Properties.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/Properties.h
@@ -62,6 +62,9 @@ public:
CORBA::Boolean asynch_updates (void);
void asynch_updates (CORBA::Boolean asynch_updates);
+ bool allow_reconnect (void);
+ void allow_reconnect (bool b);
+
// Turn on/off update messages.
CORBA::Boolean updates (void);
void updates (CORBA::Boolean updates);
@@ -112,6 +115,9 @@ protected:
/// True if send asynch updates.
CORBA::Boolean asynch_updates_;
+ /// True if clients can reconnect to proxies.
+ bool allow_reconnect_;
+
/// True if updates are enabled (default).
CORBA::Boolean updates_;
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Properties.inl b/TAO/orbsvcs/orbsvcs/Notify/Properties.inl
index 2b83846458c..c8a7893f4d7 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Properties.inl
+++ b/TAO/orbsvcs/orbsvcs/Notify/Properties.inl
@@ -60,6 +60,18 @@ TAO_Notify_Properties::asynch_updates (CORBA::Boolean asynch_updates)
this->asynch_updates_ = asynch_updates;
}
+ACE_INLINE bool
+TAO_Notify_Properties::allow_reconnect (void)
+{
+ return this->allow_reconnect_;
+}
+
+ACE_INLINE void
+TAO_Notify_Properties::allow_reconnect (bool b)
+{
+ this->allow_reconnect_ = b;
+}
+
ACE_INLINE CORBA::Boolean
TAO_Notify_Properties::updates (void)
{
diff --git a/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.cpp b/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.cpp
index 77a4fbc7364..bb5a906dc07 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.cpp
@@ -34,9 +34,9 @@ TAO_Notify_PropertySeq::init (const CosNotification::PropertySeq& prop_seq)
}
int
-TAO_Notify_PropertySeq::populate (CosNotification::PropertySeq_var& prop_seq)
+TAO_Notify_PropertySeq::populate (CosNotification::PropertySeq_var& prop_seq) const
{
- PROPERTY_MAP::ITERATOR iterator (this->property_map_);
+ PROPERTY_MAP::CONST_ITERATOR iterator (this->property_map_);
int index = prop_seq->length ();
prop_seq->length (ACE_static_cast (CORBA::ULong,
@@ -52,3 +52,11 @@ TAO_Notify_PropertySeq::populate (CosNotification::PropertySeq_var& prop_seq)
return 0;
}
+
+void
+TAO_Notify_PropertySeq::add(const ACE_CString& name, const CORBA::Any& val)
+{
+ int ret = this->property_map_.rebind (name, val);
+ ACE_ASSERT(ret >= 0);
+ ACE_UNUSED_ARG (ret); // because the assert disappears in release builds
+}
diff --git a/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.h b/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.h
index ca241e7bbee..1325b724e81 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.h
@@ -48,7 +48,15 @@ public:
int find (const char* name, CosNotification::PropertyValue& value) const;
/// Return -1 on error.
- int populate (CosNotification::PropertySeq_var& prop_seq);
+ int populate (CosNotification::PropertySeq_var& prop_seq) const;
+
+ /// return the number of properties available as a sequence
+ size_t size() const;
+
+protected:
+ /// Add the value. Used by subclasses to initialize the property map from their
+ /// member variables.
+ void add(const ACE_CString& name, const CORBA::Any& val);
protected:
/// Property Map.
diff --git a/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.inl b/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.inl
index 0998ec76b1b..b96345cb11a 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.inl
+++ b/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.inl
@@ -6,3 +6,11 @@ TAO_Notify_PropertySeq::find (const char* name, CosNotification::PropertyValue&
ACE_CString str_name (name);
return this->property_map_.find (str_name, value);
}
+
+ACE_INLINE
+size_t
+TAO_Notify_PropertySeq::size() const
+{
+ return this->property_map_.current_size();
+}
+
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.h b/TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.h
index a0eeef05462..e2d8487d0d8 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.h
@@ -57,6 +57,9 @@ public:
void get (CosNotification::PropertySeq& prop_seq);
+ /// Return the name
+ const char * name (void) const;
+
/// Return the value.
CORBA::Boolean value (void) const;
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.inl b/TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.inl
index f5522993d11..b1a469809bb 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.inl
+++ b/TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.inl
@@ -37,6 +37,13 @@ TAO_Notify_Property_Boolean::operator!= (const CORBA::Boolean &rhs) const
return (this->value_ != rhs);
}
+ACE_INLINE
+const char *
+TAO_Notify_Property_Boolean::name (void) const
+{
+ return this->name_;
+}
+
ACE_INLINE CORBA::Boolean
TAO_Notify_Property_Boolean::value (void) const
{
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Property_T.h b/TAO/orbsvcs/orbsvcs/Notify/Property_T.h
index ff39b43a068..b1b6b7c39f0 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Property_T.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/Property_T.h
@@ -57,9 +57,15 @@ public:
/// Populate the Property Sequence with this valid value.
void get (CosNotification::PropertySeq& prop_seq);
+ // assign a new value
+ void assign (const TYPE& value);
+
/// Return the value.
const TYPE& value (void) const;
+ /// Return the name
+ const char * name (void) const;
+
/// Is the current value valid
CORBA::Boolean is_valid (void) const;
@@ -125,6 +131,9 @@ public:
/// Returns 0 on success, -1 on error
int set (const TAO_Notify_PropertySeq& property_seq);
+ /// Return the name
+ const char * name (void) const;
+
/// Return the value.
const TYPE& value (void) const;
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Property_T.inl b/TAO/orbsvcs/orbsvcs/Notify/Property_T.inl
index f014ab89b29..31d5290c72d 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Property_T.inl
+++ b/TAO/orbsvcs/orbsvcs/Notify/Property_T.inl
@@ -8,6 +8,13 @@ TAO_Notify_PropertyBase_T<TYPE>::value (void) const
return this->value_;
}
+template <class TYPE> ACE_INLINE
+const char *
+TAO_Notify_PropertyBase_T<TYPE>::name (void) const
+{
+ return this->name_;
+}
+
template <class TYPE> ACE_INLINE CORBA::Boolean
TAO_Notify_PropertyBase_T<TYPE>::is_valid (void) const
{
@@ -32,14 +39,33 @@ TAO_Notify_PropertyBase_T<TYPE>:: invalidate (void)
this->valid_ = 0;
}
+template <class TYPE> ACE_INLINE
+void
+TAO_Notify_PropertyBase_T<TYPE>:: assign (const TYPE& value)
+{
+ this->value_ = value;
+ this->valid_ = 1;
+}
+
+
+
/******************************************************************************/
+template <class TYPE> ACE_INLINE
+const char *
+TAO_Notify_StructProperty_T<TYPE>::name (void) const
+{
+ return this->name_;
+}
+
template <class TYPE> ACE_INLINE const TYPE&
TAO_Notify_StructProperty_T<TYPE>::value (void) const
{
return this->value_;
}
+
+
template <class TYPE> ACE_INLINE CORBA::Boolean
TAO_Notify_StructProperty_T<TYPE>::is_valid (void) const
{
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Proxy.cpp b/TAO/orbsvcs/orbsvcs/Notify/Proxy.cpp
index 34e95f70911..ab109a6a674 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Proxy.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/Proxy.cpp
@@ -14,6 +14,7 @@ ACE_RCSID(RT_Notify, TAO_Notify_Proxy, "$Id$")
#include "Worker_Task.h"
#include "Properties.h"
#include "POA_Helper.h"
+#include "Topology_Saver.h"
TAO_Notify_Proxy::TAO_Notify_Proxy (void)
:updates_off_ (0)
@@ -29,8 +30,17 @@ TAO_Notify_Proxy::activate (PortableServer::Servant servant ACE_ENV_ARG_DECL)
{
// Set the POA that we use to return our <ref>
this->poa_ = this->proxy_poa_;
+ return TAO_Notify_Object::activate (servant ACE_ENV_ARG_PARAMETER);
+}
- return this->proxy_poa_->activate (servant, this->id_ ACE_ENV_ARG_PARAMETER);
+CORBA::Object_ptr
+TAO_Notify_Proxy::activate (PortableServer::Servant servant,
+ const CosNotifyChannelAdmin::ProxyID proxy_id
+ ACE_ENV_ARG_DECL)
+{
+ // Set the POA that we use to return our <ref>
+ this->poa_ = this->proxy_poa_;
+ return TAO_Notify_Object::activate (servant, proxy_id ACE_ENV_ARG_PARAMETER);
}
void
@@ -113,3 +123,72 @@ TAO_Notify_Proxy::qos_changed (const TAO_Notify_QoSProperties& qos_properties)
if (peer != 0)
peer->qos_changed (qos_properties);
}
+
+void
+TAO_Notify_Proxy::save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL)
+{
+ bool changed = this->children_changed_;
+ this->children_changed_ = false;
+ this->self_changed_ = false;
+
+ if (is_persistent ())
+ {
+ TAO_NOTIFY::NVPList attrs;
+ this->save_attrs(attrs);
+
+ const char * type_name = this->get_proxy_type_name ();
+ bool want_all_children = saver.begin_object(this->id(), type_name, attrs, changed ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ if (want_all_children || this->filter_admin_.is_changed ())
+ {
+ this->filter_admin_.save_persistent(saver ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+
+ if (want_all_children || this->subscribed_types_.is_changed ())
+ {
+ this->subscribed_types_.save_persistent(saver ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+
+ // todo: handle removed children
+
+ saver.end_object(this->id(), type_name ACE_ENV_ARG_PARAMETER);
+ }
+}
+
+void
+TAO_Notify_Proxy::save_attrs (TAO_NOTIFY::NVPList& attrs)
+{
+ TAO_Notify_Object::save_attrs(attrs);
+ TAO_Notify_Peer * peer = this->peer();
+ if (peer != 0)
+ {
+ ACE_CString ior;
+ if (peer->get_ior(ior))
+ {
+ attrs.push_back (TAO_NOTIFY::NVP("PeerIOR", ior));
+ }
+ }
+}
+
+TAO_NOTIFY::Topology_Object*
+TAO_Notify_Proxy::load_child (const ACE_CString &type, CORBA::Long id,
+ const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL)
+{
+ TAO_NOTIFY::Topology_Object* result = this;
+ if (type == "subscriptions")
+ {
+ // since we initialized our subscribed types to everything
+ // in the constructor. we have to clear it out first.
+ this->subscribed_types_.reset();
+ result = &this->subscribed_types_;
+ ACE_CHECK_RETURN(0);
+ }
+ else if (type == "filter_admin")
+ {
+ result = & this->filter_admin_;
+ }
+ return result;
+}
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Proxy.h b/TAO/orbsvcs/orbsvcs/Notify/Proxy.h
index 59a4c347909..69015ddb0c2 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Proxy.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/Proxy.h
@@ -20,7 +20,7 @@
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */
-#include "Object.h"
+#include "Topology_Object.h"
#include "EventTypeSeq.h"
#include "FilterAdmin.h"
#include "Admin.h"
@@ -35,7 +35,8 @@ class TAO_Notify_Peer;
* @brief Base class proxy for all proxys in NS.
*
*/
-class TAO_Notify_Serv_Export TAO_Notify_Proxy : public virtual TAO_Notify_Object
+class TAO_Notify_Serv_Export TAO_Notify_Proxy
+ : public TAO_NOTIFY::Topology_Parent
{
friend class TAO_Notify_Peer;
@@ -50,35 +51,41 @@ public:
~TAO_Notify_Proxy ();
/// Activate
- virtual CORBA::Object_ptr activate (PortableServer::Servant servant
+ virtual CORBA::Object_ptr activate (PortableServer::Servant servant
ACE_ENV_ARG_DECL);
+ /// Activate with a given ID
+ virtual CORBA::Object_ptr activate (
+ PortableServer::Servant servant,
+ CORBA::Long id
+ ACE_ENV_ARG_DECL);
+
/// Deactivate
void deactivate (ACE_ENV_SINGLE_ARG_DECL);
/// Obtain the Proxy's subscribed types.
- void subscribed_types (TAO_Notify_EventTypeSeq& subscribed_types
+ void subscribed_types (TAO_Notify_EventTypeSeq& subscribed_types
ACE_ENV_ARG_DECL);
/// Check if this event passes the admin and proxy filters.
CORBA::Boolean check_filters (
- const TAO_Notify_Event* event,
- TAO_Notify_FilterAdmin& parent_filter_admin,
+ const TAO_Notify_Event* event,
+ TAO_Notify_FilterAdmin& parent_filter_admin,
CosNotifyChannelAdmin::InterFilterGroupOperator filter_operator
ACE_ENV_ARG_DECL
);
/// Check if this event passes the admin and proxy filters.
CORBA::Boolean check_filters (
- const TAO_Notify_Event_var &event,
- TAO_Notify_FilterAdmin& parent_filter_admin,
+ const TAO_Notify_Event_var &event,
+ TAO_Notify_FilterAdmin& parent_filter_admin,
CosNotifyChannelAdmin::InterFilterGroupOperator filter_operator
ACE_ENV_ARG_DECL
);
/// Inform this proxy that the following types are being advertised.
- void types_changed (const TAO_Notify_EventTypeSeq& added,
- const TAO_Notify_EventTypeSeq& removed
+ void types_changed (const TAO_Notify_EventTypeSeq& added,
+ const TAO_Notify_EventTypeSeq& removed
ACE_ENV_ARG_DECL);
/// Have updates been turned off.
@@ -92,8 +99,8 @@ public:
/// Implement the Obtain Types.
virtual CosNotification::EventTypeSeq* obtain_types (
- CosNotifyChannelAdmin::ObtainInfoMode mode,
- const TAO_Notify_EventTypeSeq& types
+ CosNotifyChannelAdmin::ObtainInfoMode mode,
+ const TAO_Notify_EventTypeSeq& types
ACE_ENV_ARG_DECL
)
ACE_THROW_SPEC ((CORBA::SystemException));
@@ -107,6 +114,15 @@ public:
/// Override, TAO_Notify_Object::qos_changed
virtual void qos_changed (const TAO_Notify_QoSProperties& qos_properties);
+ // TAO_NOTIFY::Topology_Object
+
+ virtual void save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL);
+ virtual void save_attrs(TAO_NOTIFY::NVPList& attrs);
+ virtual const char * get_proxy_type_name (void) const = 0;
+
+ virtual TAO_NOTIFY::Topology_Object* load_child (const ACE_CString &type, CORBA::Long id,
+ const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL);
+
protected:
/// Filter Administration
diff --git a/TAO/orbsvcs/orbsvcs/Notify/ProxyConsumer.cpp b/TAO/orbsvcs/orbsvcs/Notify/ProxyConsumer.cpp
index 1675a777de5..51bcae25d25 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/ProxyConsumer.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/ProxyConsumer.cpp
@@ -40,7 +40,7 @@ TAO_Notify_ProxyConsumer::peer (void)
void
TAO_Notify_ProxyConsumer::init (TAO_Notify_SupplierAdmin* supplier_admin ACE_ENV_ARG_DECL)
{
- TAO_Notify_Object::init (supplier_admin);
+ TAO_NOTIFY::Topology_Object::init (supplier_admin);
this->supplier_admin_ = supplier_admin;
@@ -70,17 +70,30 @@ TAO_Notify_ProxyConsumer::connect (TAO_Notify_Supplier *supplier ACE_ENV_ARG_DEC
ACE_GUARD_THROW_EX (TAO_SYNCH_MUTEX, ace_mon, this->lock_,
CORBA::INTERNAL ());
ACE_CHECK;
+ TAO_Notify_Supplier* deleted_supplier = 0;
if (this->is_connected ())
{
- supplier->release ();
- ACE_THROW (CosEventChannelAdmin::AlreadyConnected ());
+ if (TAO_Notify_PROPERTIES::instance()->allow_reconnect())
+ {
+ deleted_supplier = this->supplier_;
+ }
+ else
+ {
+ supplier->release ();
+ ACE_THROW (CosEventChannelAdmin::AlreadyConnected ());
+ }
}
- supplier_ = supplier;
+ this->supplier_ = supplier;
this->supplier_admin_->subscribed_types (this->subscribed_types_ ACE_ENV_ARG_PARAMETER); // get the parents subscribed types.
ACE_CHECK;
+
+ if (deleted_supplier != 0)
+ {
+ deleted_supplier->_decr_refcnt();
+ }
}
// Inform QoS values.
diff --git a/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.cpp b/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.cpp
index 3034ae07829..1b4049662c1 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.cpp
@@ -31,7 +31,7 @@ TAO_Notify_ProxySupplier::~TAO_Notify_ProxySupplier ()
void
TAO_Notify_ProxySupplier::init (TAO_Notify_ConsumerAdmin* consumer_admin ACE_ENV_ARG_DECL)
{
- TAO_Notify_Object::init (consumer_admin);
+ TAO_NOTIFY::Topology_Object::init (consumer_admin);
this->consumer_admin_ = consumer_admin;
@@ -68,16 +68,28 @@ TAO_Notify_ProxySupplier::connect (TAO_Notify_Consumer *consumer ACE_ENV_ARG_DEC
CORBA::INTERNAL ());
ACE_CHECK;
+ TAO_Notify_Consumer * deleted_consumer = 0;
if (this->is_connected ())
{
- consumer->release ();
- ACE_THROW (CosEventChannelAdmin::AlreadyConnected ());
+ if (TAO_Notify_PROPERTIES::instance()->allow_reconnect())
+ {
+ deleted_consumer = this->consumer_;
+ }
+ else
+ {
+ consumer->release ();
+ ACE_THROW (CosEventChannelAdmin::AlreadyConnected ());
+ }
}
consumer_ = consumer;
this->consumer_admin_->subscribed_types (this->subscribed_types_ ACE_ENV_ARG_PARAMETER); // get the parents subscribed types.
ACE_CHECK;
+ if (deleted_consumer != 0)
+ {
+ deleted_consumer->_decr_refcnt();
+ }
}
// Inform QoS values.
diff --git a/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.h b/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.h
index 272c9c3f1ea..903c476b5b1 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.h
@@ -89,6 +89,7 @@ public:
/// The CA parent.
TAO_Notify_ConsumerAdmin* consumer_admin (void);
+// const char * get_proxy_type_name (void) const;
protected:
///= Data Members.
diff --git a/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier_T.cpp b/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier_T.cpp
index 86f2c82569b..33c3ed70b8c 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier_T.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier_T.cpp
@@ -140,6 +140,9 @@ TAO_Notify_ProxySupplier_T<SERVANT_TYPE>::suspend_connection (ACE_ENV_SINGLE_ARG
}
this->consumer_->suspend (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
}
template <class SERVANT_TYPE> void
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Proxy_T.cpp b/TAO/orbsvcs/orbsvcs/Notify/Proxy_T.cpp
index d767751adc3..79856ed053b 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Proxy_T.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/Proxy_T.cpp
@@ -99,7 +99,12 @@ TAO_Notify_Proxy_T<SERVANT_TYPE>::add_filter (CosNotifyFilter::Filter_ptr new_fi
CORBA::INTERNAL ());
ACE_CHECK_RETURN (0);
- return this->filter_admin_.add_filter (new_filter ACE_ENV_ARG_PARAMETER);
+ CosNotifyFilter::FilterID fid =
+ this->filter_admin_.add_filter (new_filter ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN(fid);
+ return fid;
}
template <class SERVANT_TYPE> void
diff --git a/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.cpp b/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.cpp
index 805ae87ff67..7af2da443ab 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.cpp
@@ -10,18 +10,21 @@ ACE_RCSID(Notify, TAO_Notify_QoSProperties, "$Id$")
#include "Property.h"
+
+
TAO_Notify_QoSProperties::TAO_Notify_QoSProperties (void)
- : priority_ (CosNotification::Priority)
+ : event_reliability_(CosNotification::EventReliability)
+ , connection_reliability_(CosNotification::ConnectionReliability)
+ , priority_ (CosNotification::Priority)
, timeout_ (CosNotification::Timeout)
, stop_time_supported_ (CosNotification::StopTimeSupported)
, maximum_batch_size_ (CosNotification::MaximumBatchSize)
+ , max_events_per_consumer_ (CosNotification::MaxEventsPerConsumer)
, pacing_interval_ (CosNotification::PacingInterval)
, thread_pool_ (NotifyExt::ThreadPool)
, thread_pool_lane_ (NotifyExt::ThreadPoolLanes)
{
- unsupported_[0] = CosNotification::EventReliability;
- unsupported_[1] = CosNotification::ConnectionReliability;
- unsupported_[2] = CosNotification::StartTimeSupported;
+ unsupported_[0] = CosNotification::StartTimeSupported;
}
TAO_Notify_QoSProperties::~TAO_Notify_QoSProperties ()
@@ -39,6 +42,70 @@ TAO_Notify_QoSProperties::unsupported (ACE_CString& name)
return 0;
}
+void
+TAO_Notify_QoSProperties::init ()
+{
+ if (this->event_reliability_.is_valid())
+ {
+ CORBA::Any a;
+ a <<= this->event_reliability_.value();
+ this->add(this->event_reliability_.name(), a);
+ }
+ if (this->connection_reliability_.is_valid())
+ {
+ CORBA::Any a;
+ a <<= this->connection_reliability_.value();
+ this->add(this->connection_reliability_.name(), a);
+ }
+ if (this->priority_.is_valid())
+ {
+ CORBA::Any a;
+ a <<= this->priority_.value();
+ this->add(this->priority_.name(), a);
+ }
+ if (this->timeout_.is_valid())
+ {
+ CORBA::Any a;
+ a <<= this->timeout_.value();
+ this->add(this->timeout_.name(), a);
+ }
+ if (this->stop_time_supported_.is_valid())
+ {
+ CORBA::Any a;
+ a <<= CORBA::Any::from_boolean (this->stop_time_supported_.value());
+ this->add(this->stop_time_supported_.name(), a);
+ }
+ if (this->maximum_batch_size_.is_valid())
+ {
+ CORBA::Any a;
+ a <<= this->maximum_batch_size_.value();
+ this->add(this->maximum_batch_size_.name(), a);
+ }
+ if (this->pacing_interval_.is_valid())
+ {
+ CORBA::Any a;
+ a <<= this->pacing_interval_.value();
+ this->add(this->pacing_interval_.name(), a);
+ }
+ if (this->max_events_per_consumer_.is_valid())
+ {
+ CORBA::Any a;
+ a <<= this->max_events_per_consumer_.value();
+ this->add(this->max_events_per_consumer_.name(), a);
+ }
+ if (this->thread_pool_.is_valid())
+ {
+ CORBA::Any a;
+ a <<= this->thread_pool_.value();
+ this->add(this->thread_pool_.name(), a);
+ }
+ if (this->thread_pool_lane_.is_valid())
+ {
+ CORBA::Any a;
+ a <<= this->thread_pool_lane_.value();
+ this->add(this->thread_pool_lane_.name(), a);
+ }
+}
int
TAO_Notify_QoSProperties::init (const CosNotification::PropertySeq& prop_seq, CosNotification::PropertyErrorSeq& err_seq)
@@ -64,8 +131,10 @@ TAO_Notify_QoSProperties::init (const CosNotification::PropertySeq& prop_seq, Co
}
if (prop_seq.length () > 0)
- {
+ {
// Now, init the supported properties
+ this->event_reliability_.set (*this);
+ this->connection_reliability_.set (*this);
this->priority_.set (*this);
this->timeout_.set (*this);
this->stop_time_supported_.set (*this);
@@ -81,6 +150,8 @@ TAO_Notify_QoSProperties::init (const CosNotification::PropertySeq& prop_seq, Co
int
TAO_Notify_QoSProperties::copy (TAO_Notify_QoSProperties& qos_properties)
{
+ qos_properties.event_reliability_ = this->event_reliability_;
+ qos_properties.connection_reliability_ = this->connection_reliability_;
qos_properties.priority_ = this->priority_;
qos_properties.timeout_ = this->timeout_;
qos_properties.stop_time_supported_ = this->stop_time_supported_;
diff --git a/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.h b/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.h
index ba418a24cca..91572274252 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.h
@@ -43,6 +43,9 @@ public:
/// Return 0 on success, 1 if unsupported properties were detected and -1 on error.
int init (const CosNotification::PropertySeq& prop_seq, CosNotification::PropertyErrorSeq& err_seq);
+ /// This version initializes the base from our members
+ void init ();
+
/// Populate <qos_properties> with all properties from this object. Returns -1 on error.
int copy (TAO_Notify_QoSProperties& qos_properties);
@@ -61,18 +64,42 @@ public:
/// Pacing Interval
const TAO_Notify_Property_Time& pacing_interval (void) const;
+ ///= Accessors
+
+ const TAO_Notify_Property_Short& event_reliability (void) const;
+ const TAO_Notify_Property_Short& connection_reliability (void) const;
+ const TAO_Notify_Property_Short& priority (void) const;
+ const TAO_Notify_Property_Time& timeout (void) const;
+ const TAO_Notify_Property_Boolean& stop_time_supported (void) const;
+ const TAO_Notify_Property_Long& max_events_per_consumer (void) const;
+
+ // The non-const accessors are used during topology load
+ TAO_Notify_Property_Short& event_reliability (void);
+ TAO_Notify_Property_Short& connection_reliability (void);
+ TAO_Notify_Property_Short& priority (void);
+ TAO_Notify_Property_Time& timeout (void);
+ TAO_Notify_Property_Boolean& stop_time_supported (void);
+ TAO_Notify_Property_Long& maximum_batch_size (void);
+ TAO_Notify_Property_Time& pacing_interval (void);
+ TAO_Notify_Property_Long& max_events_per_consumer (void);
protected:
/// Return 1 if <value> is unsupported.
int unsupported (ACE_CString& name);
- enum {UNSUPPORTED_PROPERTY_COUNT = 3};
+ enum {UNSUPPORTED_PROPERTY_COUNT = 1};
///= Unsupported Properties.
ACE_CString unsupported_[UNSUPPORTED_PROPERTY_COUNT];
///= Supported properties
+ /// Event Reliability
+ TAO_Notify_Property_Short event_reliability_;
+
+ /// Connection Reliability
+ TAO_Notify_Property_Short connection_reliability_;
+
/// Priority
TAO_Notify_Property_Short priority_;
@@ -85,6 +112,9 @@ protected:
/// Maximum Batch Size
TAO_Notify_Property_Long maximum_batch_size_;
+ /// Maximum Events (queue length) Per Consumer
+ TAO_Notify_Property_Long max_events_per_consumer_;
+
/// Pacing Interval
TAO_Notify_Property_Time pacing_interval_;
diff --git a/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.inl b/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.inl
index 087ab21febe..14aab6a7866 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.inl
+++ b/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.inl
@@ -1,5 +1,47 @@
// $Id$
+ACE_INLINE
+const TAO_Notify_Property_Short&
+TAO_Notify_QoSProperties::event_reliability(void) const
+{
+ return this->event_reliability_;
+}
+
+ACE_INLINE
+const TAO_Notify_Property_Short&
+TAO_Notify_QoSProperties::connection_reliability(void) const
+{
+ return this->connection_reliability_;
+}
+
+ACE_INLINE
+const TAO_Notify_Property_Short&
+TAO_Notify_QoSProperties::priority(void) const
+{
+ return this->priority_;
+}
+
+ACE_INLINE
+const TAO_Notify_Property_Time&
+TAO_Notify_QoSProperties::timeout(void) const
+{
+ return this->timeout_;
+}
+
+ACE_INLINE
+const TAO_Notify_Property_Boolean&
+TAO_Notify_QoSProperties::stop_time_supported(void) const
+{
+ return this->stop_time_supported_;
+}
+
+ACE_INLINE
+const TAO_Notify_Property_Long&
+TAO_Notify_QoSProperties::max_events_per_consumer (void) const
+{
+ return this->max_events_per_consumer_;
+}
+
ACE_INLINE const TAO_Notify_Property_ThreadPool&
TAO_Notify_QoSProperties::thread_pool (void) const
{
@@ -23,3 +65,58 @@ TAO_Notify_QoSProperties::pacing_interval (void) const
{
return this->pacing_interval_;
}
+
+ACE_INLINE
+TAO_Notify_Property_Short&
+TAO_Notify_QoSProperties::event_reliability(void)
+{
+ return this->event_reliability_;
+}
+
+ACE_INLINE
+TAO_Notify_Property_Short&
+TAO_Notify_QoSProperties::connection_reliability(void)
+{
+ return this->connection_reliability_;
+}
+
+ACE_INLINE
+TAO_Notify_Property_Short&
+TAO_Notify_QoSProperties::priority(void)
+{
+ return this->priority_;
+}
+
+ACE_INLINE
+TAO_Notify_Property_Time&
+TAO_Notify_QoSProperties::timeout(void)
+{
+ return this->timeout_;
+}
+
+ACE_INLINE
+TAO_Notify_Property_Boolean&
+TAO_Notify_QoSProperties::stop_time_supported(void)
+{
+ return this->stop_time_supported_;
+}
+
+ACE_INLINE
+TAO_Notify_Property_Long&
+TAO_Notify_QoSProperties::max_events_per_consumer (void)
+{
+ return this->max_events_per_consumer_;
+}
+
+
+ACE_INLINE TAO_Notify_Property_Long&
+TAO_Notify_QoSProperties::maximum_batch_size (void)
+{
+ return this->maximum_batch_size_;
+}
+
+ACE_INLINE TAO_Notify_Property_Time&
+TAO_Notify_QoSProperties::pacing_interval (void)
+{
+ return this->pacing_interval_;
+}
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.cpp b/TAO/orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.cpp
new file mode 100644
index 00000000000..09c3a50414c
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.cpp
@@ -0,0 +1,39 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+* @file Reconnect_Worker_T.cpp
+*
+* $Id$
+*
+* @author Jonathan Pollack <pollack_j@ociweb.com>
+*/
+//=============================================================================
+
+#ifndef RECONNECT_WORKER_CPP
+#define RECONNECT_WORKER_CPP
+
+#include "Reconnect_Worker_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+namespace TAO_NOTIFY
+{
+ template<class TOPOOBJ>
+ Reconnect_Worker<TOPOOBJ>::Reconnect_Worker()
+ {
+ }
+
+ template<class TOPOOBJ>
+ void
+ Reconnect_Worker<TOPOOBJ>::work (TOPOOBJ* o ACE_ENV_ARG_DECL)
+ {
+ ACE_ASSERT(o != 0);
+ o->reconnect (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+} // namespace TAO_NOTIFY
+
+#endif /* RECONNECT_WORKER_CPP */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.h b/TAO/orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.h
new file mode 100644
index 00000000000..0a664b61144
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.h
@@ -0,0 +1,50 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+* @file Reconnect_Worker_T.h
+*
+* $Id$
+*
+* @author Jonathan Pollack <pollack_j@ociweb.com>
+*/
+//=============================================================================
+
+#ifndef RECONNECT_WORKER_H
+#define RECONNECT_WORKER_H
+#include /**/ "ace/pre.h"
+
+#include "orbsvcs/ESF/ESF_Worker.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+namespace TAO_NOTIFY
+{
+ /**
+ * \brief Iterate through children reconnecting after reloading persistent information.
+ */
+ template<class TOPOOBJ>
+ class Reconnect_Worker : public TAO_ESF_Worker<TOPOOBJ>
+ {
+ public:
+ /// Constructor
+ Reconnect_Worker();
+
+ // override virtual ESF_Worker method
+ virtual void work (TOPOOBJ* o ACE_ENV_ARG_DECL);
+ };
+} // namespace TAO_NOTIFY
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "Reconnect_Worker_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Reconnect_Worker_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include /**/ "ace/post.h"
+
+#endif /* RECONECT_WORKER_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.cpp b/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.cpp
new file mode 100644
index 00000000000..047acc906c0
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.cpp
@@ -0,0 +1,267 @@
+/* -*- C++ -*- */
+/**
+ * @file Reconnection_Registry.cpp
+ *
+ * $Id$
+ *
+ * @author Dale Wilson <wilson_d@ociweb.com>
+ *
+ */
+#include "Reconnection_Registry.h"
+
+#if ! defined (__ACE_INLINE__)
+#include "Reconnection_Registry.inl"
+#endif /* __ACE_INLINE__ */
+
+#include <tao/debug.h>
+#include "Properties.h"
+#include "Topology_Saver.h"
+#include <ace/Vector_T.h>
+namespace TAO_NOTIFY
+{
+ Reconnection_Registry::Reconnection_Registry (Topology_Parent & parent)
+ : highest_id_(0)
+ {
+ // not the best technique, here. Take advantage of "protected"
+ Topology_Object::topology_parent_ = &parent;
+ }
+
+ Reconnection_Registry::~Reconnection_Registry ()
+ {
+ }
+
+ //////////////////////////
+ // During normal operation
+
+ NotifyExt::ReconnectionRegistry::ReconnectionID
+ Reconnection_Registry::register_callback (
+ NotifyExt::ReconnectionCallback_ptr callback
+ ACE_ENV_ARG_DECL)
+ {
+ //@@todo DO WE NEED THREAD SAFENESS?
+ NotifyExt::ReconnectionRegistry::ReconnectionID next_id = ++highest_id_;
+
+ if (TAO_debug_level > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Reconnect registry: registering %d\n"),
+ ACE_static_cast (int, next_id)
+ ));
+ }
+ TAO_Notify_Properties* properties = TAO_Notify_PROPERTIES::instance();
+ CORBA::ORB_var orb = properties->orb ();
+
+ CORBA::String_var cior = orb->object_to_string (callback ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+ ACE_CString ior(cior.in ());
+ if ( 0 != reconnection_registry_.bind (next_id, ior))
+ {
+ //todo throw something;
+ }
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ return next_id;
+ }
+
+ void
+ Reconnection_Registry::unregister_callback (NotifyExt::ReconnectionRegistry::ReconnectionID id
+ ACE_ENV_ARG_DECL)
+ {
+ if (TAO_debug_level > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Reconnect registry: unregistering %d\n"),
+ ACE_static_cast (int, id)
+ ));
+ }
+ if ( 0 != reconnection_registry_.unbind (id))
+ {
+ //@@todo throw something
+ }
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
+ }
+
+ CORBA::Boolean
+ Reconnection_Registry::is_alive (ACE_ENV_SINGLE_ARG_DECL_NOT_USED)
+ {
+ return CORBA::Boolean(1);
+ }
+
+ //////////////////////
+ // During topology save
+
+ void
+ Reconnection_Registry::save_persistent (Topology_Saver& saver ACE_ENV_ARG_DECL)
+ {
+ bool change = this->self_changed_;
+ this->self_changed_ = false;
+ this->children_changed_ = false;
+
+ NVPList attrs;
+ //@@todo: bool want_all_children =
+ saver.begin_object (0, REGISTRY_TYPE, attrs, change ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ Reconnection_Registry_Type::ENTRY *entry;
+ for (Reconnection_Registry_Type::ITERATOR iter (this->reconnection_registry_);
+ iter.next (entry);
+ iter.advance ())
+ {
+ NVPList cattrs;
+ if (TAO_debug_level > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Reconnect registry: saving %d\n"),
+ ACE_static_cast (int, entry->ext_id_)
+ ));
+ }
+ cattrs.push_back(NVP(RECONNECT_ID, entry->ext_id_));
+ cattrs.push_back(NVP(RECONNECT_IOR, entry->int_id_));
+ saver.begin_object (entry->ext_id_, REGISTRY_CALLBACK_TYPE, cattrs, true ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ saver.end_object (entry->ext_id_, REGISTRY_CALLBACK_TYPE ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+// todo:
+// for all deleted children
+// {
+// saver.delete_child(child_type, child_id);
+// }
+ saver.end_object (0, REGISTRY_TYPE ACE_ENV_ARG_PARAMETER);
+ }
+
+ ///////////////////////////////////////
+ // During reload of persistent topology
+
+ Topology_Object*
+ Reconnection_Registry::load_child (const ACE_CString & type,
+ CORBA::Long,
+ const NVPList& attrs
+ ACE_ENV_ARG_DECL_NOT_USED)
+ {
+ if (type == REGISTRY_CALLBACK_TYPE)
+ {
+ NotifyExt::ReconnectionRegistry::ReconnectionID id;
+ ACE_CString ior;
+ if (attrs.load (RECONNECT_ID, id) && attrs.load (RECONNECT_IOR, ior))
+ {
+ if (id > highest_id_)
+ {
+ highest_id_ = id;
+
+ if (TAO_debug_level > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Reconnect registry: reloading %d\n"),
+ ACE_static_cast (int, id)
+ ));
+ }
+ }
+ if ( 0 != reconnection_registry_.bind (id, ior))
+ {
+ //@@todo - throw something;
+ }
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Reconnect registry: missing attribute\n")
+ ));
+ }
+ }
+ return this;
+ }
+
+ void
+ Reconnection_Registry::send_reconnect (CosNotifyChannelAdmin::EventChannelFactory_ptr dest_factory
+ ACE_ENV_ARG_DECL_NOT_USED)
+ {
+ TAO_Notify_Properties* properties = TAO_Notify_PROPERTIES::instance();
+ CORBA::ORB_var orb = properties->orb ();
+ ACE_Vector <NotifyExt::ReconnectionRegistry::ReconnectionID> bad_ids;
+
+ Reconnection_Registry_Type::ENTRY *entry;
+ for (Reconnection_Registry_Type::ITERATOR iter (this->reconnection_registry_);
+ iter.next (entry);
+ iter.advance ())
+ {
+ ACE_TRY_NEW_ENV
+ {
+ if (TAO_debug_level > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Reconnection Registry: Sending reconnection to client %d\n"),
+ ACE_static_cast (int, entry->ext_id_)
+ ));
+ }
+ ACE_CString & ior = entry->int_id_;
+ CORBA::Object_var obj = orb->string_to_object (ior.c_str () ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ NotifyExt::ReconnectionCallback_var callback =
+ NotifyExt::ReconnectionCallback::_narrow (obj.in ());
+ if (!CORBA::is_nil (callback.in ()))
+ {
+ callback->reconnect (dest_factory ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Reconnection Registry: Can't resolve reconnection client's IOR %d\n"),
+ ACE_static_cast (int, entry->ext_id_)
+ ));
+
+ //throw this entry away but you've got an iterator so be careful
+ bad_ids.push_back (entry->ext_id_);
+ }
+ }
+ ACE_CATCHANY
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Reconnection Registry: Exception sending reconnection to client -- discarding registry entry\n")
+ ));
+ //throw this entry away but you've got an iterator so be careful
+ bad_ids.push_back (entry->ext_id_);
+ //@@todo : we might want to check for retryable exceptions, but for now...
+ }
+ ACE_ENDTRY;
+ }
+ size_t bad_count = bad_ids.size ();
+ for (size_t nbad = 0; nbad < bad_count; ++nbad)
+ {
+ this->reconnection_registry_.unbind (bad_ids[nbad]);
+ }
+ }
+
+ void
+ Reconnection_Registry::release (void)
+ {
+ delete this;
+ //@@ inform factory
+ }
+
+
+} // namespace TAO_NOTIFY
+
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Hash_Map_Entry<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString>;
+template class ACE_Hash_Map_Manager_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString, ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Iterator_Base_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString,ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Iterator_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString,ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Reverse_Iterator_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString,ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Null_Mutex>;
+// vector of int's is instantiated elsewhere
+//template class ACE_Vector<NotifyExt::ReconnectionRegistry::ReconnectionID>;
+//template class ACE_Array_Base<NotifyExt::ReconnectionRegistry::ReconnectionID>;
+
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Hash_Map_Entry<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString >
+#pragma instantiate ACE_Hash_Map_Manager_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString ,ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Iterator_Base_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString ,ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Iterator_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString ,ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Reverse_Iterator_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString ,ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Null_Mutex>
+// vector of int's is instantiated elsewhere
+//#pragma instantiate ACE_Vector<NotifyExt::ReconnectionRegistry::ReconnectionID>
+//#pragma instantiate ACE_Array_Base<NotifyExt::ReconnectionRegistry::ReconnectionID>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.h b/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.h
new file mode 100644
index 00000000000..f077a3c1695
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.h
@@ -0,0 +1,100 @@
+/* -*- C++ -*- */
+/**
+ * @file Reconnection_Registry.h
+ *
+ * $Id$
+ *
+ * @author Dale Wilson <wilson_d@ociweb.com>
+ *
+ */
+
+#ifndef TAO_NOTIFY_RECONNECTION_REGISTRY_H
+#define TAO_NOTIFY_RECONNECTION_REGISTRY_H
+#include /**/ <ace/pre.h>
+#include /**/ <ace/config-all.h>
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "Topology_Object.h"
+
+#include "orbsvcs/NotifyExtS.h"
+
+#include "ace/Hash_Map_Manager_T.h"
+#include "ace/Null_Mutex.h"
+
+namespace TAO_NOTIFY
+{
+ static const char REGISTRY_TYPE[] = "reconnect_registry";
+ static const char RECONNECT_ID[] = "ReconnectId";
+ static const char RECONNECT_IOR[] = "IOR";
+ static const char REGISTRY_CALLBACK_TYPE[] = "reconnect_callback";
+
+ /**
+ * @class Reconnection_Registry
+ *
+ * @brief Implementation of ReconnectionRegistry
+ *
+ */
+ class TAO_Notify_Serv_Export Reconnection_Registry
+ : public Topology_Object
+ {
+ /// The registry consists of a map from ReconnectionID to stringified IOR
+ typedef ACE_Hash_Map_Manager_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID,
+ ACE_CString,
+ ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>,
+ ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>,
+ ACE_SYNCH_NULL_MUTEX> Reconnection_Registry_Type;
+
+ public:
+
+ /// Constructor
+ Reconnection_Registry (Topology_Parent & parent);
+
+ /// Destructor
+ ~Reconnection_Registry ();
+
+ //////////////////////////
+ // During normal operation
+
+ /// add a new callback to the registry
+ ::NotifyExt::ReconnectionRegistry::ReconnectionID register_callback (
+ ::NotifyExt::ReconnectionCallback_ptr callback
+ ACE_ENV_ARG_DECL);
+
+ ///
+ void unregister_callback (::NotifyExt::ReconnectionRegistry::ReconnectionID id
+ ACE_ENV_ARG_DECL);
+
+ CORBA::Boolean is_alive (ACE_ENV_SINGLE_ARG_DECL);
+
+ //////////////////////
+ // During topology save
+ virtual void save_persistent (Topology_Saver& saver ACE_ENV_ARG_DECL);
+
+ ///////////////////////////////////////
+ // During reload of persistent topology
+
+ virtual Topology_Object* load_child (const ACE_CString & type,
+ CORBA::Long id,
+ const NVPList& attrs
+ ACE_ENV_ARG_DECL);
+
+ void send_reconnect (CosNotifyChannelAdmin::EventChannelFactory_ptr dest_factory
+ ACE_ENV_ARG_DECL);
+
+ void release (void);
+
+ private:
+ Reconnection_Registry_Type reconnection_registry_;
+ ::NotifyExt::ReconnectionRegistry::ReconnectionID highest_id_;
+ };
+} // namespace TAO_NOTIFY
+
+#if defined (__ACE_INLINE__)
+#include "Reconnection_Registry.inl"
+#endif /* __ACE_INLINE__ */
+
+#include /**/ <ace/post.h>
+#endif /* TAO_NOTIFY_RECONNECTION_REGISTRY_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.inl b/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.inl
new file mode 100644
index 00000000000..19ec798e989
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.inl
@@ -0,0 +1,2 @@
+// $Id$
+
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip.cpp b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip.cpp
new file mode 100644
index 00000000000..7e4894e9a38
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip.cpp
@@ -0,0 +1,878 @@
+// $Id$
+
+#include "Routing_Slip.h"
+
+#if ! defined (__ACE_INLINE__)
+#include "Routing_Slip.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "Delivery_Request.h"
+#include "Delivery_Method_Lookup.h"
+#include "Delivery_Method_Dispatch.h"
+#include "Worker_Task.h"
+#include "ProxyConsumer.h"
+#include "ProxySupplier.h"
+#include "Event_Persistence_Strategy.h"
+#include "Routing_Slip_Persistence_Manager.h"
+#include "Routing_Slip_Queue.h"
+#include "tao/debug.h"
+#include "ace/Dynamic_Service.h"
+
+//#define DEBUG_LEVEL 9
+#define DEBUG_LEVEL TAO_debug_level
+
+#define QUEUE_ALLOWED 1
+
+namespace TAO_NOTIFY
+{
+///////////////////////
+// Routing_Slip Statics
+
+Routing_Slip_Queue Routing_Slip::persistent_queue_(QUEUE_ALLOWED);
+
+TAO_SYNCH_MUTEX Routing_Slip::sequence_lock_;
+int Routing_Slip::routing_slip_sequence_= 0;
+size_t Routing_Slip::count_enter_transient_ = 0;
+size_t Routing_Slip::count_continue_transient_ = 0;
+size_t Routing_Slip::count_enter_reloaded_ = 0;
+size_t Routing_Slip::count_enter_new_ = 0;
+size_t Routing_Slip::count_continue_new_ = 0;
+size_t Routing_Slip::count_enter_complete_while_new_ = 0;
+size_t Routing_Slip::count_enter_saving_ = 0;
+size_t Routing_Slip::count_enter_saved_ = 0;
+size_t Routing_Slip::count_enter_updating_ = 0;
+size_t Routing_Slip::count_enter_changed_while_saving_ = 0;
+size_t Routing_Slip::count_continue_changed_while_saving_ = 0;
+size_t Routing_Slip::count_enter_changed_ = 0;
+size_t Routing_Slip::count_continue_changed_ = 0;
+size_t Routing_Slip::count_enter_complete_ = 0;
+size_t Routing_Slip::count_enter_deleting_ = 0;
+size_t Routing_Slip::count_enter_terminal_ = 0;
+
+Routing_Slip_Ptr
+Routing_Slip::create (
+ const TAO_Notify_Event_Ptr& event)
+{
+ Routing_Slip_Ptr result(new Routing_Slip (event));
+ result->this_ptr_ = result; // let the pointers touch so they use the same ref count
+
+ // note we don't care about ultra-precise stats, so no guard for these
+ if (DEBUG_LEVEL > 1 && ((result->sequence_ % 100) == 0))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Routing_Slip_Statistics\n")
+ ACE_TEXT (" enter_transient \t%d\n")
+ ACE_TEXT (" continue_transient \t%d\n")
+ ACE_TEXT (" enter_reloaded \t%d\n")
+ ACE_TEXT (" enter_new \t%d\n")
+ ACE_TEXT (" continue_new \t%d\n")
+ ACE_TEXT (" enter_complete_while_new \t%d\n")
+ ACE_TEXT (" enter_saving \t%d\n")
+ ACE_TEXT (" enter_saved \t%d\n")
+ ACE_TEXT (" enter_updating \t%d\n")
+ ACE_TEXT (" enter_changed_while_saving \t%d\n")
+ ACE_TEXT (" continue_changed_while_saving\t%d\n")
+ ACE_TEXT (" enter_changed \t%d\n")
+ ACE_TEXT (" continue_changed \t%d\n")
+ ACE_TEXT (" enter_complete \t%d\n")
+ ACE_TEXT (" enter_deleting \t%d\n")
+ ACE_TEXT (" enter_terminal \t%d\n")
+ , ACE_static_cast (int, count_enter_transient_)
+ , ACE_static_cast (int, count_continue_transient_)
+ , ACE_static_cast (int, count_enter_reloaded_)
+ , ACE_static_cast (int, count_enter_new_)
+ , ACE_static_cast (int, count_continue_new_)
+ , ACE_static_cast (int, count_enter_complete_while_new_)
+ , ACE_static_cast (int, count_enter_saving_)
+ , ACE_static_cast (int, count_enter_saved_)
+ , ACE_static_cast (int, count_enter_updating_)
+ , ACE_static_cast (int, count_enter_changed_while_saving_)
+ , ACE_static_cast (int, count_continue_changed_while_saving_)
+ , ACE_static_cast (int, count_enter_changed_)
+ , ACE_static_cast (int, count_continue_changed_)
+ , ACE_static_cast (int, count_enter_complete_)
+ , ACE_static_cast (int, count_enter_deleting_)
+ , ACE_static_cast (int, count_enter_terminal_)
+ ));
+ }
+ return result;
+}
+
+// static
+Routing_Slip_Ptr
+Routing_Slip::create (
+ TAO_Notify_EventChannelFactory & ecf,
+ Routing_Slip_Persistence_Manager * rspm)
+{
+ Routing_Slip_Ptr result;
+ ACE_Message_Block * event_mb = 0;
+ ACE_Message_Block * rs_mb = 0;
+ if (rspm->reload (event_mb, rs_mb))
+ {
+ TAO_InputCDR cdr_event (event_mb);
+ TAO_Notify_Event_Ptr event (TAO_Notify_Event::unmarshal (cdr_event));
+ if (event != 0)
+ {
+ result = create (event);
+ TAO_InputCDR cdr_rs (rs_mb);
+ if ( result->unmarshal (ecf, cdr_rs))
+ {
+ result->set_rspm (rspm);
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Routing_Slip::create: Unmarshalling failed for routing slip.\n")
+ ));
+ result.reset ();
+ }
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Routing_Slip::create: Unmarshalling failed for event.\n")
+ ));
+ }
+ }
+ delete event_mb;
+ delete rs_mb;
+
+ return result;
+}
+
+void
+Routing_Slip::set_rspm (Routing_Slip_Persistence_Manager * rspm)
+{
+ this->rspm_ = rspm;
+ if (rspm_ != 0)
+ {
+ rspm->set_callback (this);
+ }
+}
+
+Routing_Slip::Routing_Slip(
+ const TAO_Notify_Event_Ptr& event)
+ : is_safe_ (false)
+ , until_safe_ (internals_)
+ , this_ptr_ (0)
+ , event_(event)
+ , state_ (rssCREATING)
+ , complete_requests_ (0)
+ , rspm_ (0)
+{
+ Routing_Slip_Guard guard (sequence_lock_);
+ this->sequence_ = ++routing_slip_sequence_;
+ if (DEBUG_LEVEL > 1) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: constructor\n"),
+ this->sequence_
+ ));
+}
+
+Routing_Slip::~Routing_Slip ()
+{
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: destructor\n"),
+ this->sequence_
+ ));
+}
+
+bool
+Routing_Slip::create_persistence_manager()
+{
+ if (this->rspm_ == 0)
+ {
+ Event_Persistence_Strategy * strategy =
+ ACE_Dynamic_Service <TAO_NOTIFY::Event_Persistence_Strategy>::instance ("Event_Persistence");
+ if (strategy != 0)
+ {
+ Event_Persistence_Factory * factory = strategy->get_factory ();
+ if (factory != 0)
+ {
+ set_rspm (factory->create_routing_slip_persistence_manager(this));
+ }
+ }
+ }
+ return this->rspm_ != 0;
+}
+
+const TAO_Notify_Event_Ptr &
+Routing_Slip::event () const
+{
+ return this->event_;
+}
+
+void
+Routing_Slip::wait_persist ()
+{
+ Routing_Slip_Guard guard (this->internals_);
+ while (!this->is_safe_)
+ {
+ this->until_safe_.wait ();
+ }
+}
+
+void
+Routing_Slip::route (TAO_Notify_ProxyConsumer* pc, bool reliable_channel)
+{
+ ACE_ASSERT(pc != 0);
+
+ TAO_Notify_Refcountable_Guard pcgrd(*pc);
+
+ Routing_Slip_Guard guard (this->internals_);
+
+ size_t request_id = delivery_requests_.size ();
+
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: add Delivery_Request #%d: lookup, completed %d of %d\n"),
+ this->sequence_,
+ ACE_static_cast (int, request_id),
+ ACE_static_cast (int, this->complete_requests_),
+ ACE_static_cast (int, this->delivery_requests_.size ())
+ ));
+
+ Delivery_Request_Ptr request (new Delivery_Request (this->this_ptr_, request_id));
+ this->delivery_requests_.push_back (request);
+ Delivery_Method_Lookup method (request, pc);
+
+ if (this->state_ == rssCREATING)
+ {
+ if (! reliable_channel)
+ {
+ enter_state_transient (guard);
+ }
+ else if (ACE_Dynamic_Service <TAO_NOTIFY::Event_Persistence_Strategy>::instance ("Event_Persistence") == 0)
+ {
+ enter_state_transient (guard);
+ }
+ else if (! this->event_->reliable().is_valid())
+ {
+ enter_state_new (guard);
+ }
+ else if (this->event_->reliable().value() == CosNotification::Persistent)
+ {
+ enter_state_new (guard);
+ }
+ else
+ {
+ enter_state_transient (guard);
+ }
+ }
+ guard.release ();
+ pc->worker_task()->exec (method);
+}
+
+void
+Routing_Slip::dispatch (TAO_Notify_ProxySupplier* ps, bool filter)
+{
+ // cannot be the first action
+ ACE_ASSERT (this->state_ != rssCREATING);
+
+ TAO_Notify_Refcountable_Guard psgrd(*ps); //@@todo : Need to guard anything else?
+ Routing_Slip_Guard guard (this->internals_);
+
+ size_t request_id = delivery_requests_.size ();
+
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: add Delivery_Request #%d: Dispatch %s; completed %d of %d\n"),
+ this->sequence_,
+ ACE_static_cast (int, request_id),
+ filter ? ACE_TEXT ("Filter") : ACE_TEXT ("No Filter"),
+ ACE_static_cast (int, this->complete_requests_),
+ ACE_static_cast (int, this->delivery_requests_.size ())
+ ));
+
+ Delivery_Request_Ptr request (new Delivery_Request (this->this_ptr_, request_id));
+ if (! ps->has_shutdown() )
+ {
+ this->delivery_requests_.push_back (request);
+ Delivery_Method_Dispatch method (request, ps, filter);
+ guard.release ();
+ if (DEBUG_LEVEL > 8)
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) Routing Slip #%d: dispatching Delivery_Request %d to "
+ "proxy supplier %d\n",
+ this->sequence_,
+ ACE_static_cast (int, request_id),
+ ps->id()));
+ ps->worker_task()->exec (method);
+ }
+ else
+ {
+ if (DEBUG_LEVEL > 5)
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) Routing Slip #%d: not dispatching Delivery_Request %d to "
+ "proxy supplier %d; already shut down\n",
+ this->sequence_,
+ ACE_static_cast (int, request_id),
+ ps->id()));
+ }
+}
+
+//////////
+// signals
+
+void
+Routing_Slip::delivery_request_complete (size_t request_id)
+{
+ Routing_Slip_Guard guard (this->internals_);
+ ACE_ASSERT (request_id < this->delivery_requests_.size ());
+ // reset the pointer to allow the delivery_request to be deleted.
+ this->delivery_requests_[request_id].reset ();
+ this->complete_requests_ += 1;
+
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: delivery_request_complete #%d: completed %d of %d\n"),
+ this->sequence_,
+ ACE_static_cast (int, request_id),
+ ACE_static_cast (int, this->complete_requests_),
+ ACE_static_cast (int, this->delivery_requests_.size ())
+ ));
+ State state = this->state_;
+ switch (state)
+ {
+ case rssTRANSIENT:
+ {
+ continue_state_transient (guard);
+ break;
+ }
+ case rssNEW:
+ {
+ continue_state_new (guard);
+ break;
+ }
+ case rssSAVING:
+ {
+ enter_state_changed_while_saving (guard);
+ break;
+ }
+ case rssUPDATING:
+ {
+ enter_state_changed_while_saving (guard);
+ break;
+ }
+ case rssSAVED:
+ {
+ enter_state_changed (guard);
+ break;
+ }
+ case rssCHANGED_WHILE_SAVING:
+ {
+ continue_state_changed_while_saving (guard);
+ break;
+ }
+ case rssCHANGED:
+ {
+ continue_state_changed (guard);
+ break;
+ }
+ default:
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Notification Service Routing Slip: Unexpected delivery_request_complete in state %d\n"),
+ ACE_static_cast (int, this->state_)
+ ));
+ break;
+ }
+ }
+}
+
+void
+Routing_Slip::at_front_of_persist_queue ()
+{
+ Routing_Slip_Guard guard (this->internals_);
+ State state = this->state_;
+ switch (state)
+ {
+ case rssNEW:
+ {
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: NEW Reached front of queue\n"),
+ this->sequence_
+ ));
+ enter_state_saving (guard);
+ break;
+ }
+ case rssCOMPLETE_WHILE_NEW:
+ {
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: COMPLETE_WHILE_NEW Reached front of queue\n"),
+ this->sequence_
+ ));
+ this->persistent_queue_.complete ();
+ enter_state_terminal (guard);
+ break;
+ }
+ case rssCHANGED:
+ {
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: CHANGED Reached front of queue\n"),
+ this->sequence_
+ ));
+ enter_state_updating (guard);
+ break;
+ }
+ case rssCOMPLETE:
+ {
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: COMPLETE Reached front of queue\n"),
+ this->sequence_
+ ));
+ enter_state_deleting (guard);
+ break;
+ }
+ default:
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Routing Slip %d: Unexpected at_front_of_persist_queue in state %d\n"),
+ this->sequence_,
+ ACE_static_cast (int, this->state_)
+ ));
+ break;
+ }
+ }
+}
+
+void
+Routing_Slip::persist_complete ()
+{
+ // keep this object around til this method returns.
+ Routing_Slip_Ptr me(this->this_ptr_);
+ Routing_Slip_Guard guard (this->internals_);
+ ACE_ASSERT (guard.locked ());
+
+ // allow the ConsumerProxy to return from the CORBA push call.
+ if (! is_safe_)
+ {
+ is_safe_ = true;
+ this->until_safe_.signal ();
+ }
+
+ State state = this->state_;
+ switch (state)
+ {
+ case rssSAVING:
+ {
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: SAVING persist complete\n"),
+ this->sequence_
+ ));
+ enter_state_saved(guard);
+ break;
+ }
+ case rssCHANGED_WHILE_SAVING:
+ {
+ enter_state_changed (guard);
+ break;
+ }
+ case rssUPDATING:
+ {
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: UPDATING persist complete\n"),
+ this->sequence_
+ ));
+ enter_state_saved (guard);
+ break;
+ }
+ case rssDELETING:
+ {
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: DELETING persist complete\n"),
+ this->sequence_
+ ));
+ enter_state_terminal (guard);
+ break;
+ }
+ default:
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Notification Service Routing Slip: Unexpected transition in state %d\n"),
+ ACE_static_cast (int, this->state_)
+ ));
+ break;
+ }
+ }
+ this->persistent_queue_.complete ();
+}
+
+//////////////////
+// support methods
+
+bool
+Routing_Slip::all_deliveries_complete () const
+{
+ return this->complete_requests_ == this->delivery_requests_.size ();
+}
+
+void
+Routing_Slip::add_to_persist_queue(Routing_Slip_Guard & guard)
+{
+ guard.release ();
+ this->persistent_queue_.add (this->this_ptr_);
+ guard.acquire (); // necessary?
+}
+
+////////////////////
+// State transitions
+
+void
+Routing_Slip::enter_state_new (Routing_Slip_Guard & guard)
+{
+ ++count_enter_new_;
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state NEW\n"),
+ this->sequence_
+ ));
+ this->state_ = rssNEW;
+ add_to_persist_queue(guard);
+}
+
+void
+Routing_Slip::continue_state_new (Routing_Slip_Guard & guard)
+{
+ ++count_continue_new_;
+ if (all_deliveries_complete ())
+ {
+ this->enter_state_complete_while_new (guard);
+ }
+}
+void
+Routing_Slip::enter_state_complete_while_new (Routing_Slip_Guard & guard)
+{
+ ++count_enter_complete_while_new_;
+ ACE_UNUSED_ARG (guard);
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state COMPLETE_WHILE_NEW\n"),
+ this->sequence_
+ ));
+ // allow the ConsumerProxy to return from the CORBA push call.
+ if (! is_safe_)
+ {
+ is_safe_ = true;
+ this->until_safe_.signal ();
+ }
+ this->state_ = rssCOMPLETE_WHILE_NEW;
+}
+
+void
+Routing_Slip::enter_state_reloaded (Routing_Slip_Guard & guard)
+{
+ ++count_enter_reloaded_;
+ ACE_UNUSED_ARG (guard);
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #&d: enter state RELOADED\n"),
+ this->sequence_
+ ));
+ this->state_ = rssRELOADED;
+}
+
+void
+Routing_Slip::enter_state_transient (Routing_Slip_Guard & guard)
+{
+ ++count_enter_transient_;
+ ACE_UNUSED_ARG (guard);
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state TRANSIENT\n"),
+ this->sequence_
+ ));
+ this->state_ = rssTRANSIENT;
+ if (! is_safe_)
+ {
+ is_safe_ = true;
+ this->until_safe_.signal ();
+ }
+ if (all_deliveries_complete ())
+ {
+ enter_state_terminal (guard);
+ }
+}
+
+void
+Routing_Slip::continue_state_transient (Routing_Slip_Guard & guard)
+{
+ ++count_continue_transient_;
+ if (all_deliveries_complete ())
+ {
+ enter_state_terminal (guard);
+ }
+}
+void
+Routing_Slip::enter_state_saving (Routing_Slip_Guard & guard)
+{
+ ++count_enter_saving_;
+ if (!create_persistence_manager ())
+ {
+ // Note This should actually be a throw (out of memory)
+ // but we cheat and make this a transient event.
+ this->persistent_queue_.complete ();
+ enter_state_transient (guard);
+ }
+ else
+ {
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state SAVING\n"),
+ this->sequence_
+ ));
+ this->state_ = rssSAVING;
+
+ TAO_OutputCDR event_cdr;
+ this->event_->marshal (event_cdr);
+
+ const ACE_Message_Block *event_mb = event_cdr.begin ();
+ TAO_OutputCDR rs_cdr;
+ marshal (rs_cdr);
+ const ACE_Message_Block *rs_mb = rs_cdr.begin ();
+
+ guard.release ();
+ this->rspm_->store (*event_mb, *rs_mb);
+
+ guard.acquire (); // necessary?
+ }
+}
+
+void
+Routing_Slip::enter_state_saved (Routing_Slip_Guard & guard)
+{
+ ++count_enter_saved_;
+ ACE_UNUSED_ARG (guard);
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state SAVED\n"),
+ this->sequence_
+ ));
+ this->state_ = rssSAVED;
+}
+
+void
+Routing_Slip::enter_state_updating (Routing_Slip_Guard & guard)
+{
+ ++count_enter_updating_;
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state UPDATING\n"),
+ this->sequence_
+ ));
+ this->state_ = rssUPDATING;
+
+ TAO_OutputCDR rs_cdr;
+ marshal (rs_cdr);
+ const ACE_Message_Block *rs_mb = rs_cdr.begin ();
+ guard.release ();
+
+ ACE_ASSERT (this->rspm_ != 0);
+ this->rspm_->update (*rs_mb);
+ guard.acquire (); // necessary?
+}
+
+
+void
+Routing_Slip::enter_state_changed_while_saving (Routing_Slip_Guard & guard)
+{
+ ++count_enter_changed_while_saving_;
+ ACE_UNUSED_ARG (guard);
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state CHANGED_WHILE_SAVING\n"),
+ this->sequence_
+ ));
+ this->state_ = rssCHANGED_WHILE_SAVING;
+}
+
+void
+Routing_Slip::continue_state_changed_while_saving (Routing_Slip_Guard & guard)
+{
+ ACE_UNUSED_ARG (guard);
+ // no action necessary
+}
+
+void
+Routing_Slip::enter_state_changed (Routing_Slip_Guard & guard)
+{
+ ++count_enter_changed_;
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state CHANGED\n"),
+ this->sequence_
+ ));
+ // complete state change BEFORE initiating request to avoid
+ // race condition if request finishes before state is stable.
+ this->state_ = rssCHANGED;
+ if (all_deliveries_complete ())
+ {
+ enter_state_complete (guard);
+ }
+ add_to_persist_queue (guard);
+}
+
+void
+Routing_Slip::continue_state_changed (Routing_Slip_Guard & guard)
+{
+ ++count_continue_changed_;
+ if (all_deliveries_complete ())
+ {
+ enter_state_complete (guard);
+ }
+}
+
+void
+Routing_Slip::enter_state_complete (Routing_Slip_Guard & guard)
+{
+ ++count_enter_complete_;
+ ACE_UNUSED_ARG (guard);
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state COMPLETE\n"),
+ this->sequence_
+ ));
+ this->state_ = rssCOMPLETE;
+}
+
+void
+Routing_Slip::enter_state_deleting (Routing_Slip_Guard & guard)
+{
+ ++count_enter_deleting_;
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state DELETING\n"),
+ this->sequence_
+ ));
+ this->state_ = rssDELETING;
+ guard.release ();
+ this->rspm_->remove ();
+ guard.acquire (); // necessary?
+}
+
+void
+Routing_Slip::enter_state_terminal (Routing_Slip_Guard & guard)
+{
+ ++count_enter_terminal_;
+ ACE_UNUSED_ARG (guard);
+ ACE_ASSERT( this->is_safe_);
+ if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state TERMINAL\n"),
+ this->sequence_
+ ));
+ this->state_ = rssTERMINAL;
+ this->this_ptr_.reset ();
+}
+
+void
+Routing_Slip::marshal (TAO_OutputCDR & cdr)
+{
+ size_t request_count = this->delivery_requests_.size();
+ cdr.write_ulong (request_count - this->complete_requests_);
+ for (size_t nreq = 0; nreq < request_count; ++nreq)
+ {
+ Delivery_Request * request = this->delivery_requests_[nreq].get ();
+ if (request != 0)
+ {
+ request->marshal (cdr);
+ }
+ }
+}
+
+bool
+Routing_Slip::unmarshal (TAO_Notify_EventChannelFactory &ecf, TAO_InputCDR & cdr)
+{
+ CORBA::ULong count = 0;
+ cdr.read_ulong (count);
+ for (size_t nreq = 0; nreq < count; ++nreq)
+ {
+ ACE_CDR::Octet code = 0;
+ while (cdr.read_octet(code))
+ {
+ ACE_TRY_NEW_ENV
+ {
+ if (code == Delivery_Method_Dispatch::persistence_code)
+ {
+ Delivery_Request_Ptr request(new Delivery_Request(this_ptr_, this->delivery_requests_.size ()));
+ Delivery_Method * method = Delivery_Method_Dispatch::create (
+ request,
+ ecf,
+ cdr
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ if (method != 0)
+ {
+ this->delivery_requests_.push_back (request);
+ this->delivery_methods_.push_back (method);
+ }
+ }
+ else if (code == Delivery_Method_Lookup::persistence_code)
+ {
+ Delivery_Request_Ptr request(new Delivery_Request(this_ptr_, this->delivery_requests_.size ()));
+ Delivery_Method * method = Delivery_Method_Lookup::create (
+ request,
+ ecf,
+ cdr
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK
+ if (method != 0)
+ {
+ this->delivery_requests_.push_back (request);
+ this->delivery_methods_.push_back (method);
+ }
+ }
+ }
+ ACE_CATCHANY;
+ {
+ // @@todo should we log this?
+ // just ignore failures
+ }
+ ACE_ENDTRY;
+ }
+ }
+ return this->delivery_requests_.size () > 0;
+}
+
+void
+Routing_Slip::reconnect (ACE_ENV_SINGLE_ARG_DECL)
+{
+ Routing_Slip_Guard guard (this->internals_);
+ enter_state_saved (guard);
+ guard.release ();
+ //@@todo is there a worker_task available to do this?
+ size_t count = this->delivery_methods_.size ();
+ for (size_t nmethod = 0; nmethod < count; ++nmethod)
+ {
+ this->delivery_methods_[nmethod] ->execute (TAO_Notify_Method_Request::EXECUTE ACE_ENV_ARG_PARAMETER);
+ }
+ this->delivery_methods_.clear ();
+}
+
+int
+Routing_Slip::sequence() const
+{
+ return this->sequence_;
+}
+
+bool
+Routing_Slip::should_retry () const
+{
+ // simple minded test: if it's transient, don't retry it
+ // @@todo Eventually this should check timeout, discard policy, etc.
+ return this->state_ != rssTRANSIENT;
+}
+
+
+
+} // namespace
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Auto_Basic_Ptr<TAO_NOTIFY::Routing_Slip>;
+template class ACE_Strong_Bound_Ptr<TAO_NOTIFY::Routing_Slip, TAO_SYNCH_MUTEX>;
+template class ACE_Auto_Basic_Ptr<TAO_NOTIFY::Delivery_Request>;
+template class ACE_Strong_Bound_Ptr<TAO_NOTIFY::Delivery_Request,TAO_SYNCH_MUTEX>;
+template class ACE_Vector <TAO_NOTIFY::Delivery_Request_Ptr>;
+template class ACE_Array_Base<ACE_Strong_Bound_Ptr<TAO_NOTIFY::Delivery_Request,TAO_SYNCH_MUTEX> >;
+template class ACE_Vector <TAO_NOTIFY::Delivery_Request *>;
+template class ACE_Array_Base<TAO_NOTIFY::Delivery_Request *>;
+template class ACE_Dynamic_Service <TAO_NOTIFY::Event_Persistence_Strategy>;
+template class ACE_Array_Base<TAO_NOTIFY::Delivery_Method*>;
+template class ACE_Vector<TAO_NOTIFY::Delivery_Method*>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Auto_Basic_Ptr<TAO_NOTIFY::Routing_Slip>
+#pragma instantiate ACE_Strong_Bound_Ptr<TAO_NOTIFY::Routing_Slip,TAO_SYNCH_MUTEX>
+#pragma instantiate ACE_Auto_Basic_Ptr<TAO_NOTIFY::Delivery_Request>
+#pragma instantiate ACE_Strong_Bound_Ptr<TAO_NOTIFY::Delivery_Request,TAO_SYNCH_MUTEX>
+#pragma instantiate ACE_Vector <TAO_NOTIFY::Delivery_Request_Ptr>
+#pragma instantiate ACE_Array_Base<ACE_Strong_Bound_Ptr<TAO_NOTIFY::Delivery_Request,TAO_SYNCH_MUTEX> >
+#pragma instantiate ACE_Vector <TAO_NOTIFY::Delivery_Request *>
+#pragma instantiate ACE_Array_Base<TAO_NOTIFY::Delivery_Request *>
+#pragma instantiate ACE_Dynamic_Service <TAO_NOTIFY::Event_Persistence_Strategy>
+#pragma instantiate ACE_Array_Base<TAO_NOTIFY::Delivery_Method*>
+#pragma instantiate ACE_Vector<TAO_NOTIFY::Delivery_Method*>
+#endif /*ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip.h b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip.h
new file mode 100644
index 00000000000..477f6117d37
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip.h
@@ -0,0 +1,241 @@
+/* -*- C++ -*- */
+/**
+ * @file Routing_Slip.h
+ *
+ * $Id$
+ *
+ * @author Dale Wilson <wilson_d@ociweb.com>
+ *
+ *
+ */
+
+#ifndef TAO_NOTIFY_ROUTING_SLIP_H
+#define TAO_NOTIFY_ROUTING_SLIP_H
+#include "ace/pre.h"
+
+#include "notify_export.h"
+#include "Event.h"
+#include "Types.h"
+#include "Delivery_Request.h"
+#include "Event_Persistence_Factory.h"
+
+#include "Persistent_File_Allocator.h" // for Persistent_Callback
+
+#include <ace/Vector_T.h>
+#include <ace/Malloc_Base.h> // necessary?
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Forward declarations of classes/pointers/collections
+// referenced from this header
+class TAO_Notify_EventChannelFactory;
+class TAO_Notify_Method_Request;
+
+namespace TAO_NOTIFY
+{
+
+class TAO_Notify_Export Routing_Slip_Persistence_Manager;
+
+// Forward declarations of TAO_NOTIFY classes/pointers/collections
+// referenced from this header
+
+/// A vector of Delivery Requests. The body of a Routing_Slip.
+typedef ACE_Vector <Delivery_Request_Ptr> Delivery_Request_Vec;
+
+class Delivery_Method;
+/// A vector of Delivery_Methods. Used during recovery.
+typedef ACE_Vector <Delivery_Method *> Delivery_Method_Vec;
+
+class Routing_Slip;
+/// A reference-counted smart pointer to a Routing_Slip
+typedef ACE_Strong_Bound_Ptr<Routing_Slip, TAO_SYNCH_MUTEX> Routing_Slip_Ptr;
+
+class Routing_Slip_Persistence_Manager;
+
+class Routing_Slip_Queue;
+
+/**
+ * \brief Class which manages the delivery of events to destination.
+ *
+ * Interacts with persistent storage to provide reliable delivery.
+ */
+class TAO_Notify_Export Routing_Slip : public Persistent_Callback
+{
+ typedef ACE_Guard< TAO_SYNCH_MUTEX > Routing_Slip_Guard;
+public:
+ /// "Factory" method for normal use.
+ static Routing_Slip_Ptr create (const TAO_Notify_Event_Ptr& event);
+
+ /// "Factory" method for use during reload from persistent storage.
+ static Routing_Slip_Ptr create (
+ TAO_Notify_EventChannelFactory & ecf,
+ Routing_Slip_Persistence_Manager * rspm);
+
+ void set_rspm (Routing_Slip_Persistence_Manager * rspm);
+
+ void reconnect (ACE_ENV_SINGLE_ARG_DECL);
+
+ /// destructor (should be private but that inspires compiler wars)
+ virtual ~Routing_Slip ();
+
+ //////////////////
+ // Action requests
+
+ /// Route this event to destinations
+ /// must be the Action request after
+ /// the routing slip is created.
+ void route (TAO_Notify_ProxyConsumer* pc, bool reliable_channel);
+
+ /// \brief Schedule delivery to a consumer via a proxy supplier
+ /// \param proxy_supplier the proxy supplier that will deliver the event
+ /// \param filter should consumer-based filtering be applied?
+ /// \param a task to use for this work.
+ void dispatch (TAO_Notify_ProxySupplier * proxy_supplier, bool filter);
+
+ /////////////////////////////////////////
+ /// \brief Wait until the event/routing_slip has
+ /// been saved at least once.
+ void wait_persist ();
+
+ /////////////////////////////////////
+ // signals from the rest of the world
+
+ /// \brief A delivery request has been satisfied.
+ void delivery_request_complete (size_t request_id);
+
+ /// \brief This Routing_Slip reached the front of the persistence queue
+ void at_front_of_persist_queue ();
+
+ /// \brief The persistent storage has completed the last request.
+ virtual void persist_complete ();
+
+ /////////////////////////////////////////////////////
+ // \brief Access the event associated with this routing slip
+ const TAO_Notify_Event_Ptr & event () const;
+
+ /// \brief Provide an identifying number for this Routing Slip
+ /// to use in debug messages.
+ int sequence() const;
+
+ /// \brief Should delivery of this event be retried if it fails?
+ bool should_retry () const;
+
+private:
+ ////////////////////
+ // state transitions
+ void enter_state_transient (Routing_Slip_Guard & guard);
+ void continue_state_transient (Routing_Slip_Guard & guard);
+ void enter_state_reloaded (Routing_Slip_Guard & guard);
+ void enter_state_new (Routing_Slip_Guard & guard);
+ void continue_state_new (Routing_Slip_Guard & guard);
+ void enter_state_complete_while_new (Routing_Slip_Guard & guard);
+ void enter_state_saving (Routing_Slip_Guard & guard);
+ void enter_state_saved (Routing_Slip_Guard & guard);
+ void enter_state_updating (Routing_Slip_Guard & guard);
+ void enter_state_changed_while_saving (Routing_Slip_Guard & guard);
+ void continue_state_changed_while_saving (Routing_Slip_Guard & guard);
+ void enter_state_changed (Routing_Slip_Guard & guard);
+ void continue_state_changed (Routing_Slip_Guard & guard);
+ void enter_state_complete (Routing_Slip_Guard & guard);
+ void enter_state_deleting (Routing_Slip_Guard & guard);
+ void enter_state_terminal (Routing_Slip_Guard & guard);
+
+private:
+ bool create_persistence_manager();
+
+ /// Private constructor for use by create method
+ Routing_Slip(const TAO_Notify_Event_Ptr& event);
+
+ /// Test to see if all deliveries are complete.
+ bool all_deliveries_complete () const;
+
+ /// This routing_slip needs to be saved.
+ void add_to_persist_queue(Routing_Slip_Guard & guard);
+
+ /// Marshal into a CDR
+ void marshal (TAO_OutputCDR & cdr);
+
+ /// Marshal from CDR
+ bool unmarshal (TAO_Notify_EventChannelFactory &ecf, TAO_InputCDR & rscdr);
+
+private:
+ /// Protection for internal information
+ TAO_SYNCH_MUTEX internals_;
+ /// true when event persistence qos is guaranteed
+ bool is_safe_;
+ /// signalled when is_safe_ goes true
+ ACE_SYNCH_CONDITION until_safe_;
+
+ /// Smart pointer to this object
+ /// Provides continuity between smart pointers and "Routing_Slip::this"
+ /// Also lets the Routing_Slip manage its own minimum lifetime.
+ Routing_Slip_Ptr this_ptr_;
+
+ // The event being delivered.
+ TAO_Notify_Event_Ptr event_;
+
+ /// A mini-state machine to control persistence
+ /// See external doc for circles and arrows.
+ enum State
+ {
+ rssCREATING,
+ rssTRANSIENT,
+ rssRELOADED,
+ rssNEW,
+ rssCOMPLETE_WHILE_NEW,
+ rssSAVING,
+ rssSAVED,
+ rssUPDATING,
+ rssCHANGED_WHILE_SAVING,
+ rssCHANGED,
+ rssCOMPLETE,
+ rssDELETING,
+ rssTERMINAL
+ } state_;
+
+ /// A collection of delivery requests
+ Delivery_Request_Vec delivery_requests_;
+
+ /// Methods that should be restarted during event recovery
+ Delivery_Method_Vec delivery_methods_;
+
+ /// How many delivery requests are complete
+ size_t complete_requests_;
+
+ /// Pointer to a Routing_Slip_Persistence_Manager
+ Routing_Slip_Persistence_Manager * rspm_;
+
+ int sequence_;
+
+ static TAO_SYNCH_MUTEX sequence_lock_;
+ static int routing_slip_sequence_;
+ static size_t count_enter_transient_;
+ static size_t count_continue_transient_;
+ static size_t count_enter_reloaded_;
+ static size_t count_enter_new_;
+ static size_t count_continue_new_;
+ static size_t count_enter_complete_while_new_;
+ static size_t count_enter_saving_;
+ static size_t count_enter_saved_;
+ static size_t count_enter_updating_;
+ static size_t count_enter_changed_while_saving_;
+ static size_t count_continue_changed_while_saving_;
+ static size_t count_enter_changed_;
+ static size_t count_continue_changed_;
+ static size_t count_enter_complete_;
+ static size_t count_enter_deleting_;
+ static size_t count_enter_terminal_;
+
+ static Routing_Slip_Queue persistent_queue_;
+};
+
+} // namespace
+
+#if defined (__ACE_INLINE__)
+#include "Routing_Slip.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* TAO_NOTIFY_ROUTING_SLIP_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.cpp b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.cpp
new file mode 100644
index 00000000000..dfb67f4f7ec
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.cpp
@@ -0,0 +1,803 @@
+// $Id$
+
+#include "Routing_Slip_Persistence_Manager.h"
+#include "Standard_Event_Persistence.h"
+#include "Persistent_File_Allocator.h"
+
+namespace TAO_NOTIFY
+{
+
+Routing_Slip_Persistence_Manager::Routing_Slip_Persistence_Manager(
+ Standard_Event_Persistence_Factory* factory)
+ : removed_(false)
+ , serial_number_(0)
+ , allocator_(factory->allocator())
+ , factory_(factory)
+ , first_event_block_(0)
+ , first_routing_slip_block_(0)
+ , callback_(0)
+ , event_mb_ (0)
+ , routing_slip_mb_(0)
+{
+ this->prev_manager_ = this;
+ this->next_manager_ = this;
+}
+
+Routing_Slip_Persistence_Manager::~Routing_Slip_Persistence_Manager()
+{
+ ACE_ASSERT(this->prev_manager_ == this);
+ ACE_ASSERT(this->next_manager_ == this);
+ delete this->first_event_block_;
+ this->first_event_block_ = 0;
+ delete this->first_routing_slip_block_;
+ this->first_routing_slip_block_ = 0;
+ delete this->event_mb_;
+ this->event_mb_ = 0;
+ delete this->routing_slip_mb_;
+ this->routing_slip_mb_ = 0;
+}
+
+void
+Routing_Slip_Persistence_Manager::set_callback(Persistent_Callback* callback)
+{
+ ACE_GUARD(ACE_SYNCH_MUTEX, ace_mon, this->lock_);
+ this->callback_ = callback;
+}
+
+bool
+Routing_Slip_Persistence_Manager::store_root()
+{
+ bool result = false;
+
+ this->factory_->get_preallocated_pointer (
+ this->routing_slip_header_.next_serial_number,
+ this->routing_slip_header_.next_routing_slip_block);
+
+ // we should already have a psb, but JIC
+ ACE_ASSERT(this->first_routing_slip_block_ != 0);
+ ACE_ASSERT(this->first_routing_slip_block_->block_number() ==
+ ROUTING_SLIP_ROOT_BLOCK_NUMBER);
+
+ // Don't take any chances. Use hard-wired root serial number.
+ this->routing_slip_header_.serial_number = ROUTING_SLIP_ROOT_SERIAL_NUMBER;
+
+ // This will eventually break after something like 58000 years.
+ // At such time we should change this to !=.
+ ACE_ASSERT(this->routing_slip_header_.next_serial_number >
+ ROUTING_SLIP_ROOT_SERIAL_NUMBER);
+
+ ACE_Message_Block versioninfo(2);
+ versioninfo.wr_ptr()[0] = 1; // Major version number
+ versioninfo.wr_ptr()[1] = 0; // Minor version number
+ versioninfo.wr_ptr(2);
+ ACE_GUARD_RETURN(ACE_SYNCH_MUTEX, ace_mon, this->lock_, result);
+ result = this->build_chain(this->first_routing_slip_block_,
+ this->routing_slip_header_, this->allocated_routing_slip_blocks_,
+ versioninfo);
+ if (result)
+ {
+ this->routing_slip_header_.put_header(*this->first_routing_slip_block_);
+ this->allocator_->write(this->first_routing_slip_block_);
+ }
+ return result;
+}
+
+bool
+Routing_Slip_Persistence_Manager::reload(
+ ACE_Message_Block*& event,
+ ACE_Message_Block*& routing_slip)
+{
+ bool result = false;
+ if (this->event_mb_ != 0 && this->routing_slip_mb_ != 0)
+ {
+ event = this->event_mb_;
+ this->event_mb_ = 0;
+ routing_slip = this->routing_slip_mb_;
+ this->routing_slip_mb_ = 0;
+ result = true;
+ }
+ else
+ {
+ event = 0;
+ routing_slip = 0;
+ }
+ return result;
+}
+
+bool
+Routing_Slip_Persistence_Manager::load(
+ Block_Number block_number,
+ Block_Serial_Number expected_serial_number)
+{
+ /**
+ * NOTE: There is no need to worry about guarding anything. We assume
+ * that there will be one and only one thread doing the entire
+ * reload process.
+ */
+ bool result = false;
+ size_t block_size = this->allocator_->block_size();
+ this->first_routing_slip_block_ =
+ this->allocator_->allocate_at(block_number);
+ this->first_routing_slip_block_->set_allocator_owns(false);
+ this->first_routing_slip_block_->set_sync();
+
+ this->serial_number_ = expected_serial_number;
+
+ ACE_NEW_NORETURN(this->routing_slip_mb_, ACE_Message_Block(block_size));
+ ACE_NEW_NORETURN(this->event_mb_, ACE_Message_Block(block_size));
+ if (this->event_mb_ != 0 && this->routing_slip_mb_ != 0)
+ {
+ if (this->reload_chain(
+ this->first_routing_slip_block_,
+ this->routing_slip_header_,
+ this->allocated_routing_slip_blocks_,
+ this->routing_slip_mb_,
+ expected_serial_number))
+ {
+ if (this->routing_slip_header_.event_block != 0)
+ {
+ this->first_event_block_ = this->allocator_->allocate_at(
+ this->routing_slip_header_.event_block);
+ result = this->reload_chain(
+ this->first_event_block_,
+ this->event_header_,
+ this->allocated_event_blocks_,
+ this->event_mb_,
+ 0);
+ }
+ else if (block_number == ROUTING_SLIP_ROOT_BLOCK_NUMBER)
+ {
+ // only the root can lack event
+ result = true;
+ }
+ else
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT(
+ "(%P|%t) Reloaded Persistent Event is missing event.\n")
+ ));
+ }
+ }
+ }
+ if (! result)
+ {
+ delete this->routing_slip_mb_;
+ this->routing_slip_mb_ = 0;
+ delete this->event_mb_;
+ this->event_mb_ = 0;
+ }
+ return result;
+}
+
+Routing_Slip_Persistence_Manager *
+Routing_Slip_Persistence_Manager::load_next ()
+{
+ Routing_Slip_Persistence_Manager * result;
+ ACE_NEW_RETURN(result, Routing_Slip_Persistence_Manager (this->factory_), 0);
+
+ if (result->load(this->routing_slip_header_.next_routing_slip_block,
+ this->routing_slip_header_.next_serial_number))
+ {
+ result->dllist_push_back();
+ }
+ else
+ {
+ // steal the psb for use as the next psb.
+ // delete the rspm. We'll create another one later.
+ Persistent_Storage_Block * next_psb = result->first_routing_slip_block_;
+ result->first_routing_slip_block_ = 0;
+// next_psb->set_allocator_owns(true);
+ this->factory_->done_reloading (
+ next_psb,
+ result->serial_number_);
+ delete result;
+ result = 0;
+ }
+ return result;
+}
+
+bool
+Routing_Slip_Persistence_Manager::store(const ACE_Message_Block& event,
+ const ACE_Message_Block& routing_slip)
+{
+ bool result = false;
+ ACE_GUARD_RETURN(ACE_SYNCH_MUTEX, ace_mon, this->lock_, result);
+ if (!this->removed_)
+ {
+ result = store_i(event, routing_slip);
+ }
+ return result;
+}
+
+bool
+Routing_Slip_Persistence_Manager::update(const ACE_Message_Block& routing_slip)
+{
+ bool result = false;
+ ACE_GUARD_RETURN(ACE_SYNCH_MUTEX, ace_mon, this->lock_, result);
+ // If we have not gotten the event yet or we have no allocator, fail
+ if (!this->removed_)
+ {
+ if (this->persisted())
+ {
+ result = update_i(routing_slip);
+ }
+ }
+ return result;
+}
+
+bool
+Routing_Slip_Persistence_Manager::remove()
+{
+ bool result = false;
+ ACE_GUARD_RETURN(ACE_SYNCH_MUTEX, ace_mon, this->lock_, result);
+ // Assert that this is in the dllist
+ ACE_ASSERT(this->prev_manager_ != this);
+ ACE_ASSERT(this->persisted());
+ Routing_Slip_Persistence_Manager* prev = this->prev_manager_;
+ // Once our previous manager removes us, we can deallocate in any order
+ this->factory_->lock.acquire();
+ this->remove_from_dllist();
+ result = prev->update_next_manager(this);
+ this->factory_->lock.release();
+ size_t block_number = 0;
+ if (this->first_routing_slip_block_ != 0)
+ {
+ this->allocator_->free(this->first_routing_slip_block_->block_number());
+ delete this->first_routing_slip_block_;
+ this->first_routing_slip_block_ = 0;
+ }
+ if (this->first_event_block_ != 0)
+ {
+ this->allocator_->free(this->first_event_block_->block_number());
+ delete this->first_event_block_;
+ this->first_event_block_ = 0;
+ }
+ while (this->allocated_routing_slip_blocks_.pop(block_number) == 0)
+ {
+ this->allocator_->free(block_number);
+ }
+ while (this->allocated_event_blocks_.pop(block_number) == 0)
+ {
+ this->allocator_->free(block_number);
+ }
+ this->removed_ = true;
+ Persistent_Storage_Block* callbackblock =
+ this->allocator_->allocate_nowrite();
+ callbackblock->set_callback(this->callback_);
+ result &= this->allocator_->write(callbackblock);
+ return result;
+}
+
+Routing_Slip_Persistence_Manager::Block_Header::Block_Header(Header_Type type)
+ : serial_number (0)
+ , next_overflow(0)
+ , header_type (ACE_static_cast (Block_Type, type))
+ , data_size(0)
+{
+}
+
+size_t
+Routing_Slip_Persistence_Manager::Block_Header::extract_header(
+ Persistent_Storage_Block& psb, const size_t offset)
+{
+ size_t pos = offset;
+ unsigned char* data = psb.data();
+
+ serial_number = data[pos++];
+ serial_number = (serial_number << 8) + data[pos++];
+ serial_number = (serial_number << 8) + data[pos++];
+ serial_number = (serial_number << 8) + data[pos++];
+ serial_number = (serial_number << 8) + data[pos++];
+ serial_number = (serial_number << 8) + data[pos++];
+ serial_number = (serial_number << 8) + data[pos++];
+ serial_number = (serial_number << 8) + data[pos++];
+
+ next_overflow = data[pos++];
+ next_overflow = (next_overflow << 8) + data[pos++];
+ next_overflow = (next_overflow << 8) + data[pos++];
+ next_overflow = (next_overflow << 8) + data[pos++];
+
+ header_type = data[pos++];
+ header_type = (data_size << 8) + data[pos++];
+
+ data_size = data[pos++];
+ data_size = (data_size << 8) + data[pos++];
+ return pos;
+}
+
+size_t
+Routing_Slip_Persistence_Manager::Block_Header::put_header(
+ Persistent_Storage_Block& psb, size_t offset)
+{
+ // Assume that our psb can hold our small amount of data...
+ size_t pos = offset;
+ unsigned char* data = psb.data();
+ // Store serial_number
+ data[pos++] = ACE_static_cast (unsigned char, (serial_number >> 56) & 0xff);
+ data[pos++] = ACE_static_cast (unsigned char, (serial_number >> 48) & 0xff);
+ data[pos++] = ACE_static_cast (unsigned char, (serial_number >> 40) & 0xff);
+ data[pos++] = ACE_static_cast (unsigned char, (serial_number >> 32) & 0xff);
+ data[pos++] = ACE_static_cast (unsigned char, (serial_number >> 24) & 0xff);
+ data[pos++] = ACE_static_cast (unsigned char, (serial_number >> 16) & 0xff);
+ data[pos++] = ACE_static_cast (unsigned char, (serial_number >> 8) & 0xff);
+ data[pos++] = ACE_static_cast (unsigned char, (serial_number >> 0) & 0xff);
+ // Store next_overflow
+ data[pos++] = next_overflow >> 24;
+ data[pos++] = (next_overflow >> 16) & 0xff;
+ data[pos++] = (next_overflow >> 8) & 0xff;
+ data[pos++] = next_overflow & 0xff;
+ // Store header_type
+ data[pos++] = (header_type >> 8) & 0xff;
+ data[pos++] = header_type & 0xff;
+ // Store data_size
+ data[pos++] = (data_size >> 8) & 0xff;
+ data[pos++] = data_size & 0xff;
+
+ return pos;
+}
+
+Routing_Slip_Persistence_Manager::Routing_Slip_Header::Routing_Slip_Header()
+ : Block_Header (BT_Event)
+ , next_routing_slip_block(0)
+ , next_serial_number(0)
+ , event_block(0)
+{
+}
+
+size_t
+Routing_Slip_Persistence_Manager::Routing_Slip_Header::extract_header(
+ Persistent_Storage_Block& psb, const size_t offset)
+{
+ size_t pos = offset;
+ pos = this->Block_Header::extract_header(psb, pos);
+ unsigned char* data = psb.data();
+ next_routing_slip_block = data[pos++];
+ next_routing_slip_block = (next_routing_slip_block << 8) + data[pos++];
+ next_routing_slip_block = (next_routing_slip_block << 8) + data[pos++];
+ next_routing_slip_block = (next_routing_slip_block << 8) + data[pos++];
+ next_serial_number = data[pos++];
+ next_serial_number = (next_serial_number << 8) + data[pos++];
+ next_serial_number = (next_serial_number << 8) + data[pos++];
+ next_serial_number = (next_serial_number << 8) + data[pos++];
+ next_serial_number = (next_serial_number << 8) + data[pos++];
+ next_serial_number = (next_serial_number << 8) + data[pos++];
+ next_serial_number = (next_serial_number << 8) + data[pos++];
+ next_serial_number = (next_serial_number << 8) + data[pos++];
+ event_block = data[pos++];
+ event_block = (event_block << 8) + data[pos++];
+ event_block = (event_block << 8) + data[pos++];
+ event_block = (event_block << 8) + data[pos++];
+ return pos;
+}
+
+size_t
+Routing_Slip_Persistence_Manager::Routing_Slip_Header::put_header(
+ Persistent_Storage_Block& psb, const size_t offset)
+{
+ // Assume that our psb can hold our small amount of data...
+ size_t pos = offset;
+ // Store serial number, next_overflow and data_size
+ pos = this->Block_Header::put_header(psb, pos);
+
+ unsigned char* data = psb.data();
+ // Store next_routing_slip_block
+ data[pos++] = next_routing_slip_block >> 24;
+ data[pos++] = (next_routing_slip_block >> 16) & 0xff;
+ data[pos++] = (next_routing_slip_block >> 8) & 0xff;
+ data[pos++] = next_routing_slip_block & 0xff;
+ // Store serial_number
+ data[pos++] = ACE_static_cast (unsigned char, (next_serial_number >> 56) & 0xff);
+ data[pos++] = ACE_static_cast (unsigned char, (next_serial_number >> 48) & 0xff);
+ data[pos++] = ACE_static_cast (unsigned char, (next_serial_number >> 40) & 0xff);
+ data[pos++] = ACE_static_cast (unsigned char, (next_serial_number >> 32) & 0xff);
+ data[pos++] = ACE_static_cast (unsigned char, (next_serial_number >> 24) & 0xff);
+ data[pos++] = ACE_static_cast (unsigned char, (next_serial_number >> 16) & 0xff);
+ data[pos++] = ACE_static_cast (unsigned char, (next_serial_number >> 8) & 0xff);
+ data[pos++] = ACE_static_cast (unsigned char, (next_serial_number >> 0) & 0xff);
+ // Store event_block
+ data[pos++] = event_block >> 24;
+ data[pos++] = (event_block >> 16) & 0xff;
+ data[pos++] = (event_block >> 8) & 0xff;
+ data[pos++] = event_block & 0xff;
+ return pos;
+}
+
+Routing_Slip_Persistence_Manager::Overflow_Header::Overflow_Header ()
+ : Block_Header (BT_Overflow)
+{
+}
+
+Routing_Slip_Persistence_Manager::Event_Header::Event_Header ()
+ : Block_Header (BT_Routing_Slip)
+{
+}
+
+bool
+Routing_Slip_Persistence_Manager::store_i(const ACE_Message_Block& event,
+ const ACE_Message_Block& routing_slip)
+{
+ bool result = false;
+
+ bool initially_persisted = this->persisted();
+ if (!initially_persisted)
+ {
+ this->factory_->lock.acquire();
+ this->factory_->preallocate_next_record(this->serial_number_,
+ this->first_routing_slip_block_,
+ this->routing_slip_header_.next_serial_number,
+ this->routing_slip_header_.next_routing_slip_block);
+ this->routing_slip_header_.serial_number = this->serial_number_;
+ }
+
+ result = this->build_chain(this->first_routing_slip_block_,
+ this->routing_slip_header_, this->allocated_routing_slip_blocks_,
+ routing_slip);
+
+ if (result)
+ {
+ // No need for a callback here since we do our own below
+ result &= this->store_event(event);
+ // If we have an event block allocated, update our header
+ if (this->first_event_block_ != 0)
+ {
+ this->routing_slip_header_.event_block =
+ this->first_event_block_->block_number();
+ }
+ else
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT(
+ "(%P|%t) No Event is being stored with this routing slip.\n")
+ ));
+ }
+ // Always write our first block out.
+ this->dllist_push_back();
+ result &= (this->write_first_routing_slip_block() != 0);
+ // because the first rs blocks everywhere have been given sync, we are
+ // guaranteed that they will be totally written by the time we get to this
+ // empty callback-only block.
+ Persistent_Storage_Block* callbackblock =
+ this->allocator_->allocate_nowrite();
+ callbackblock->set_callback(this->callback_);
+ result &= this->allocator_->write(callbackblock);
+ }
+ if (!initially_persisted)
+ {
+ this->factory_->lock.release();
+ }
+ return result;
+}
+
+bool
+Routing_Slip_Persistence_Manager::update_i(
+ const ACE_Message_Block& routing_slip)
+{
+ bool result = true;
+ size_t routing_slip_size = routing_slip.total_length();
+ if (routing_slip_size != 0)
+ {
+ result = this->build_chain(this->first_routing_slip_block_,
+ this->routing_slip_header_, this->allocated_routing_slip_blocks_,
+ routing_slip);
+
+ result &= this->allocator_->write(this->first_routing_slip_block_);
+ }
+ Persistent_Storage_Block* callbackblock =
+ this->allocator_->allocate_nowrite();
+ callbackblock->set_callback(this->callback_);
+ result &= this->allocator_->write(callbackblock);
+ return result;
+}
+
+bool
+Routing_Slip_Persistence_Manager::store_event(
+ const ACE_Message_Block& event)
+{
+ bool result = true;
+ size_t event_size = event.total_length();
+ if (event_size != 0)
+ {
+ if (this->first_event_block_ == 0)
+ {
+ this->first_event_block_ = this->allocator_->allocate();
+ this->first_event_block_->set_allocator_owns(false);
+ }
+
+ result = this->build_chain(this->first_event_block_,
+ this->event_header_, this->allocated_event_blocks_,
+ event);
+
+ result &= this->allocator_->write(this->first_event_block_);
+ }
+ return result;
+}
+
+size_t
+Routing_Slip_Persistence_Manager::fill_block(Persistent_Storage_Block& psb,
+ const size_t offset_into_block, const ACE_Message_Block* data,
+ const size_t offset_into_msg)
+{
+ unsigned char* ptr = (unsigned char*)data->rd_ptr();
+ return this->fill_block(psb, offset_into_block, ptr + offset_into_msg,
+ data->length() - offset_into_msg);
+}
+
+size_t
+Routing_Slip_Persistence_Manager::fill_block(Persistent_Storage_Block& psb,
+ const size_t offset_into_block, unsigned char* data, const size_t data_size)
+{
+ size_t result = 0;
+ if (data_size > 0)
+ {
+ const size_t max_size = this->allocator_->block_size() - offset_into_block;
+ size_t size_to_copy = data_size;
+ if (size_to_copy > max_size)
+ {
+ size_to_copy = max_size;
+ result = data_size - size_to_copy;
+ }
+ else
+ {
+ result = 0;
+ }
+ ACE_OS::memcpy(psb.data() + offset_into_block, data, size_to_copy);
+ }
+ return result;
+}
+
+bool
+Routing_Slip_Persistence_Manager::build_chain(
+ Persistent_Storage_Block* first_block, Block_Header& first_header,
+ ACE_Unbounded_Stack<size_t>& allocated_blocks,
+ const ACE_Message_Block& data)
+{
+ size_t data_size = data.total_length();
+ size_t remainder = data_size;
+ bool result = true;
+ // Save the number of items currently on the allocation list for
+ ACE_Unbounded_Stack<size_t> blocks_to_free;
+ size_t block_number = 0;
+
+ // reverse the order so when we pop, we free up things closer to block 0
+ // first
+ while (allocated_blocks.pop(block_number) == 0)
+ {
+ blocks_to_free.push(block_number);
+ }
+ size_t pos = first_header.put_header(
+ *first_block);
+ const ACE_Message_Block* mblk = &data;
+ remainder = this->fill_block(*first_block, pos, mblk, 0);
+ while ((remainder == 0) && (mblk->cont() != 0))
+ {
+ pos += mblk->length();
+ mblk = mblk->cont();
+ remainder = this->fill_block(*first_block, pos, mblk, 0);
+ }
+ first_header.data_size = data_size - remainder;
+ first_header.next_overflow = 0;
+
+ Block_Header* prevhdr = &first_header;
+ Persistent_Storage_Block* prevblk = first_block;
+
+ while (remainder > 0)
+ {
+ Overflow_Header* hdr = 0;
+ ACE_NEW_RETURN(hdr, Overflow_Header, result);
+
+ Persistent_Storage_Block* curblk = this->allocator_->allocate();
+ allocated_blocks.push(curblk->block_number());
+ // Set the previous block's overflow "pointer" to us.
+ prevhdr->next_overflow = curblk->block_number();
+ prevhdr->put_header(*prevblk);
+ pos = hdr->put_header(*curblk);
+ hdr->data_size = remainder;
+
+ size_t offset_into_msg = mblk->length() - remainder;
+ remainder = this->fill_block(*curblk, pos, mblk, offset_into_msg);
+ while ((remainder == 0) && (mblk->cont() != 0))
+ {
+ pos += mblk->length();
+ mblk = mblk->cont();
+ remainder = this->fill_block(*curblk, pos, mblk, 0);
+ }
+
+ hdr->data_size -= remainder;
+ if (prevblk != first_block)
+ {
+ // allocator obtains ownership, so write out and delete the header
+ // only.
+ result &= this->allocator_->write(prevblk);
+ delete prevhdr;
+ }
+ prevblk = curblk;
+ prevhdr = hdr;
+ }
+ if (prevblk != first_block)
+ {
+ prevhdr->put_header(*prevblk);
+ result &= this->allocator_->write(prevblk);
+ delete prevhdr;
+ }
+ pos = first_header.put_header(
+ *first_block);
+ // Free all but the first routing_slip_block
+ while (blocks_to_free.pop(block_number) == 0)
+ {
+ this->allocator_->free(block_number);
+ }
+
+ return result;
+}
+
+bool
+Routing_Slip_Persistence_Manager::reload_chain(
+ Persistent_Storage_Block* first_block, Block_Header& first_header,
+ ACE_Unbounded_Stack<size_t>& allocated_blocks,
+ ACE_Message_Block* amb,
+ ACE_UINT64 expected_serial_number
+ )
+{
+ bool result = false;
+ size_t block_size = this->allocator_->block_size();
+ if (this->allocator_->read(first_block))
+ {
+ size_t pos = 0;
+ size_t nextptr = 0;
+ ACE_Message_Block* mbptr = amb;
+ ACE_Message_Block* mbnew = 0;
+
+ pos = first_header.extract_header(*first_block);
+ if (first_header.serial_number == expected_serial_number)
+ {
+ // We have to copy the first block because we cache it.
+ ACE_OS::memcpy(mbptr->wr_ptr(), first_block->data(),
+ block_size);
+ mbptr->rd_ptr(pos);
+ mbptr->wr_ptr(pos + first_header.data_size);
+ nextptr = first_header.next_overflow;
+ while (nextptr != 0)
+ {
+ Overflow_Header overflow_header;
+ ACE_NEW_RETURN(mbnew, ACE_Message_Block(block_size), result);
+ mbptr->cont(mbnew);
+ Persistent_Storage_Block* psb = this->allocator_->allocate_at(nextptr);
+ mbptr = mbnew;
+ // Deallocate the PSB's data and reallocate it to our wr_ptr()...
+ psb->reassign_data(ACE_static_cast(unsigned char*,
+ ACE_static_cast(void*, mbptr->wr_ptr())), true);
+ // ...read into the PSB (whose data is inside of the AMB)...
+ this->allocator_->read(psb);
+ allocated_blocks.push(psb->block_number());
+ // ...extract all headers so we know the data's size...
+ pos = overflow_header.extract_header(*psb);
+ // ...set up the region that somebody else can look at...
+ mbptr->rd_ptr(pos);
+ mbptr->wr_ptr(pos + overflow_header.data_size);
+ // ...then make sure we don't delete data since we don't own it.
+ psb->reassign_data(0);
+ delete psb;
+ nextptr = overflow_header.next_overflow;
+ }
+ result = true;
+ }
+ }
+ return result;
+}
+
+bool
+Routing_Slip_Persistence_Manager::update_next_manager(
+ Routing_Slip_Persistence_Manager* next)
+{
+ bool result = false;
+ ACE_GUARD_RETURN(ACE_SYNCH_MUTEX, ace_mon, this->lock_, result);
+ ACE_ASSERT(this->persisted());
+ if (!this->removed_)
+ {
+ bool updated = false;
+ if (this->next_manager_ != 0)
+ {
+ if (this->routing_slip_header_.next_serial_number !=
+ next->routing_slip_header_.next_serial_number)
+ {
+ this->routing_slip_header_.next_serial_number =
+ next->routing_slip_header_.next_serial_number;
+ updated = true;
+ }
+ if (this->routing_slip_header_.next_routing_slip_block !=
+ next->routing_slip_header_.next_routing_slip_block)
+ {
+ this->routing_slip_header_.next_routing_slip_block =
+ next->routing_slip_header_.next_routing_slip_block;
+ updated = true;
+ }
+ }
+ if (updated)
+ {
+ this->write_first_routing_slip_block();
+ }
+ }
+ return result;
+}
+
+bool
+Routing_Slip_Persistence_Manager::persisted()
+{
+ return (0 != this->first_routing_slip_block_);
+}
+
+bool
+Routing_Slip_Persistence_Manager::is_root () const
+{
+ return this->serial_number_ == ROUTING_SLIP_ROOT_SERIAL_NUMBER;
+}
+
+void
+Routing_Slip_Persistence_Manager::release_all ()
+{
+ ACE_ASSERT(is_root());
+ while (this->next_manager_ != this)
+ {
+ Routing_Slip_Persistence_Manager * next = this->next_manager_;
+ next->remove_from_dllist();
+ ACE_ASSERT(next != this->next_manager_);
+ delete next;
+ }
+}
+
+size_t
+Routing_Slip_Persistence_Manager::write_first_routing_slip_block(
+ bool prepare_only)
+{
+ size_t pos = this->routing_slip_header_.put_header(
+ *this->first_routing_slip_block_);
+ if (!prepare_only)
+ {
+ this->allocator_->write(this->first_routing_slip_block_);
+ }
+ return pos;
+}
+
+void
+Routing_Slip_Persistence_Manager::dllist_push_back()
+{
+ insert_before (&this->factory_->root());
+}
+
+void
+Routing_Slip_Persistence_Manager::insert_before (Routing_Slip_Persistence_Manager * node)
+{
+ // Since this is a private function, the caller should have done locking
+ // on the factory before calling here. The same is true for removals.
+ ACE_ASSERT(this->prev_manager_ == this);
+ ACE_ASSERT(this->next_manager_ == this);
+ ACE_ASSERT(node != this);
+ this->prev_manager_ = node->prev_manager_;
+ node->prev_manager_ = this;
+ this->next_manager_ = node;
+ this->prev_manager_->next_manager_ = this;
+}
+
+void
+Routing_Slip_Persistence_Manager::remove_from_dllist()
+{
+ // Since this is a private function, the caller should have done locking
+ // on the factory before calling here. The same is true for insertions.
+ ACE_ASSERT(this->persisted());
+ ACE_ASSERT(this->prev_manager_ != this);
+ ACE_ASSERT(this->next_manager_ != this);
+ this->prev_manager_->next_manager_ = this->next_manager_;
+ this->next_manager_->prev_manager_ = this->prev_manager_;
+ this->prev_manager_ = this;
+ this->next_manager_ = this;
+}
+
+} /* namespace TAO_NOTIFY */
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+//template class ACE_Node<size_t>;
+//template class ACE_Unbounded_Stack<size_t>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+//#pragma instantiate ACE_Node<size_t>
+//#pragma instantiate ACE_Unbounded_Stack<size_t>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.h b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.h
new file mode 100644
index 00000000000..b425fa71152
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.h
@@ -0,0 +1,264 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Routing_Slip_Persistence_Manager.h
+ *
+ * $Id$
+ *
+ * A Routing_Slip_Persistence manager controls the actual allocation of
+ * blocks through a Persistent_Storage_Allocator and can persist an
+ * event and its routing slip.
+ *
+ * @author Jonathan Pollack <pollack_j@ociweb.com>
+ */
+//=============================================================================
+
+#ifndef ROUTING_SLIP_PERSISTENCE_MANAGER_H
+#define ROUTING_SLIP_PERSISTENCE_MANAGER_H
+#include /**/ "ace/pre.h"
+#include /**/ "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "notify_export.h"
+#include "ace/Message_Block.h"
+#include "ace/Synch_T.h"
+#include "ace/Containers_T.h"
+
+namespace TAO_NOTIFY
+{
+
+// Some forward declarations.
+class TAO_Notify_Export Standard_Event_Persistence_Factory;
+class TAO_Notify_Export Persistent_File_Allocator;
+class TAO_Notify_Export Persistent_Storage_Block;
+class TAO_Notify_Export Persistent_Callback;
+
+/**
+ * \brief Manage interaction between Routing_Slip and persistent storage.
+ *
+ * todo: to complete the strategization of event persistent storage this
+ * should become an interface that is implemented differently by different
+ * strategies. For now it interacts with Standard_Event_Persistence.
+ */
+class TAO_Notify_Export Routing_Slip_Persistence_Manager
+{
+public:
+ /// A unique identifier for logical blocks in persistent storage.
+ typedef ACE_UINT64 Block_Serial_Number;
+ /// The physical address of a block in persistent storage.
+ typedef ACE_UINT32 Block_Number;
+ /// The size of a block in persistent storage.
+ typedef ACE_UINT16 Block_Size;
+ /// A code to indicate the type of block in persistent storage.
+ typedef ACE_UINT16 Block_Type;
+
+ /// The constructor.
+ /// We must have one allocator per Persistent_File, and it has to be
+ /// passed in here.
+ Routing_Slip_Persistence_Manager(Standard_Event_Persistence_Factory* factory);
+
+ /// The destructor.
+ ~Routing_Slip_Persistence_Manager();
+
+ /// Set up callbacks
+ void set_callback(Persistent_Callback* callback);
+
+
+ /// Store an event + routing slip.
+ bool store(const ACE_Message_Block& event,
+ const ACE_Message_Block& routing_slip);
+
+ /// \brief Update the routing slip.
+ ///
+ /// We must always overwrite the first block
+ /// last, and it may not chance. Other blocks should be freed and
+ /// reallocated.
+ bool update(const ACE_Message_Block& routing_slip);
+
+ /// \brief Remove our associated event and routing slip from the
+ /// Persistent_File_Allocator.
+ bool remove();
+
+ /////////////////////////////////////////
+ // Methods to be used during reload only.
+
+ /// \brief Call this method to recover data during event reload.
+ ///
+ /// It should not fail under normal circumstances.
+ /// Caller owns the resulting message blocks and is responsible
+ /// for deleting them.
+ /// Reload the event and routing_slip from the Persistent_File_Allocator.
+ bool reload(ACE_Message_Block*& event, ACE_Message_Block*&routing_slip);
+
+ /// \brief Get next RSPM during reload.
+ ///
+ /// After using the data from the reload method, call this
+ /// method to get the next RSPM. It returns a null pointer
+ /// when all persistent events have been reloaded.
+ Routing_Slip_Persistence_Manager * load_next ();
+
+ /////////////////////////
+ // Implementation methods.
+ // Should not be called by Routing_Slip
+
+ /// \brief Commit root data to disk, which should only be done for a root node.
+ bool store_root();
+
+ /// \brief Reload data into this RSPM from the given block/serial#
+ ///
+ /// \return false if the reload is not successful.
+ bool load(Block_Number block_number, Block_Serial_Number expected_serial_number);
+
+ /// \brief Is this RSPM attached to the root block?
+ bool is_root () const;
+
+ /// \brief During cleanup for shut down, release all chained RSPMs.
+ void release_all ();
+
+private:
+ /**
+ * \brief private: Storage for header information of all persistent block.
+ */
+ class Block_Header
+ {
+ public:
+ enum Header_Type {
+ BT_Routing_Slip,
+ BT_Event,
+ BT_Overflow
+ };
+
+ Block_Header(Header_Type type);
+ virtual size_t extract_header(Persistent_Storage_Block& psb,
+ const size_t offset = 0);
+ virtual size_t put_header(Persistent_Storage_Block& psb,
+ const size_t offset = 0);
+
+ public:
+ /// Our serial number
+ Block_Serial_Number serial_number;
+ /// Address of the overflow record (if any)
+ Block_Number next_overflow;
+ /// How much extra header data is in this block (not including this header)
+ Block_Type header_type;
+ /// How much actual data is in this block? (not including headers)
+ Block_Size data_size;
+ };
+
+ /**
+ * \brief private: Storage for header information for Routing_Slip blocks.
+ */
+ class Routing_Slip_Header : public Block_Header
+ {
+ public:
+ Routing_Slip_Header();
+ virtual size_t extract_header(Persistent_Storage_Block& psb,
+ const size_t offset = 0);
+ virtual size_t put_header(Persistent_Storage_Block& psb,
+ const size_t offset = 0);
+
+ public:
+ /// The next event in the system
+ Block_Number next_routing_slip_block;
+ /// The next expected serial number
+ Block_Serial_Number next_serial_number;
+ Block_Number event_block;
+ };
+
+ /// \brief An Event block header.
+ ///
+ /// is just a Block_Header with no extra data
+ class Event_Header : public Block_Header
+ {
+ public:
+ Event_Header ();
+ };
+
+ /// \brief An overflow block header.
+ ///
+ /// is just a Block_Header with no extra data
+ /// The same record type is used for both Routing_Slip
+ /// and Event overflows.
+ class Overflow_Header : public Block_Header
+ {
+ public:
+ Overflow_Header ();
+ };
+
+ bool store_i(const ACE_Message_Block& event,
+ const ACE_Message_Block& routing_slip);
+
+ bool update_i(const ACE_Message_Block& routing_slip);
+
+ bool store_event(const ACE_Message_Block& event);
+
+ /// Fill in a block with data, and return the number of bytes
+ /// of data remaining to be written.
+ size_t fill_block(Persistent_Storage_Block& psb,
+ const size_t offset_into_block, const ACE_Message_Block* data,
+ const size_t offset_into_msg);
+ size_t fill_block(Persistent_Storage_Block& psb,
+ const size_t offset_into_block, unsigned char* data,
+ const size_t data_size);
+
+ /// Build a chain of Persistent_Storage_Blocks
+ bool build_chain(
+ Persistent_Storage_Block* first_block,
+ Block_Header& first_header,
+ ACE_Unbounded_Stack<size_t>& allocated_blocks,
+ const ACE_Message_Block& data);
+
+ /// Reload a chain from persistent store.
+ bool reload_chain(Persistent_Storage_Block* first_block,
+ Block_Header& first_header,
+ ACE_Unbounded_Stack<size_t>& allocated_blocks,
+ ACE_Message_Block* amb,
+ ACE_UINT64 expected_serial_number);
+
+ /// Locked method to do the work of setting the next_manager_.
+ bool update_next_manager(Routing_Slip_Persistence_Manager* next);
+
+ /// Have we been persisted yet?
+ bool persisted();
+
+ /// Write out our first event block.
+ size_t write_first_routing_slip_block(bool prepare_only = false);
+
+ /// Insert ourselves into a linked list of Routing_Slip_Persistnce_Managers
+ void dllist_push_back();
+
+ void insert_before (Routing_Slip_Persistence_Manager * node);
+
+ /// Remove ourselves from a linked list of Routing_Slip_Persistence_Managers
+ void remove_from_dllist();
+
+private:
+ ACE_SYNCH_MUTEX lock_;
+ bool removed_;
+ ACE_UINT64 serial_number_;
+ Persistent_File_Allocator* allocator_;
+ Standard_Event_Persistence_Factory* factory_;
+ Event_Header event_header_;
+ Routing_Slip_Header routing_slip_header_;
+ Persistent_Storage_Block* first_event_block_;
+ Persistent_Storage_Block* first_routing_slip_block_;
+ /// We are part of a doubly-linked list
+ Routing_Slip_Persistence_Manager* prev_manager_;
+ Routing_Slip_Persistence_Manager* next_manager_;
+ ACE_Unbounded_Stack<size_t> allocated_event_blocks_;
+ ACE_Unbounded_Stack<size_t> allocated_routing_slip_blocks_;
+ Persistent_Callback* callback_;
+
+ /// if these are non-zero we own 'em
+ ACE_Message_Block * event_mb_;
+ ACE_Message_Block * routing_slip_mb_;
+};
+
+} /* namespace TAO_NOTIFY */
+
+#include /**/ "ace/post.h"
+#endif /* ROUTING_SLIP_PERSISTENCE_MANAGER_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.cpp b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.cpp
new file mode 100644
index 00000000000..4ca7d08ebb9
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.cpp
@@ -0,0 +1,120 @@
+// $Id$
+
+#include "Routing_Slip_Queue.h"
+
+#if ! defined (__ACE_INLINE__)
+#include "Routing_Slip_Queue.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "tao/debug.h"
+#include "ace/Dynamic_Service.h"
+
+//#define DEBUG_LEVEL 9
+#define DEBUG_LEVEL TAO_debug_level
+
+namespace TAO_NOTIFY
+{
+ Routing_Slip_Queue::Routing_Slip_Queue (size_t allowed)
+ : allowed_ (allowed)
+ , active_ (0)
+ {
+ }
+
+ Routing_Slip_Queue::~Routing_Slip_Queue ()
+ {
+ }
+
+ void
+ Routing_Slip_Queue::add (const Routing_Slip_Ptr & routing_slip)
+ {
+ Guard guard (internals_);
+ ACE_ASSERT (guard.locked()); // check recursion
+ if (this->allowed_ == 0)
+ {
+ ++this->active_;
+ guard.release ();
+ routing_slip->at_front_of_persist_queue ();
+// guard.acquire ();
+ }
+ else
+ {
+ this->queue_.enqueue_tail (routing_slip);
+ dispatch (guard);
+ }
+ }
+
+ void Routing_Slip_Queue::complete ()
+ {
+ Guard guard (internals_);
+ ACE_ASSERT (guard.locked()); // check recursion
+ ACE_ASSERT (this->active_ > 0);
+ --this->active_;
+ dispatch (guard);
+ }
+
+ void
+ Routing_Slip_Queue::dispatch (Guard & guard)
+ {
+ // we start out pretty nice,
+ // but the more work we do for other people
+ // the less nice we get.
+ size_t nice = this->allowed_ + 1;
+ while (nice > 0 && (this->active_ < this->allowed_))
+ {
+ if (dispatch_one (guard))
+ {
+ --nice;
+ }
+ else
+ {
+ // that's about as nice as I get.
+ nice = 0;
+ }
+ }
+ }
+
+ bool
+ Routing_Slip_Queue::dispatch_one (Guard & guard)
+ {
+ bool ok = false;
+ Routing_Slip_Ptr routing_slip;
+ if (this->queue_.dequeue_head (routing_slip) == 0)
+ {
+ ++this->active_;
+ guard.release ();
+ routing_slip->at_front_of_persist_queue ();
+ guard.acquire ();
+ }
+ return ok;
+ }
+
+ void
+ Routing_Slip_Queue::set_allowed (size_t allowed)
+ {
+ Guard guard (internals_);
+ size_t allowed_was = this->allowed_;
+ this->allowed_ = allowed;
+ if (allowed == 0 && allowed_was != 0)
+ {
+ while (dispatch_one (guard))
+ {
+ ; // work happens in dispatc_one
+ }
+ }
+ else
+ {
+ dispatch (guard);
+ }
+ }
+} // namespace
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Node<TAO_NOTIFY::Routing_Slip_Ptr>;
+template class ACE_Unbounded_Queue<TAO_NOTIFY::Routing_Slip_Ptr>;
+template class ACE_Unbounded_Queue_Iterator<TAO_NOTIFY::Routing_Slip_Ptr>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Node<TAO_NOTIFY::Routing_Slip_Ptr>
+#pragma instantiate ACE_Unbounded_Queue<TAO_NOTIFY::Routing_Slip_Ptr>
+#pragma instantiate ACE_Unbounded_Queue_Iterator<TAO_NOTIFY::Routing_Slip_Ptr>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.h b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.h
new file mode 100644
index 00000000000..93ddab1b713
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.h
@@ -0,0 +1,92 @@
+/* -*- C++ -*- */
+// $Id$
+
+#ifndef TAO_NOTIFY_ROUTING_SLIP_QUEUE_H
+#define TAO_NOTIFY_ROUTING_SLIP_QUEUE_H
+#include "ace/pre.h"
+
+#include "Routing_Slip.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+namespace TAO_NOTIFY
+{
+ /**
+ * \brief A queue of Routing_Slips waiting to be persisted.
+ *
+ * The Routing_Slip_Queue keeps a queue of Routing_Slips waiting
+ * to be written to persistent storage. The "allowed" parameter
+ * determines how many Routing_Slips can be handled simultaneously
+ * by the persistent storage. Until this threshold is reached,
+ * Routing_Slips are not held in the queue, but pass straight through.
+ *
+ * Once the allowe number of Routing_Slips are being handled, any
+ * additional requests are held in the queue until persistence is
+ * complete for another Routing_Slips.
+ *
+ * Having Routing_Slips waiting in the queue is "a good thing" [TM]
+ * because it allows delivery completions to be applied to the
+ * routing slip before it is written -- thereby reducing or completely
+ * eliminating the number of actual writes to persistent storage.
+ *
+ * Experimentation indicates that a good value for "allowed" is 1.
+ *
+ * Allowed == 0 is treated as a special case meaning pass all Routing_Slips
+ * through the queue immediately. Setting it a good way to test how well
+ * your storage device withstands continuous beating.
+ */
+ class TAO_Notify_Export Routing_Slip_Queue
+ {
+ typedef ACE_Unbounded_Queue <Routing_Slip_Ptr> Queue;
+ typedef ACE_Guard< TAO_SYNCH_MUTEX > Guard;
+ public:
+ /**
+ * \brief Construct setting "allowed".
+ * \param allowed the number of Routing_Slips that can be handled
+ * simultaneously by the persistent store.
+ */
+ Routing_Slip_Queue (size_t allowed = 1);
+ /// Destructor.
+ ~Routing_Slip_Queue ();
+
+ /**
+ * \brief Add a routing slip to the tail of the queue and dispatch if necessary.
+ */
+ void add (const Routing_Slip_Ptr & routing_slip);
+ /**
+ * \brief A call back to indicate that processing is complete for a previously-queued
+ * Routing_Slip.
+ */
+ void complete ();
+
+ /**
+ * /brief Adjust the "allowed" value on-the-fly (not recommended, but it works.)
+ */
+ void set_allowed (size_t allowed);
+
+ private:
+ void dispatch (Guard & guard);
+ bool dispatch_one (Guard & guard);
+
+ private:
+ Routing_Slip_Queue (const Routing_Slip_Queue & rhs);
+ Routing_Slip_Queue & operator = (const Routing_Slip_Queue & rhs);
+ private:
+ // configuration setting
+ size_t allowed_;
+ /// Protection for internal information
+ TAO_SYNCH_MUTEX internals_;
+ size_t active_;
+ Queue queue_;
+
+ };
+} // namespace
+
+#if defined (__ACE_INLINE__)
+#include "Routing_Slip_Queue.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* TAO_NOTIFY_ROUTING_SLIP_QUEUE_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.cpp b/TAO/orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.cpp
new file mode 100644
index 00000000000..edbb3518baf
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.cpp
@@ -0,0 +1,46 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+* @file Save_Persist_Worker_T.h
+*
+* $Id$
+*
+* @author Jonathan Pollack <pollack_j@ociweb.com>
+*/
+//=============================================================================
+
+#ifndef SAVE_PERSIST_WORKER_CPP
+#define SAVE_PERSIST_WORKER_CPP
+
+#include "orbsvcs/ESF/ESF_Worker.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+namespace TAO_NOTIFY
+{
+ template<class TOPOOBJ>
+ Save_Persist_Worker<TOPOOBJ>::Save_Persist_Worker(
+ Topology_Saver& saver,
+ bool want_all_children)
+ : saver_(saver)
+ , want_all_children_ (want_all_children)
+ {
+ }
+
+ template<class TOPOOBJ>
+ void
+ Save_Persist_Worker<TOPOOBJ>::work (TOPOOBJ* o ACE_ENV_ARG_DECL)
+ {
+ ACE_ASSERT(o != 0);
+ if (this->want_all_children_ || o->is_changed ())
+ {
+ o->save_persistent (saver_ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+ }
+} // namespace TAO_NOTIFY
+
+#endif /* SAVE_PERSIST_WORKER_CPP */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.h b/TAO/orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.h
new file mode 100644
index 00000000000..adee13f8de4
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.h
@@ -0,0 +1,58 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+* \file Save_Persist_Worker_T.h
+*
+* $Id$
+*
+* \author Jonathan Pollack <pollack_j@ociweb.com>
+*/
+//=============================================================================
+
+#ifndef SAVE_PERSIST_WORKER_H
+#define SAVE_PERSIST_WORKER_H
+#include /**/ "ace/pre.h"
+
+#include "orbsvcs/ESF/ESF_Worker.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+namespace TAO_NOTIFY
+{
+ /**
+ * \brief Iterate through children saving persistent topology information.
+ */
+ template<class TOPOOBJ>
+ class Save_Persist_Worker : public TAO_ESF_Worker<TOPOOBJ>
+ {
+ public:
+ /**
+ * /brief Constructor
+ * /param saver the object that will save persistent information.
+ * /param want_all_children if true, unmodified children should be saved, too.
+ */
+ Save_Persist_Worker(Topology_Saver& saver, bool want_all_children);
+
+ // override virtual ESF_Worker method
+ virtual void work (TOPOOBJ* o ACE_ENV_ARG_DECL);
+
+ private:
+ Topology_Saver& saver_;
+ bool want_all_children_;
+ };
+} // namespace TAO_NOTIFY
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "Save_Persist_Worker_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Save_Persist_Worker_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include /**/ "ace/post.h"
+
+#endif /* SAVE_PERSIST_WORKER_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.cpp b/TAO/orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.cpp
new file mode 100644
index 00000000000..bd6b1053245
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.cpp
@@ -0,0 +1,233 @@
+// $Id$
+
+#include "Standard_Event_Persistence.h"
+#include "Persistent_File_Allocator.h"
+#include "tao/debug.h"
+#include "ace/Dynamic_Service.h"
+#include "ace/OS_NS_strings.h"
+
+namespace TAO_NOTIFY
+{
+
+Standard_Event_Persistence::Standard_Event_Persistence ()
+ : filename_ ("__PERSISTENT_EVENT__.DB")
+ , block_size_ (512)
+ , factory_ (0)
+{
+}
+
+Standard_Event_Persistence::~Standard_Event_Persistence ()
+{
+}
+
+// get the current factory, creating it if necessary
+Event_Persistence_Factory *
+Standard_Event_Persistence::get_factory ()
+{
+ //@@todo guard? ; doublecheck?
+ if (this->factory_ == 0)
+ {
+ ACE_NEW_NORETURN (
+ this->factory_,
+ Standard_Event_Persistence_Factory ()
+ );
+ if (this->factory_ != 0)
+ {
+ if (!this->factory_->open (this->filename_.c_str ()))
+ {
+ this->factory_ = 0;
+ }
+ }
+ }
+ return this->factory_;
+}
+
+// release the current factory so a new one can be created
+void
+Standard_Event_Persistence::reset ()
+{
+ delete this->factory_;
+ this->factory_ = 0;
+}
+
+int
+Standard_Event_Persistence::init (int argc, ACE_TCHAR *argv[])
+{
+ int result = 0;
+ bool verbose = false;
+ for (int narg = 0; narg < argc; ++narg)
+ {
+ ACE_TCHAR * av = argv[narg];
+ if (ACE_OS::strcasecmp (av, "-v") == 0)
+ {
+ verbose = true;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Standard_Event_Persistence: -verbose\n")
+ ));
+ }
+ else if (ACE_OS::strcasecmp (av, "-file_path") == 0 && narg + 1 < argc)
+ {
+ this->filename_ = argv[narg + 1];
+ if (TAO_debug_level > 0 || verbose)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Standard_Event_Persistence: Setting -file_path: %s\n"),
+ this->filename_.c_str ()
+ ));
+ }
+ narg += 1;
+ }
+ else if (ACE_OS::strcasecmp (av, "-block_size") == 0 && narg + 1 < argc)
+ {
+ this->block_size_ = ACE_OS::atoi(argv[narg + 1]);
+ if (TAO_debug_level > 0 || verbose)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Standard_Event_Persistence: Setting -block_size: %d\n"),
+ this->block_size_
+ ));
+ }
+ narg += 1;
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Unknown parameter to Standard Event Persistence: %s\n"),
+ argv[narg]
+ ));
+ result = -1;
+ }
+ }
+ return result;
+}
+
+int
+Standard_Event_Persistence::fini ()
+{
+ delete this->factory_;
+ this->factory_ = 0;
+ return 0;
+}
+
+Standard_Event_Persistence_Factory::Standard_Event_Persistence_Factory ()
+ : allocator_()
+ , root_(this)
+ , psb_(0)
+ , serial_number_(ROUTING_SLIP_ROOT_SERIAL_NUMBER + 1)
+ , is_reloading_ (false)
+{
+}
+
+bool
+Standard_Event_Persistence_Factory::open (const char * filename,
+ ACE_UINT32 block_size)
+{
+ bool result = false;
+ if (allocator_.open (filename, block_size))
+ {
+ this->is_reloading_ = this->root_.load(ROUTING_SLIP_ROOT_BLOCK_NUMBER, ROUTING_SLIP_ROOT_SERIAL_NUMBER);
+ if (! this->is_reloading_)
+ {
+ ACE_ASSERT (this->psb_ == 0);
+// this->psb_ = this->allocator_.allocate();
+ this->root_.store_root();
+ }
+ result = true;
+ }
+ return result;
+}
+
+Standard_Event_Persistence_Factory::~Standard_Event_Persistence_Factory()
+{
+ if (TAO_debug_level > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Standard_Event_Persistence_Factory::~Standard_Event_Persistence_Factory\n")
+ ));
+ }
+ this->root_.release_all ();
+ delete this->psb_;
+ this->psb_ = 0;
+ this->allocator_.shutdown();
+}
+
+Routing_Slip_Persistence_Manager*
+Standard_Event_Persistence_Factory::create_routing_slip_persistence_manager(
+ Persistent_Callback* callback)
+{
+ Routing_Slip_Persistence_Manager* rspm = 0;
+ ACE_NEW_RETURN(rspm, Routing_Slip_Persistence_Manager(this), rspm);
+ rspm->set_callback(callback);
+ return rspm;
+}
+
+Routing_Slip_Persistence_Manager *
+Standard_Event_Persistence_Factory::first_reload_manager()
+{
+ Routing_Slip_Persistence_Manager * result = 0;
+ if (this->is_reloading_)
+ {
+ result = this->root_.load_next();
+ }
+ return result;
+}
+
+void
+Standard_Event_Persistence_Factory::done_reloading(
+ Persistent_Storage_Block * next_psb,
+ ACE_UINT64 current_serial_number)
+{
+ ACE_ASSERT (this->psb_ == 0);
+ this->psb_ = next_psb;
+ this->serial_number_ = current_serial_number;
+ this->is_reloading_ = false;
+}
+
+void
+Standard_Event_Persistence_Factory::preallocate_next_record(
+ ACE_UINT64& current_serial_number,
+ Persistent_Storage_Block*& current_psb,
+ ACE_UINT64& next_serial_number,
+ ACE_UINT32& next_block_number)
+{
+ // return current serial number and
+ // a psb containing current record number
+ current_serial_number = this->serial_number_;
+ this->psb_->set_allocator_owns(false); // give up ownership
+ this->psb_->set_sync();
+ current_psb = this->psb_;
+ this->get_preallocated_pointer (next_serial_number, next_block_number);
+}
+
+void
+Standard_Event_Persistence_Factory::get_preallocated_pointer(
+ ACE_UINT64& next_serial_number,
+ ACE_UINT32& next_block_number)
+{
+ ++this->serial_number_;
+ this->psb_ = this->allocator_.allocate();
+
+ next_serial_number = this->serial_number_;
+ next_block_number = this->psb_->block_number();
+}
+
+Persistent_File_Allocator*
+Standard_Event_Persistence_Factory::allocator()
+{
+ return &this->allocator_;
+}
+
+Routing_Slip_Persistence_Manager &
+Standard_Event_Persistence_Factory::root()
+{
+ return this->root_;
+}
+
+ACE_FACTORY_DECLARE (TAO_Notify, Standard_Event_Persistence)
+ACE_FACTORY_DEFINE (TAO_Notify, Standard_Event_Persistence)
+
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.h b/TAO/orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.h
new file mode 100644
index 00000000000..3079d7c6765
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.h
@@ -0,0 +1,128 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * \file Event_Persistence_Factory.h
+ *
+ * $Id$
+ *
+ * The standard implementation of Event_Persistence_Factory.
+ *
+ * \author Jonathan Pollack <pollack_j@ociweb.com>
+ */
+//=============================================================================
+
+#ifndef STANDARD_EVENT_PERSISTENCE_H
+#define STANDARD_EVENT_PERSISTENCE_H
+#include /**/ "ace/pre.h"
+#include /**/ "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "Event_Persistence_Strategy.h"
+#include "Event_Persistence_Factory.h"
+#include "Persistent_File_Allocator.h"
+#include "Routing_Slip_Persistence_Manager.h"
+#include <ace/SString.h>
+
+namespace TAO_NOTIFY
+{
+static const ACE_UINT32 ROUTING_SLIP_ROOT_BLOCK_NUMBER = 0;
+static const ACE_UINT64 ROUTING_SLIP_ROOT_SERIAL_NUMBER = 1;
+
+/// \brief Standard (i.e. default) implementation of Event_Persistence_Factory interface
+class TAO_Notify_Export Standard_Event_Persistence_Factory :
+ public Event_Persistence_Factory
+{
+public:
+ /// Constructor
+ Standard_Event_Persistence_Factory ();
+ /// Destructor
+ virtual ~Standard_Event_Persistence_Factory();
+
+ /// Open persistence file and initialize.
+ /// /param filename the fully qualified path/name of the file to contain
+ /// persistent information.
+ /// /param block_size the size of a physical block on the device containing
+ /// the file.
+ bool open (const char * filename, ACE_UINT32 block_size = 512);
+
+ //////////////////////////////////////////////////////
+ // Implement Event_Persistence_Factory virtual methods.
+ virtual Routing_Slip_Persistence_Manager*
+ create_routing_slip_persistence_manager(Persistent_Callback* callback);
+
+ virtual Routing_Slip_Persistence_Manager * first_reload_manager();
+
+ /// reloading process complete. Where should the chain continue?
+ void done_reloading(
+ Persistent_Storage_Block * next_psb,
+ ACE_UINT64 current_serial_number);
+
+ /// return current serial # and a psb containing current record#
+ /// allocate new serial # and record number, and return those, too.
+ void preallocate_next_record(
+ ACE_UINT64& current_serial_number,
+ Persistent_Storage_Block*& current_psb,
+ ACE_UINT64& next_serial_number,
+ ACE_UINT32& next_block_number);
+
+ // return block pointer info for the
+ void get_preallocated_pointer(
+ ACE_UINT64& next_serial_number,
+ ACE_UINT32& next_block_number);
+
+ /// Accessor for file allocator.
+ /// Intended for use only by the Routing Slip Persistence Manager
+ Persistent_File_Allocator* allocator();
+
+ /// Access root record.
+ /// Intended for use only by the Routing Slip Persistence Manager
+ Routing_Slip_Persistence_Manager & root();
+
+public:
+ ACE_SYNCH_MUTEX lock;
+
+private:
+ Persistent_File_Allocator allocator_;
+ Routing_Slip_Persistence_Manager root_;
+ Persistent_Storage_Block* psb_;
+ ACE_UINT64 serial_number_;
+ bool is_reloading_;
+};
+
+/// \brief The standard implementation of the
+/// Event_Persistence_Strategy interface.
+class TAO_Notify_Export Standard_Event_Persistence :
+ public Event_Persistence_Strategy
+{
+public :
+ /// Constructor.
+ Standard_Event_Persistence ();
+ /// Destructor.
+ virtual ~Standard_Event_Persistence ();
+ /////////////////////////////////////////////
+ // Override Event_Persistent_Strategy methods
+ // Parse arguments and initialize.
+ virtual int init(int argc, ACE_TCHAR *argv[]);
+ // Prepare for shutdown
+ virtual int fini ();
+
+ // get the current factory, creating it if necessary
+ virtual Event_Persistence_Factory * get_factory ();
+
+ // release the current factory so a new one can be created
+ virtual void reset ();
+
+private:
+ ACE_CString filename_; // set via -file_path
+ ACE_UINT32 block_size_; // set via -block_size
+ Standard_Event_Persistence_Factory * factory_;
+};
+
+}
+
+#include /**/ "ace/post.h"
+#endif /* STANDARD_EVENT_PERSISTENCE_H */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.cpp b/TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.cpp
index 12e343f11b7..8c06d5864ee 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.cpp
@@ -7,6 +7,7 @@
#endif /* __ACE_INLINE__ */
ACE_RCSID(RT_Notify, TAO_Notify_StructuredPushSupplier, "$Id$")
+#include "../Properties.h"
TAO_Notify_StructuredPushSupplier::TAO_Notify_StructuredPushSupplier (TAO_Notify_ProxyConsumer* proxy)
:TAO_Notify_Supplier (proxy)
@@ -31,3 +32,24 @@ TAO_Notify_StructuredPushSupplier::release (void)
delete this;
//@@ inform factory
}
+
+bool
+TAO_Notify_StructuredPushSupplier::get_ior (ACE_CString & iorstr) const
+{
+ bool result = false;
+ CORBA::ORB_var orb = TAO_Notify_PROPERTIES::instance()->orb();
+ ACE_DECLARE_NEW_CORBA_ENV;
+ ACE_TRY
+ {
+ CORBA::String_var ior = orb->object_to_string(this->push_supplier_.in() ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ iorstr = ACE_static_cast (const char *, ior.in ());
+ result = true;
+ }
+ ACE_CATCHANY
+ {
+ ACE_ASSERT(0);
+ }
+ ACE_ENDTRY;
+ return result;
+}
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.h b/TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.h
index f2329db3542..ddfdcd23017 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.h
@@ -45,6 +45,9 @@ public:
/// Release
virtual void release (void);
+ /// Retrieve the ior of this peer
+ virtual bool get_ior (ACE_CString & iorstr) const;
+
protected:
/// The Supplier
CosNotifyComm::StructuredPushSupplier_var push_supplier_;
diff --git a/TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.cpp b/TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.cpp
index 37823207801..50f1e93c42b 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.cpp
+++ b/TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.cpp
@@ -6,19 +6,23 @@
#include "SupplierAdmin.inl"
#endif /* __ACE_INLINE__ */
-ACE_RCSID (RT_Notify,
- TAO_Notify_SupplierAdmin,
+ACE_RCSID (RT_Notify,
+ TAO_Notify_SupplierAdmin,
"$Id$")
#include "orbsvcs/ESF/ESF_Proxy_Collection.h"
#include "Builder.h"
-#include "Proxy.h"
+#include "ProxyConsumer.h"
#include "EventChannel.h"
#include "Subscription_Change_Worker.h"
#include "Find_Worker_T.h"
#include "Seq_Worker_T.h"
#include "Properties.h"
+#include "tao/debug.h"
+//#define DEBUG_LEVEL 9
+#define DEBUG_LEVEL TAO_debug_level
+
typedef TAO_Notify_Find_Worker_T<TAO_Notify_Proxy
, CosNotifyChannelAdmin::ProxyConsumer
, CosNotifyChannelAdmin::ProxyConsumer_ptr
@@ -28,9 +32,16 @@ TAO_Notify_ProxyConsumer_Find_Worker;
typedef TAO_Notify_Seq_Worker_T<TAO_Notify_Proxy> TAO_Notify_Proxy_Seq_Worker;
TAO_Notify_SupplierAdmin::TAO_Notify_SupplierAdmin (void)
+ : TAO_Notify_Admin ()
{
}
+const char *
+TAO_Notify_SupplierAdmin::get_admin_type_name () const
+{
+ return "supplier_admin";
+}
+
TAO_Notify_SupplierAdmin::~TAO_Notify_SupplierAdmin ()
{
}
@@ -81,6 +92,65 @@ TAO_Notify_SupplierAdmin::destroy (ACE_ENV_SINGLE_ARG_DECL)
ACE_CHECK;
}
+TAO_NOTIFY::Topology_Object*
+TAO_Notify_SupplierAdmin::load_child (const ACE_CString &type,
+ CORBA::Long id, const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL)
+{
+ TAO_NOTIFY::Topology_Object* result = this;
+ if (type == "proxy_push_consumer")
+ {
+ if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Admin reload proxy %d\n")
+ , ACE_static_cast (int, id)
+ ));
+ result = this->load_proxy(id, CosNotifyChannelAdmin::ANY_EVENT, attrs ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+ }
+ else if (type == "structured_proxy_push_consumer")
+ {
+ if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Admin reload proxy %d\n")
+ , ACE_static_cast (int, id)
+ ));
+ result = this->load_proxy(id, CosNotifyChannelAdmin::STRUCTURED_EVENT, attrs ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+ }
+ else if (type == "sequence_proxy_push_consumer")
+ {
+ if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Admin reload proxy %d\n")
+ , ACE_static_cast (int, id)
+ ));
+ result = this->load_proxy(id, CosNotifyChannelAdmin::SEQUENCE_EVENT, attrs ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+ }
+ else
+ {
+ result = TAO_Notify_Admin::load_child (type, id, attrs ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+ }
+ return result;
+}
+
+TAO_NOTIFY::Topology_Object*
+TAO_Notify_SupplierAdmin::load_proxy (
+ CORBA::Long id,
+ CosNotifyChannelAdmin::ClientType ctype,
+ const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL)
+{
+ TAO_Notify_Builder* bld = TAO_Notify_PROPERTIES::instance()->builder();
+ TAO_Notify_ProxyConsumer * proxy =
+ bld->build_proxy (this
+ , ctype
+ , id
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ ACE_ASSERT(proxy != 0);
+ proxy->load_attrs (attrs);
+ return proxy;
+}
+
+
void
TAO_Notify_SupplierAdmin::set_qos (const CosNotification::QoSProperties & qos ACE_ENV_ARG_DECL)
ACE_THROW_SPEC ((
@@ -112,11 +182,16 @@ TAO_Notify_SupplierAdmin::obtain_notification_push_consumer (CosNotifyChannelAdm
{
CosNotification::QoSProperties initial_qos;
- return TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this
+ CosNotifyChannelAdmin::ProxyConsumer_var proxy =
+ TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this
, ctype
, proxy_id
, initial_qos
ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (proxy._retn ());
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (proxy._retn ());
+ return proxy._retn ();
}
CosNotifyChannelAdmin::ProxyConsumer_ptr
@@ -131,11 +206,16 @@ TAO_Notify_SupplierAdmin::obtain_notification_push_consumer_with_qos (CosNotifyC
, CosNotification::UnsupportedQoS
))
{
- return TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this
+ CosNotifyChannelAdmin::ProxyConsumer_var proxy =
+ TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this
, ctype
, proxy_id,
initial_qos
ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (proxy._retn ());
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (proxy._retn ());
+ return proxy._retn ();
}
@@ -145,7 +225,12 @@ TAO_Notify_SupplierAdmin::obtain_push_consumer (ACE_ENV_SINGLE_ARG_DECL)
CORBA::SystemException
))
{
- return TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this ACE_ENV_ARG_PARAMETER);
+ CosEventChannelAdmin::ProxyPushConsumer_var proxy =
+ TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (proxy._retn ());
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (proxy._retn ());
+ return proxy._retn ();
}
CosNotifyChannelAdmin::AdminID
@@ -231,7 +316,12 @@ TAO_Notify_SupplierAdmin::add_filter (CosNotifyFilter::Filter_ptr new_filter ACE
CORBA::SystemException
))
{
- return this->filter_admin_.add_filter (new_filter ACE_ENV_ARG_PARAMETER);
+ CosNotifyFilter::FilterID fid =
+ this->filter_admin_.add_filter (new_filter ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (fid);
+ this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (fid);
+ return fid;
}
void
diff --git a/TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.h b/TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.h
index bb1233eeae0..020a2b817a1 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.h
@@ -37,8 +37,8 @@
* @brief Implementation of CosNotifyChannelAdmin::SupplierAdmin
*
*/
-class TAO_Notify_Serv_Export TAO_Notify_SupplierAdmin
- : public virtual POA_NotifyExt::SupplierAdmin,
+class TAO_Notify_Serv_Export TAO_Notify_SupplierAdmin
+ : public virtual POA_NotifyExt::SupplierAdmin,
public virtual TAO_Notify_Admin
{
public:
@@ -58,8 +58,22 @@ public:
/// Release
virtual void release (void);
+ virtual const char * get_admin_type_name () const;
+
+ virtual TAO_NOTIFY::Topology_Object* load_child (
+ const ACE_CString &type,
+ CORBA::Long id,
+ const TAO_NOTIFY::NVPList& attrs
+ ACE_ENV_ARG_DECL);
+
protected:
+ TAO_NOTIFY::Topology_Object *load_proxy (
+ CORBA::Long id,
+ CosNotifyChannelAdmin::ClientType ctype,
+ const TAO_NOTIFY::NVPList& attrs
+ ACE_ENV_ARG_DECL);
+
/// = NotifyExt::SupplierAdmin methods
CosNotifyChannelAdmin::ProxyConsumer_ptr
obtain_notification_push_consumer_with_qos (
@@ -103,7 +117,7 @@ protected:
ACE_THROW_SPEC ((CORBA::SystemException,
CosNotifyChannelAdmin::ProxyNotFound));
- virtual ::CosNotifyChannelAdmin::ProxyConsumer_ptr
+ virtual ::CosNotifyChannelAdmin::ProxyConsumer_ptr
obtain_notification_pull_consumer (
CosNotifyChannelAdmin::ClientType ctype,
CosNotifyChannelAdmin::ProxyID_out proxy_id
@@ -112,7 +126,7 @@ protected:
ACE_THROW_SPEC ((CORBA::SystemException,
CosNotifyChannelAdmin::AdminLimitExceeded));
- virtual ::CosNotifyChannelAdmin::ProxyConsumer_ptr
+ virtual ::CosNotifyChannelAdmin::ProxyConsumer_ptr
obtain_notification_push_consumer (
CosNotifyChannelAdmin::ClientType ctype,
CosNotifyChannelAdmin::ProxyID_out proxy_id
@@ -127,7 +141,7 @@ protected:
virtual ::CosNotification::QoSProperties* get_qos (ACE_ENV_SINGLE_ARG_DECL)
ACE_THROW_SPEC ((CORBA::SystemException));
- virtual void set_qos (const CosNotification::QoSProperties& qos
+ virtual void set_qos (const CosNotification::QoSProperties& qos
ACE_ENV_ARG_DECL)
ACE_THROW_SPEC ((CORBA::SystemException,
CosNotification::UnsupportedQoS));
@@ -160,7 +174,7 @@ protected:
CosNotifyFilter::FilterNotFound));
virtual ::CosNotifyFilter::Filter_ptr get_filter (
- CosNotifyFilter::FilterID filter
+ CosNotifyFilter::FilterID filter
ACE_ENV_ARG_DECL
)
ACE_THROW_SPEC ((CORBA::SystemException,
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Topology_Factory.h b/TAO/orbsvcs/orbsvcs/Notify/Topology_Factory.h
new file mode 100644
index 00000000000..7526159f717
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Topology_Factory.h
@@ -0,0 +1,46 @@
+/**
+ * @file Topology_Factory.h
+ *
+ * $Id$
+ *
+ * @author Dale Wilson <wilson_d@ociweb.com>
+ *
+ *
+ */
+#ifndef TAO_NOTIFY_TOPOLOGY_FACTORY_H
+#define TAO_NOTIFY_TOPOLOGY_FACTORY_H
+#include /**/ "ace/pre.h"
+
+#include "notify_serv_export.h"
+
+#include "ace/Service_Object.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+namespace TAO_NOTIFY
+{
+ class Topology_Saver;
+ class Topology_Loader;
+
+ /**
+ * @brief Service Object to allow dynamic control of the loaded saver factory.
+ *
+ */
+ class TAO_Notify_Serv_Export Topology_Factory : public ACE_Service_Object
+ {
+ public:
+ /// Create a Saver.
+ /// \return a pointer to a Topology_Saver which must be deleted
+ /// by the caller.
+ virtual Topology_Saver* create_saver () = 0;
+ /// Create a Loader
+ /// \return a pointer to a Topology_Loader which must be deleted
+ /// by the caller.
+ virtual Topology_Loader* create_loader () = 0;
+ };
+}
+
+#include /**/ "ace/post.h"
+#endif
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Topology_Loader.cpp b/TAO/orbsvcs/orbsvcs/Notify/Topology_Loader.cpp
new file mode 100644
index 00000000000..4eb9e308531
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Topology_Loader.cpp
@@ -0,0 +1,16 @@
+// $Id$
+
+#include "Topology_Loader.h"
+
+TAO_NOTIFY::Topology_Loader::Topology_Loader ()
+{
+}
+
+TAO_NOTIFY::Topology_Loader::~Topology_Loader ()
+{
+}
+
+void
+TAO_NOTIFY::Topology_Loader::close (ACE_ENV_SINGLE_ARG_DECL_NOT_USED)
+{
+}
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Topology_Loader.h b/TAO/orbsvcs/orbsvcs/Notify/Topology_Loader.h
new file mode 100644
index 00000000000..a06494c80a1
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/Notify/Topology_Loader.h
@@ -0,0 +1,73 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Topology_Loader.h
+ *
+ * $Id$
+ *
+ * @author Jonathan Pollack <pollack_j@ociweb.com>
+ */
+//=============================================================================
+
+#ifndef TOPOLOGY_LOADER_H
+#define TOPOLOGY_LOADER_H
+#include "ace/pre.h"
+
+#include "ace/config-all.h"
+
+#include "tao/corba.h"
+#include "notify_serv_export.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+namespace TAO_NOTIFY
+{
+
+/// A forward declaration.
+class Topology_Object;
+
+/**
+ * \brief An interface for an object that loads Persistent Topology Information.
+ *
+ * A persistent store must provide an implemention this interface.
+ *
+ */
+class TAO_Notify_Serv_Export Topology_Loader
+{
+public:
+ /// The constructor.
+ Topology_Loader ();
+
+ /// The destructor.
+ virtual ~Topology_Loader ();
+
+ /** \brief Begin the restore process.
+ *
+ * Call this function to start the reload of data from a persistent store.
+ * When the Topology_Loader detects a child object, it should
+ * call the load_child method of the object passed in, then do the same
+ * loading process on the returned object.
+ */
+ virtual void load (Topology_Object *root ACE_ENV_ARG_DECL) = 0;
+
+ /**
+ * \brief Close the loader after loading is complete.
+ *
+ * This is not pure virtual because some loaders may not need to be closed.
+ * The default implementation does nothing.
+ *
+ * There should be a corresponding open, but the signature may
+ * vary based on the type of loader, so we can't include it in the
+ * interface.
+ */
+ virtual void close (ACE_ENV_SINGLE_ARG_DECL);
+};
+
+} // namespace TAO_NOTIFY
+
+#include /**/ "ace/post.h"
+
+#endif /* TOPOLOGY_LOADER */
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Topology_Object.h b/TAO/orbsvcs/orbsvcs/Notify/Topology_Object.h
index de7adc1c23b..19654b3db7a 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Topology_Object.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/Topology_Object.h
@@ -123,7 +123,7 @@ namespace TAO_NOTIFY
/// the get_id returns the same thing as id -- we just need someone
/// to find it for us.
virtual TAO_Notify_Object_Id get_id () const;
-
+
/// \brief Get the path of id's from the root to this object.
void get_id_path (IdVec & id_path) const;
diff --git a/TAO/orbsvcs/orbsvcs/Notify/Topology_Object.inl b/TAO/orbsvcs/orbsvcs/Notify/Topology_Object.inl
index 1c12c7df671..6c2c3b88396 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/Topology_Object.inl
+++ b/TAO/orbsvcs/orbsvcs/Notify/Topology_Object.inl
@@ -2,7 +2,7 @@
namespace TAO_NOTIFY
{
ACE_INLINE
- bool
+ bool
Topology_Object::is_changed () const
{
return this->self_changed_ | this->children_changed_;
diff --git a/TAO/orbsvcs/orbsvcs/Notify/XML_Saver.h b/TAO/orbsvcs/orbsvcs/Notify/XML_Saver.h
index 1d5beff9e5e..e1956637a95 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/XML_Saver.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/XML_Saver.h
@@ -37,12 +37,12 @@ public:
XML_Saver (bool timestamp = true);
virtual ~XML_Saver ();
-
+
/// Open the output file.
/// \param file_name the fully qualified file name
/// \return true if successful
bool open (const ACE_CString & file_name, size_t backup_count);
-
+
//////////////////////////////////
// Override Topology_Saver methods
// see Topology_Saver.h for doc
diff --git a/TAO/orbsvcs/orbsvcs/Notify/XML_Topology_Factory.h b/TAO/orbsvcs/orbsvcs/Notify/XML_Topology_Factory.h
index e063acdbc42..97a14512cfa 100644
--- a/TAO/orbsvcs/orbsvcs/Notify/XML_Topology_Factory.h
+++ b/TAO/orbsvcs/orbsvcs/Notify/XML_Topology_Factory.h
@@ -63,7 +63,7 @@ namespace TAO_NOTIFY
// documented in ace/Shared_Object.h
virtual int init (int argc, ACE_TCHAR *argv[]);
virtual int fini ();
-
+
private:
ACE_CString save_base_path_;
ACE_CString load_base_path_;
diff --git a/TAO/orbsvcs/orbsvcs/NotifyExt.idl b/TAO/orbsvcs/orbsvcs/NotifyExt.idl
index 7c94e9bcb26..5e0d9ca9b69 100644
--- a/TAO/orbsvcs/orbsvcs/NotifyExt.idl
+++ b/TAO/orbsvcs/orbsvcs/NotifyExt.idl
@@ -83,12 +83,55 @@ module NotifyExt
unsigned long max_request_buffer_size;
};
- /*
- * Extend the EventChannelFactory to have a shutdown method.
+ /**
+ * \brief An interface which gets registered with a ReconnectionRegistry.
+ *
+ * A supplier or consumer must implement this interface in order to
+ * allow the Notification Service to attempt to reconnect to it after
+ * a failure. The supplier or consumer must register its instance of
+ * this interface with the ReconnectionRegistry.
+ */
+ interface ReconnectionCallback
+ {
+ /// Perform operations to reconnect to the Notification Service
+ /// after a failure.
+ void reconnect (in Object new_connection);
+
+ /// Check to see if the ReconnectionCallba ck is alive
+ boolean is_alive ();
+ };
+
+ /**
+ * \brief An interface that handles registration of suppliers and consumers.
+ *
+ * This registry should be implemented by an EventChannelFactory and
+ * will call the appropriate reconnect methods for all ReconnectionCallback
+ * objects registered with it.
+ */
+ interface ReconnectionRegistry
+ {
+ typedef long ReconnectionID;
+ ReconnectionID register_callback(in ReconnectionCallback reconection);
+
+ void unregister_callback (in ReconnectionID id);
+
+ /// Check to see if the ReconnectionRegistry is alive
+ boolean is_alive ();
+ };
+
+ /**
+ * Extend the EventChannelFactory to have a shutdown method
+ * and a Reconnection Registry
*/
- interface EventChannelFactory : CosNotifyChannelAdmin::EventChannelFactory
+ interface EventChannelFactory
+ : CosNotifyChannelAdmin::EventChannelFactory
+ , ReconnectionRegistry
{
void destroy ();
+ /// save topology: for diagnostic and testing purposes
+ /// Normal topology save is automatic when connectivity persistence
+ /// is configured.
+ void save_topology();
};
interface ConsumerAdmin : CosNotifyChannelAdmin::ConsumerAdmin
diff --git a/TAO/orbsvcs/tests/Notify/PluggableTopology/PlugTop.mpc b/TAO/orbsvcs/tests/Notify/PluggableTopology/PlugTop.mpc
new file mode 100644
index 00000000000..dda1bb794af
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/PluggableTopology/PlugTop.mpc
@@ -0,0 +1,19 @@
+project(*lib): orbsvcslib, notify_serv {
+ requires += exceptions;
+ sharedname = NotifyPlugTop
+ dynamicflags = PLUGTOP_BUILD_DLL
+ source_files {
+ Test_Saver.cpp
+ Test_Topology_Factory.cpp
+ }
+}
+
+project : orbsvcsexe, notify_serv {
+ requires += exceptions;
+ after += *lib
+ source_files {
+ main.cpp
+ }
+ header_files {
+ }
+}
diff --git a/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Saver.cpp b/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Saver.cpp
new file mode 100644
index 00000000000..567979e64c2
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Saver.cpp
@@ -0,0 +1,37 @@
+// $Id$
+
+#include "Test_Saver.h"
+
+#include <ace/streams.h>
+
+Test_Saver::Test_Saver()
+{
+}
+
+bool
+Test_Saver::begin_object(CORBA::Long id,
+ const ACE_CString &type,
+ const TAO_NOTIFY::NVPList& attrs,
+ bool changed
+ ACE_ENV_ARG_DECL_NOT_USED)
+{
+ cout << "Test_Saver::begin_object type=\"" << type << "\" "
+ << " id=" << id
+ << " changed=\"" << changed << "\"";
+ for (size_t idx = 0; idx < attrs.size(); idx++)
+ {
+ cout << " " << attrs[idx].name << "=\"" << attrs[idx].value << "\"";
+ }
+ cout << endl;
+ return true;
+}
+
+void
+Test_Saver::end_object (CORBA::Long id,
+ const ACE_CString &type ACE_ENV_ARG_DECL_NOT_USED)
+{
+ cout << "Test_Saver::end_object type=\"" << type << "\""
+ << " id=" << id
+ << endl;
+}
+
diff --git a/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Saver.h b/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Saver.h
new file mode 100644
index 00000000000..ce95cb0781c
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Saver.h
@@ -0,0 +1,39 @@
+/* -*- C++ -*- */
+/**
+ * $Id$
+ */
+
+#ifndef TEST_SAVER_H
+#define TEST_SAVER_H
+#include /**/ "ace/pre.h"
+
+#include "plugtop_export.h"
+
+#include "orbsvcs/Notify/Topology_Saver.h"
+
+#include "tao/corba.h"
+#include "ace/streams.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+class PLUGTOP_Export Test_Saver : public TAO_NOTIFY::Topology_Saver
+{
+public:
+ Test_Saver();
+
+ virtual bool begin_object (CORBA::Long id,
+ const ACE_CString &type,
+ const TAO_NOTIFY::NVPList& attrs,
+ bool changed
+ ACE_ENV_ARG_DECL);
+
+ virtual void end_object (CORBA::Long id,
+ const ACE_CString &type
+ ACE_ENV_ARG_DECL);
+};
+
+
+#include /**/ "ace/post.h"
+#endif /* TEST_SAVER_H */
diff --git a/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.cpp b/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.cpp
new file mode 100644
index 00000000000..fdab5be129c
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.cpp
@@ -0,0 +1,26 @@
+// $Id$
+
+#include "Test_Topology_Factory.h"
+#include "Test_Saver.h"
+
+Test_Topology_Factory::Test_Topology_Factory()
+{
+}
+
+TAO_NOTIFY::Topology_Saver*
+Test_Topology_Factory::create_saver ()
+{
+ TAO_NOTIFY::Topology_Saver *saver = 0;
+ ACE_NEW_RETURN (saver, Test_Saver, 0);
+ return saver;
+}
+
+//virtual
+TAO_NOTIFY::Topology_Loader*
+Test_Topology_Factory::create_loader ()
+{
+ return 0;
+}
+
+
+ACE_FACTORY_DEFINE (PLUGTOP, Test_Topology_Factory)
diff --git a/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.h b/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.h
new file mode 100644
index 00000000000..6b76b1a2205
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.h
@@ -0,0 +1,31 @@
+/* -*- C++ -*- */
+//$Id$
+
+#ifndef TEST_TOPOLOGY_FACTORY_H
+#define TEST_TOPOLOGY_FACTORY_H
+#include /**/ "ace/pre.h"
+
+#include "plugtop_export.h"
+
+#include "orbsvcs/Notify/Topology_Factory.h"
+
+#include "tao/corba.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+class PLUGTOP_Export Test_Topology_Factory : public TAO_NOTIFY::Topology_Factory
+{
+public:
+ Test_Topology_Factory ();
+ /////////////////////////////////////////////////
+ // override virtual methods from Topology_Factory
+ virtual TAO_NOTIFY::Topology_Saver* create_saver ();
+ virtual TAO_NOTIFY::Topology_Loader* create_loader ();
+};
+
+ACE_FACTORY_DECLARE (PLUGTOP, Test_Topology_Factory)
+
+#include /**/ "ace/post.h"
+#endif /* TEST_TOPOLOGY_FACTORY_H */
diff --git a/TAO/orbsvcs/tests/Notify/PluggableTopology/main.cpp b/TAO/orbsvcs/tests/Notify/PluggableTopology/main.cpp
new file mode 100644
index 00000000000..786728187fa
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/PluggableTopology/main.cpp
@@ -0,0 +1,109 @@
+/**
+ * $Id$
+ */
+
+#include <orbsvcs/CosNotifyChannelAdminC.h>
+//#include <orbsvcs/CosNotifyCommS.h>
+//#include <orbsvcs/CosNotificationS.h>
+#include <tao/TimeBaseC.h>
+
+#include <ace/ARGV.h>
+#include <ace/OS_NS_stdio.h>
+
+using namespace CORBA;
+namespace CNCA = CosNotifyChannelAdmin;
+namespace CN = CosNotification;
+namespace CNC = CosNotifyComm;
+
+const char* NOTIFY_IOR = "corbaloc::localhost:9050/NotifyEventChannelFactory";
+
+ORB_var orb;
+CNCA::EventChannelFactory_var ecf;
+
+namespace {
+ void init_qos_props(CN::QoSProperties& qos, bool topology_persist) {
+ qos.length(13);
+ ULong i = 0;
+ qos[i].name = "EventReliability";
+ qos[i++].value <<= CN::BestEffort;
+ if (topology_persist) {
+ qos[i].name = "ConnectionReliability";
+ qos[i++].value <<= CN::Persistent;
+ }
+ else
+ {
+ qos[i].name = "ConnectionReliability";
+ qos[i++].value <<= CN::BestEffort;
+ }
+ qos[i].name = "Priority";
+ qos[i++].value <<= (Short) 1234;
+ qos[i].name = "Timeout";
+ qos[i++].value <<= (TimeBase::TimeT) 55555;
+ qos[i].name = "MaximumBatchSize";
+ qos[i++].value <<= (Long) 200;
+ qos[i].name = "PacingInterval";
+ qos[i++].value <<= (TimeBase::TimeT) 42000;
+ qos[i].name = "StopTimeSupported";
+ qos[i++].value <<= Any::from_boolean(0);
+ qos.length(i);
+ }
+ void init_admin_props(CN::AdminProperties& admin) {
+ admin.length(13);
+ ULong i = 0;
+ admin[i].name = "MaxQueueLength";
+ admin[i++].value <<= (Long) 200;
+ admin[i].name = "MaxConsumers";
+ admin[i++].value <<= (Long) 2;
+ admin[i].name = "MaxSuppliers";
+ admin[i++].value <<= (Long) 1;
+ admin[i].name = "RejectNewEvents";
+ admin[i++].value <<= Any::from_boolean(1);
+ }
+ void setUp()
+ {
+ ACE_ARGV av;
+ int ac = 0;
+ orb = ORB_init(ac, av.argv());
+ ACE_ASSERT(! is_nil(orb.in()));
+ Object_var obj = orb->string_to_object(NOTIFY_IOR);
+ ACE_ASSERT(! is_nil(obj.in()));
+ ecf = CNCA::EventChannelFactory::_narrow(obj.in());
+ ACE_ASSERT(! is_nil(ecf.in()));
+ }
+
+ void tearDown()
+ {
+ ecf = CNCA::EventChannelFactory::_nil();
+ orb->destroy();
+ orb = ORB::_nil();
+ }
+}
+
+
+int main(int, char**)
+{
+ try
+ {
+ setUp();
+
+ CN::QoSProperties qos;
+ CN::AdminProperties admin;
+ init_qos_props(qos, true);
+ init_admin_props(admin);
+
+ CNCA::ChannelID ecid;
+ CNCA::EventChannel_var ec = ecf->create_channel(qos, admin, ecid);
+
+ printf("Created channel id=\"%ld\"\n", static_cast<long>(ecid));
+
+ tearDown();
+
+ return 0;
+ }
+ catch (Exception& e)
+ {
+ ACE_OS::fputs(e._name (), stderr);
+ ACE_OS::fputs("\n", stderr);
+ }
+ return 1;
+}
diff --git a/TAO/orbsvcs/tests/Notify/PluggableTopology/plugtop_export.h b/TAO/orbsvcs/tests/Notify/PluggableTopology/plugtop_export.h
new file mode 100644
index 00000000000..fe7fbfbee28
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/PluggableTopology/plugtop_export.h
@@ -0,0 +1,40 @@
+
+// -*- C++ -*-
+// $Id$
+// Definition for Win32 Export directives.
+// This file is generated automatically by generate_export_file.pl
+// ------------------------------
+#ifndef PLUGTOP_EXPORT_H
+#define PLUGTOP_EXPORT_H
+
+#include "ace/config-all.h"
+
+#if defined (TAO_AS_STATIC_LIBS)
+# if !defined (PLUGTOP_HAS_DLL)
+# define PLUGTOP_HAS_DLL 0
+# endif /* ! PLUGTOP_HAS_DLL */
+#else
+# if !defined (PLUGTOP_HAS_DLL)
+# define PLUGTOP_HAS_DLL 1
+# endif /* ! PLUGTOP_HAS_DLL */
+#endif
+
+#if defined (PLUGTOP_HAS_DLL) && (PLUGTOP_HAS_DLL == 1)
+# if defined (PLUGTOP_BUILD_DLL)
+# define PLUGTOP_Export ACE_Proper_Export_Flag
+# define PLUGTOP_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T)
+# define PLUGTOP_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
+# else /* PLUGTOP_BUILD_DLL */
+# define PLUGTOP_Export ACE_Proper_Import_Flag
+# define PLUGTOP_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T)
+# define PLUGTOP_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
+# endif /* PLUGTOP_BUILD_DLL */
+#else /* PLUGTOP_HAS_DLL == 1 */
+# define PLUGTOP_Export
+# define PLUGTOP_SINGLETON_DECLARATION(T)
+# define PLUGTOP_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
+#endif /* PLUGTOP_HAS_DLL == 1 */
+
+#endif /* PLUGTOP_EXPORT_H */
+
+// End of auto generated file.
diff --git a/TAO/orbsvcs/tests/Notify/PluggableTopology/plugtop_ns.conf b/TAO/orbsvcs/tests/Notify/PluggableTopology/plugtop_ns.conf
new file mode 100644
index 00000000000..63b5faf531b
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/PluggableTopology/plugtop_ns.conf
@@ -0,0 +1,3 @@
+
+dynamic TopologyFactory Service_Object * NotifyPlugTop:_make_Test_Topology_Factory() ""
+#dynamic TopologyFactory Service_Object * TAO_CosNotification:_make_XML_Topology_Factory() "" \ No newline at end of file
diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/Consumer.cpp b/TAO/orbsvcs/tests/Notify/Reconnecting/Consumer.cpp
new file mode 100644
index 00000000000..d2837a547b4
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/Reconnecting/Consumer.cpp
@@ -0,0 +1,1878 @@
+//$Id$
+
+#include "Consumer.h"
+#include "tao/debug.h"
+#include "tao/PortableServer/PortableServerC.h"
+#include <tao/TimeBaseC.h>
+#include <ace/OS_NS_strings.h>
+#include <ace/OS_NS_stdio.h>
+#include <tao/Any.h>
+
+ACE_RCSID (Notify_Tests, Consumer_Main, "$Id$")
+
+static const char NOTIFY_FACTORY_NAME[] = "NotifyEventChannelFactory";
+static const char NAMING_SERVICE_NAME[] = "NameService";
+
+static const size_t minus_one = ACE_static_cast (size_t, -1);
+
+///////////////////////////
+// StructuredPushConsumer_i
+
+StructuredPushConsumer_i::StructuredPushConsumer_i ()
+ : verbose_ (false)
+ , received_ (0)
+ , expect_ (10)
+ , fail_ (0)
+ , may_discard_ (0)
+ , serial_number_ (0)
+ , exceptions_thrown_ (0)
+ , problem_ (false)
+ , connected_ (false)
+{
+}
+
+size_t
+StructuredPushConsumer_i::received () const
+{
+ return this->received_;
+}
+
+bool
+StructuredPushConsumer_i::has_problem () const
+{
+ return this->problem_;
+}
+
+void
+StructuredPushConsumer_i::set_connected (bool flag)
+{
+ this->connected_ = flag;
+}
+
+bool
+StructuredPushConsumer_i::is_connected () const
+{
+ return this->connected_;
+}
+
+void
+StructuredPushConsumer_i::set_expectations (size_t expected, size_t fail, size_t serial_number, bool verbose)
+{
+ this->expect_ = expected;
+ this->fail_ = fail;
+ this->serial_number_ = serial_number;
+ this->verbose_ = verbose;
+}
+
+void
+StructuredPushConsumer_i::offer_change (
+ const CosNotification::EventTypeSeq & added,
+ const CosNotification::EventTypeSeq & removed
+ ACE_ENV_ARG_DECL_NOT_USED
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ CosNotifyComm::InvalidEventType))
+{
+ ACE_UNUSED_ARG (added);
+ ACE_UNUSED_ARG (removed);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) StructuredPushConsumer offered change \n")
+ ));
+}
+
+void
+StructuredPushConsumer_i::check_serial_number (CORBA::ULong seq)
+{
+ if (this->serial_number_ == minus_one)
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Structured Consumer received event %d.\n"),
+ ACE_static_cast (int, seq)
+ ));
+ }
+ }
+ else
+ {
+ if (seq == this->serial_number_)
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Structured Consumer received correct event %d.\n"),
+ ACE_static_cast (int, seq)
+ ));
+ }
+ }
+ else if ((seq - this->serial_number_) <= this->may_discard_)
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Structured Consumer: service received event %d; Notify discarded %d*.\n"),
+ ACE_static_cast (int, seq),
+ ACE_static_cast (int, this->serial_number_)
+ ));
+ }
+ this->received_ += seq - this->serial_number_;
+ }
+ else
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Structured Consumer received notifications out of sequence. Expecting %d received %d.\n"),
+ ACE_static_cast (int, this->serial_number_),
+ ACE_static_cast (int, seq)
+ ));
+ }
+ this->serial_number_ = seq + 1;
+ }
+ may_discard_ = 0;
+}
+
+
+void
+StructuredPushConsumer_i::push_structured_event (
+ const CosNotification::StructuredEvent & notification
+ ACE_ENV_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException,
+ CosEventComm::Disconnected))
+{
+ this->received_ += 1;
+ if (this->received_ == this->expect_ + 1)
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Structured Consumer received more than the %d events that were expected.\n"),
+ this->expect_
+ ));
+ }
+ if (this->fail_ != 0 && ((this->received_ + this->exceptions_thrown_) % this->fail_) == 0)
+ {
+ this->received_ -= 1;
+ this->exceptions_thrown_ += 1;
+ this->may_discard_ = 1;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Structured Consumer failing at event # %d.\n"),
+ ACE_static_cast (int, this->received_)
+ ));
+ ACE_THROW (CORBA::UNKNOWN());
+ ACE_CHECK;
+ }
+ if (notification.filterable_data.length () > 0)
+ {
+ if (0 == ACE_OS::strcmp (notification.filterable_data[0].name, "serial_number"))
+ {
+ const CORBA::Any & data = notification.filterable_data[0].value;
+
+ CORBA::ULong seq = 0;
+ if (data >>= seq)
+ {
+ check_serial_number (seq);
+ }
+ else
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Structured Consumer received unexpected data type for serial_number.\n")
+ ));
+ }
+ }
+ else
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Structured Consumer received wrong filterable data name.%s. Expecting serial_number\n"),
+ ACE_static_cast (const char *, notification.filterable_data[0].name)
+ ));
+ }
+ }
+ else if (0 == ACE_OS::strcmp (notification.header.fixed_header.event_type.type_name, "%ANY")
+ && 0 == strcmp (notification.header.fixed_header.event_type.domain_name, ""))
+ {
+ const CORBA::Any * any;
+ if (notification.remainder_of_body >>= any)
+ {
+ // this is a wrapped "Any"
+ CORBA::ULong seq = 0;
+ if ((*any) >>= seq)
+ {
+ check_serial_number (seq);
+ }
+ else
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Structured Consumer received Any with unknown data type\n")
+ ));
+ }
+ }
+ else
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Structured Consumer received remainder_of_body with unknown data type\n")
+ ));
+ }
+ }
+ else
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Structured Consumer: no filterable data. \n")
+ ));
+ }
+ this->may_discard_ = 0;
+}
+
+void
+StructuredPushConsumer_i::disconnect_structured_push_consumer (
+ ACE_ENV_SINGLE_ARG_DECL_NOT_USED
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) StructuredPushConsumer received disconnect\n")
+ ));
+}
+
+///////////////////////////
+// SequencePushConsumer_i
+
+SequencePushConsumer_i::SequencePushConsumer_i ()
+ : verbose_ (false)
+ , received_ (0)
+ , expect_ (10)
+ , fail_ (0)
+ , may_discard_ (0)
+ , serial_number_ (0)
+ , exceptions_thrown_ (0)
+ , problem_ (false)
+ , connected_ (false)
+{
+}
+
+size_t
+SequencePushConsumer_i::received () const
+{
+ return this->received_;
+}
+
+bool
+SequencePushConsumer_i::has_problem () const
+{
+ return this->problem_;
+}
+
+void
+SequencePushConsumer_i::set_connected (bool flag)
+{
+ this->connected_ = flag;
+}
+
+bool
+SequencePushConsumer_i::is_connected () const
+{
+ return this->connected_;
+}
+
+void
+SequencePushConsumer_i::set_expectations (size_t expected, size_t fail,size_t serial_number, bool verbose)
+{
+ this->expect_ = expected;
+ this->fail_ = fail;
+ this->serial_number_ = serial_number;
+ this->verbose_ = verbose;
+}
+
+void
+SequencePushConsumer_i::offer_change (
+ const CosNotification::EventTypeSeq & added,
+ const CosNotification::EventTypeSeq & removed
+ ACE_ENV_ARG_DECL_NOT_USED
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ CosNotifyComm::InvalidEventType))
+{
+ ACE_UNUSED_ARG (added);
+ ACE_UNUSED_ARG (removed);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) SequencePushConsumer offered subscription change\n")
+ ));
+}
+
+void
+SequencePushConsumer_i::check_serial_number (CORBA::ULong seq)
+{
+ if (this->serial_number_ == minus_one)
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Sequence Consumer received event %d.\n"),
+ ACE_static_cast (int, seq)
+ ));
+ }
+ }
+ else
+ {
+ if (seq == this->serial_number_)
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Sequence Consumer received correct event %d.\n"),
+ ACE_static_cast (int, seq)
+ ));
+ }
+ }
+ else if ((seq - this->serial_number_) <= this->may_discard_)
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Sequence Consumer: service received event %d; Notify discarded %d*.\n"),
+ ACE_static_cast (int, seq),
+ ACE_static_cast (int, this->serial_number_)
+ ));
+ }
+ this->received_ += seq - this->serial_number_;
+ }
+ else
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Sequence Consumer received notifications out of sequence. Expecting %d received %d.\n"),
+ ACE_static_cast (int, this->serial_number_),
+ ACE_static_cast (int, seq)
+ ));
+ }
+ this->serial_number_ = seq + 1;
+ }
+ may_discard_ = 0;
+}
+
+void
+SequencePushConsumer_i::push_structured_events (
+ const CosNotification::EventBatch & notifications
+ ACE_ENV_ARG_DECL
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException,
+ CosEventComm::Disconnected))
+{
+ size_t batch_size = notifications.length();
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Sequence Consumer received batch of %d events.\n"),
+ ACE_static_cast (int, batch_size)
+ ));
+ }
+ for (size_t nevent = 0; nevent < batch_size; ++nevent)
+ {
+ this->received_ += 1;
+ if (this->received_ == this->expect_ + 1)
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Sequence Consumer received more than the %d events that were expected.\n"),
+ this->expect_
+ ));
+ }
+ if (this->fail_ != 0 && ((this->received_ + this->exceptions_thrown_) % this->fail_) == 0)
+ {
+ this->received_ -= 1;
+ this->exceptions_thrown_ += 1;
+ this->may_discard_ = batch_size;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Sequence Consumer failing at event # %d. Expecting %d duplicates.\n"),
+ ACE_static_cast (int, this->received_),
+ ACE_static_cast (int, nevent + 1)
+ ));
+ ACE_THROW (CORBA::UNKNOWN());
+ ACE_CHECK;
+ }
+ const CosNotification::StructuredEvent & notification = notifications[nevent];
+ if (notification.filterable_data.length () > 0)
+ {
+ if (0 == ACE_OS::strcmp (notification.filterable_data[0].name, "serial_number"))
+ {
+ const CORBA::Any & data = notification.filterable_data[0].value;
+
+ CORBA::ULong seq = 0;
+ if (data >>= seq)
+ {
+ check_serial_number (seq);
+ }
+ else
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Sequence Consumer received unexpected data type for serial_number.\n")
+ ));
+ }
+ }
+ else
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Sequence Consumer received wrong filterable data name.%s. Expecting serial_number\n"),
+ ACE_static_cast (const char *, notification.filterable_data[0].name)
+ ));
+ }
+ }
+ else if (0 == ACE_OS::strcmp (notification.header.fixed_header.event_type.type_name, "%ANY")
+ && 0 == strcmp (notification.header.fixed_header.event_type.domain_name, ""))
+ {
+ CORBA::ULong seq = 0;
+ if (notification.remainder_of_body >>= seq)
+ {
+ check_serial_number (seq);
+ }
+ else
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Sequence Consumer received Any with unknown data type\n")
+ ));
+ }
+ }
+ else
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Sequence Consumer received no filterable data\n")
+ ));
+ }
+ }
+}
+
+void
+SequencePushConsumer_i::disconnect_sequence_push_consumer (
+ ACE_ENV_SINGLE_ARG_DECL_NOT_USED
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) SequencePushConsumer received disconnect\n")
+ ));
+}
+
+///////////////////////////
+// AnyPushConsumer_i
+
+AnyPushConsumer_i::AnyPushConsumer_i ()
+ : verbose_ (false)
+ , received_ (0)
+ , expect_ (10)
+ , fail_ (0)
+ , may_discard_ (0)
+ , serial_number_ (0)
+ , exceptions_thrown_ (0)
+ , problem_ (false)
+ , connected_ (false)
+{
+}
+
+size_t
+AnyPushConsumer_i::received () const
+{
+ return this->received_;
+}
+
+bool
+AnyPushConsumer_i::has_problem () const
+{
+ return this->problem_;
+}
+
+void
+AnyPushConsumer_i::set_connected (bool flag)
+{
+ this->connected_ = flag;
+}
+
+bool
+AnyPushConsumer_i::is_connected () const
+{
+ return this->connected_;
+}
+
+void
+AnyPushConsumer_i::set_expectations (size_t expected, size_t fail, size_t serial_number, bool verbose)
+{
+ this->expect_ = expected;
+ this->fail_ = fail;
+ this->serial_number_ = serial_number;
+ this->verbose_ = verbose;
+}
+
+void
+AnyPushConsumer_i::offer_change (
+ const CosNotification::EventTypeSeq & added,
+ const CosNotification::EventTypeSeq & removed
+ ACE_ENV_ARG_DECL_NOT_USED
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ CosNotifyComm::InvalidEventType))
+{
+ ACE_UNUSED_ARG (added);
+ ACE_UNUSED_ARG (removed);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) SequencePushConsumer offered subscription change\n")
+ ));
+}
+
+void
+AnyPushConsumer_i::check_serial_number (CORBA::ULong seq)
+{
+ if (this->serial_number_ == minus_one)
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Any Consumer received event %d.\n"),
+ ACE_static_cast (int, seq)
+ ));
+ }
+ }
+ else
+ {
+ if (seq == this->serial_number_)
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Any Consumer received correct event %d.\n"),
+ ACE_static_cast (int, seq)
+ ));
+ }
+ }
+ else if ((seq - this->serial_number_) <= this->may_discard_)
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Any Consumer: service received event %d; Notify discarded %d*.\n"),
+ ACE_static_cast (int, seq),
+ ACE_static_cast (int, this->serial_number_)
+ ));
+ }
+ this->received_ += seq - this->serial_number_;
+ }
+ else
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Any Consumer received notifications out of sequence. Expecting %d received %d.\n"),
+ ACE_static_cast (int, this->serial_number_),
+ ACE_static_cast (int, seq)
+ ));
+ }
+ this->serial_number_ = seq + 1;
+ }
+ may_discard_ = 0;
+}
+
+void
+AnyPushConsumer_i::push (
+ const CORBA::Any & data
+ ACE_ENV_ARG_DECL
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException,
+ CosEventComm::Disconnected))
+{
+ this->received_ += 1;
+ if (this->received_ == this->expect_ + 1)
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Any Consumer received more than the %d events that were expected.\n"),
+ this->expect_
+ ));
+ }
+ if (this->fail_ != 0 && ((this->received_ + this->exceptions_thrown_) % this->fail_) == 0)
+ {
+ this->received_ -= 1;
+ this->exceptions_thrown_ += 1;
+ this->may_discard_ = 1;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Any Consumer failing at event # %d.\n"),
+ ACE_static_cast (int, this->received_)
+ ));
+ ACE_THROW (CORBA::UNKNOWN());
+ ACE_CHECK;
+ }
+ CORBA::ULong seq = 0;
+ if (data >>= seq)
+ {
+ check_serial_number (seq);
+ }
+ else
+ {
+ const CosNotification::StructuredEvent * notification;
+ if (data >>= notification)
+ {
+ if (notification->filterable_data.length () > 0)
+ {
+ if (0 == ACE_OS::strcmp (notification->filterable_data[0].name, "serial_number"))
+ {
+ const CORBA::Any & data = notification->filterable_data[0].value;
+
+ CORBA::ULong seq = 0;
+ if (data >>= seq)
+ {
+ check_serial_number (seq);
+ }
+ else
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Any Consumer received structured notification with unexpected data type for serial_number in structured event.\n")
+ ));
+ }
+ }
+ else
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Any Consumer received wrong filterable data name in structured event: %s. Expecting serial_number\n"),
+ ACE_static_cast (const char *, notification->filterable_data[0].name)
+ ));
+ }
+ }
+ else
+ {
+ this->problem_ = true;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Any Consumer: no filterable data in structured event. \n")
+ ));
+ }
+ }
+ else
+ {
+ this->problem_ = true;
+
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Any Consumer received unexpected data type.\n")
+ ));
+ }
+ }
+}
+
+void
+AnyPushConsumer_i::disconnect_push_consumer (
+ ACE_ENV_SINGLE_ARG_DECL_NOT_USED
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) AnyPushConsumer received disconnect\n")
+ ));
+}
+
+/////////////////////////
+// ReconnectionCallback_i
+
+ReconnectionCallback_i::ReconnectionCallback_i (Consumer_Main & consumer_main)
+ : consumer_main_ (consumer_main)
+ , id_is_valid_ (false)
+ , reconnect_count_ (0)
+{
+}
+
+size_t
+ReconnectionCallback_i::reconnect_count () const
+{
+ return this->reconnect_count_;
+}
+
+void
+ReconnectionCallback_i::reconnect (
+ CORBA::Object_ptr reconnection
+ ACE_ENV_ARG_DECL
+ ) ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer received reconnection request\n")
+ ));
+ this->ecf_ = CosNotifyChannelAdmin::EventChannelFactory::_narrow (reconnection ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ if (!CORBA::is_nil (this->ecf_.in ()))
+ {
+ this->consumer_main_.reconnect (this->ecf_.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ this->reconnect_count_ += 1;
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer reconnection request failed: wrong object type\n")
+ ));
+ }
+}
+
+CORBA::Boolean
+ReconnectionCallback_i::is_alive (ACE_ENV_SINGLE_ARG_DECL_NOT_USED)
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ return CORBA::Boolean (1);
+}
+
+
+ReconnectionCallback_i::~ReconnectionCallback_i ()
+{
+ // normally you would disconnect from registry here, but
+ // to simulate a failure, we exit without cleaning up
+ // if the fini method is not called.
+}
+
+
+void
+ReconnectionCallback_i::fini (ACE_ENV_SINGLE_ARG_DECL)
+{
+ if (this->id_is_valid_)
+ {
+ NotifyExt::ReconnectionRegistry_var registry =
+ NotifyExt::ReconnectionRegistry::_narrow (this->ecf_.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ registry->unregister_callback (this->callback_id_ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ this->id_is_valid_ = false;
+ }
+}
+
+void
+ReconnectionCallback_i::init (
+ PortableServer::POA_ptr poa,
+ CosNotifyChannelAdmin::EventChannelFactory_ptr ecf
+ ACE_ENV_ARG_DECL)
+{
+ this->ecf_ = CosNotifyChannelAdmin::EventChannelFactory::_duplicate (ecf);
+ PortableServer::ObjectId_var reconnection_callback_id =
+ poa->activate_object (this ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ CORBA::Object_var obj =
+ poa->id_to_reference (reconnection_callback_id.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ NotifyExt::ReconnectionCallback_var callback =
+ NotifyExt::ReconnectionCallback::_narrow (obj.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ NotifyExt::ReconnectionRegistry_var registry =
+ NotifyExt::ReconnectionRegistry::_narrow (ecf ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ this->callback_id_ = registry->register_callback (callback.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ this->id_is_valid_ = true;
+}
+
+/////////////////
+// Consumer_Main
+
+Consumer_Main::Consumer_Main ()
+ : verbose_ (false)
+ , mode_ (MODE_ANY)
+ , expect_ (10)
+ , fail_ (0)
+ , use_naming_service_ (true)
+ , serial_number_ (0)
+ , disconnect_on_exit_ (false)
+ , id_file_ ("consumer.ids")
+ , reconnection_callback_ (*this)
+ , reconnecting_ (false)
+{
+}
+
+Consumer_Main::~Consumer_Main ()
+{
+}
+
+int
+Consumer_Main::parse_args (int argc, char *argv[])
+{
+ int result = 0;
+ int narg = 1;
+ bool corba_arg = false;
+ while (narg < argc && result == 0)
+ {
+ int consumed = parse_single_arg (argc - narg, &argv[narg]);
+ if ( consumed > 0)
+ {
+ narg += consumed;
+ corba_arg = false;
+ }
+ else if (ACE_OS::strncmp (argv[narg], "-ORB", 4) == 0)
+ {
+ corba_arg = true;
+ }
+ else if (corba_arg)
+ {
+ // previous argument was a ORB arg.
+ // current argument is unrecognized
+ // assume the ORB eats this arg
+ narg += 1;
+ corba_arg = false;
+ }
+ else
+ {
+ ACE_OS::fprintf (stderr, ACE_TEXT ("Unrecognized argument: %s\n"),
+ argv[narg]);
+ usage (stderr);
+ result = -1;
+ }
+ }
+ return result;
+}
+
+int
+Consumer_Main::parse_single_arg (int argc, char *argv[])
+{
+ int consumed = 0;
+ if (ACE_OS::strcasecmp (argv[0], "-any") == 0)
+ {
+ this->mode_ = MODE_ANY;
+ consumed = 1;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], "-structured") == 0)
+ {
+ this->mode_ = MODE_STRUCTURED;
+ consumed = 1;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], "-sequence") == 0)
+ {
+ this->mode_ = MODE_SEQUENCE;
+ consumed = 1;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], "-v") == 0)
+ {
+ this->verbose_ = true;
+ consumed = 1;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], "-channel") == 0)
+ {
+ this->channel_file_= argv[1];
+ consumed = 2;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], "-expect") == 0 && argc > 1)
+ {
+ this->expect_ = ACE_OS::atoi (argv[1]);
+ consumed = 2;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], "-fail") == 0 && argc > 1)
+ {
+ this->fail_ = ACE_OS::atoi (argv[1]);
+ consumed = 2;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], "-serial_number") == 0)
+ {
+ this->serial_number_= ACE_OS::atoi (argv[1]);
+ consumed = 2;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], "-nonamesvc") == 0)
+ {
+ this->use_naming_service_ = false;
+ consumed = 1;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], "-disconnect") == 0)
+ {
+ this->disconnect_on_exit_ = true;
+ consumed = 1;
+ }
+ return consumed;
+}
+
+void Consumer_Main::usage(FILE * out)const
+{
+ ACE_OS::fputs (
+ ACE_TEXT ("usage\n")
+ ACE_TEXT (" -channel filename Where to find a channel number.\n")
+ ACE_TEXT (" -any or -structured or -sequence\n")
+ ACE_TEXT (" What type of event to send (pick one, default is -any)\n")
+ ACE_TEXT (" -expect n How many events of each type are expected.\n")
+ ACE_TEXT (" -fail n Throw an exception every n events.\n")
+ ACE_TEXT (" -serial_number n What serial number to start with \n")
+ ACE_TEXT (" or -1 to disable serial number checking.\n")
+ ACE_TEXT (" -v Verbose output.\n")
+ ACE_TEXT (" -disconnect Disconnect from channel on exit (prevents reconnect.) \n")
+ ACE_TEXT (" -nonamesvc Don't use the name service to find EventChannelFactory\n")
+ , out);
+}
+
+int Consumer_Main::init (int argc, char *argv[] ACE_ENV_ARG_DECL)
+{
+ this->orb_ = CORBA::ORB_init(argc, argv, "" ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+
+ if (0 != this->parse_args(argc, argv))
+ {
+ return -1;
+ }
+
+ CORBA::Object_ptr poa_object =
+ this->orb_->resolve_initial_references("RootPOA"
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+
+ if (CORBA::is_nil (poa_object))
+ {
+ ACE_ERROR ((LM_ERROR,
+ " (%P|%t) Unable to initialize the POA.\n"));
+ return -1;
+ }
+
+ this->root_poa_ =
+ PortableServer::POA::_narrow (poa_object ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+
+ PortableServer::POAManager_var poa_manager =
+ root_poa_->the_POAManager (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+
+ poa_manager->activate (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+
+ if (this->use_naming_service_ )
+ {
+ this->find_notify_factory (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+ }
+ else
+ {
+ int ok = resolve_notify_factory (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+ if (!ok)
+ {
+ return -1;
+ }
+ }
+
+ this->reconnecting_ = load_ids ();
+
+ init_event_channel (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+
+ init_consumer_admin (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+
+ switch (this->mode_)
+ {
+ case MODE_STRUCTURED:
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) Consumer: Listening for %d structured events. Failing every %d events.\n"),
+ ACE_static_cast (int, this->expect_),
+ ACE_static_cast (int, this->fail_)
+ ));
+ }
+ this->structured_push_consumer_.set_expectations (this->expect_, this->fail_, this->serial_number_, this->verbose_);
+ init_structured_proxy_supplier (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+ break;
+ }
+ case MODE_SEQUENCE:
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) Consumer: Listening for %d sequence events. Failing every %d events.\n"),
+ ACE_static_cast (int, this->expect_),
+ ACE_static_cast (int, this->fail_)
+ ));
+ }
+ this->sequence_push_consumer_.set_expectations (this->expect_, this->fail_, this->serial_number_, this->verbose_);
+ init_sequence_proxy_supplier (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+ break;
+ }
+ case MODE_ANY:
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) Consumer: Listening for %d CORBA::Any events. Failing every %d events.\n"),
+ ACE_static_cast (int, this->expect_),
+ ACE_static_cast (int, this->fail_)
+ ));
+ }
+ this->any_push_consumer_.set_expectations (this->expect_, this->fail_, this->serial_number_, this->verbose_);
+ init_any_proxy_supplier (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+ break;
+ }
+ default:
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Consumer: Unknown listening mode.\n")
+ ));
+ break;
+ }
+ }
+
+ this->reconnection_callback_.init (
+ this->root_poa_.in (),
+ this->ecf_.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+
+ save_ids ();
+ return 0;
+}
+void
+Consumer_Main::save_ids()
+{
+ FILE *idf =
+ ACE_OS::fopen (this->id_file_.c_str (), "w");
+
+ if (idf != 0)
+ {
+ int endflag = 12345;
+ int imode = ACE_static_cast (int, this->mode_);
+ ACE_OS::fprintf (idf,
+ "%d,%d,%d,%d,%d,%d,%d,\n",
+ imode,
+ ec_id_,
+ sa_id_,
+ structured_proxy_id_,
+ sequence_proxy_id_,
+ any_proxy_id_,
+ endflag);
+ ACE_OS::fclose (idf);
+ }
+}
+
+bool
+Consumer_Main::load_ids()
+{
+ bool ok = false;
+ FILE *idf =
+ ACE_OS::fopen (this->id_file_.c_str (), "w");
+
+ if (idf != 0)
+ {
+ int field = 0;
+
+ char buffer[100];
+ ACE_OS::fgets (buffer, sizeof(buffer), idf);
+ ACE_OS::fclose (idf);
+ char * pb = buffer;
+ while (*pb != 0)
+ {
+ char * eb = ACE_OS::strchr (pb, ',');
+ char * nb = eb + 1;
+ if (eb == 0)
+ {
+ eb = pb + ACE_OS::strlen (pb);
+ nb = eb;
+ }
+ else
+ {
+ *eb = 0;
+ }
+ if (pb < eb)
+ {
+ int value = ACE_OS::atoi(pb);
+ switch (field)
+ {
+ case 1:
+ this->mode_ = static_cast<Mode_T> (value);
+ break;
+ case 2:
+ this->ec_id_ = value;
+ break;
+ case 3:
+ this->sa_id_ = value;
+ break;
+ case 4:
+ this->structured_proxy_id_ = value;
+ break;
+ case 5:
+ this->sequence_proxy_id_ = value;
+ break;
+ case 6:
+ this->any_proxy_id_ = value;
+ break;
+ case 7:
+ ok = value == 12345;
+ break;
+ default:
+ ACE_OS::fprintf (stderr, ACE_TEXT ("Warning: too many fields in saved id file.\n"));
+ ok = false;
+ break;
+ }
+ }
+ pb = nb;
+ }
+ }
+ return ok;
+}
+
+void
+Consumer_Main::reconnect (
+ CosNotifyChannelAdmin::EventChannelFactory_ptr dest_factory
+ ACE_ENV_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer begin ReconnectRegistry based reconnection\n")
+ ));
+ }
+ this->ecf_ = CosNotifyChannelAdmin::EventChannelFactory::_duplicate (dest_factory);
+ this->reconnecting_ = true;
+ init_event_channel (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+
+ init_consumer_admin (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+
+ switch (this->mode_)
+ {
+ case MODE_STRUCTURED:
+ {
+ init_structured_proxy_supplier (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+ break;
+ }
+
+ case MODE_SEQUENCE:
+ {
+ init_sequence_proxy_supplier (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+ break;
+ }
+
+ case MODE_ANY :
+ {
+ init_any_proxy_supplier (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+ break;
+ }
+ }
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer ReconnectRegistry based reconnection complete\n")
+ ));
+ }
+}
+
+
+int
+Consumer_Main::resolve_naming_service (ACE_ENV_SINGLE_ARG_DECL)
+{
+ // ignore redundant calls
+ if (CORBA::is_nil (this->naming_context_.in ()))
+ {
+ CORBA::Object_var naming_obj =
+ this->orb_->resolve_initial_references (NAMING_SERVICE_NAME
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+
+ this->naming_context_ =
+ CosNaming::NamingContext::_narrow (naming_obj.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ }
+
+ return !CORBA::is_nil (this->naming_context_.in ());
+}
+
+int
+Consumer_Main::find_notify_factory (ACE_ENV_SINGLE_ARG_DECL)
+{
+ int status = this->resolve_naming_service (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+ if (status)
+ {
+ CosNaming::Name name (1);
+ name.length (1);
+ name[0].id = CORBA::string_dup (NOTIFY_FACTORY_NAME);
+
+ CORBA::Object_var obj =
+ this->naming_context_->resolve (name
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+
+ this->ecf_ =
+ CosNotifyChannelAdmin::EventChannelFactory::_narrow (
+ obj.in ()
+ ACE_ENV_ARG_PARAMETER
+ );
+ ACE_CHECK_RETURN(0);
+ }
+ return ! CORBA::is_nil (this->ecf_.in ());
+}
+
+int
+Consumer_Main::resolve_notify_factory (ACE_ENV_SINGLE_ARG_DECL)
+{
+ CORBA::Object_var factory_obj =
+ this->orb_->resolve_initial_references (NOTIFY_FACTORY_NAME
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+
+ this->ecf_ =
+ CosNotifyChannelAdmin::EventChannelFactory::_narrow (
+ factory_obj.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ return ! CORBA::is_nil (this->ecf_.in ());
+}
+
+void
+Consumer_Main::init_event_channel (ACE_ENV_SINGLE_ARG_DECL)
+{
+ bool ok = false;
+ if (this->reconnecting_)
+ {
+ ACE_TRY_NEW_ENV
+ {
+ this->ec_ = this->ecf_->get_event_channel (
+ this->ec_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ ok = ! CORBA::is_nil (this->ec_.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer: Reconnect to event channel %d\n"),
+ ACE_static_cast (int, this->ec_id_)
+ ));
+ }
+ }
+ ACE_CATCHALL
+ {
+ }
+ ACE_ENDTRY;
+ }
+
+ // if we don't have a channel yet, and a channel id file was specified
+ // try to read from it
+ if (!ok && this->channel_file_.length () > 0)
+ {
+ FILE * chf = ACE_OS::fopen (this->channel_file_.c_str (), "r");
+ if (chf != 0)
+ {
+ char buffer[100];
+ ACE_OS::fgets (buffer, sizeof(buffer), chf);
+ ACE_OS::fclose (chf);
+ this->ec_id_ = ACE_OS::atoi (buffer);
+
+ ACE_DECLARE_NEW_ENV;
+ ACE_TRY_EX (unique_label_1)
+ {
+ this->ec_ = this->ecf_->get_event_channel (
+ this->ec_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK_EX (unique_label_1)
+ ok = ! CORBA::is_nil (this->ec_.in ());
+ if (ok)
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) supplier: Connect to Existing event channel %d\n"),
+ ACE_static_cast (int, this->ec_id_)
+ ));
+ }
+ // kill the channel filename so we don't overwrite the file
+ this->channel_file_ = "";
+ }
+ }
+ ACE_CATCHALL
+ {
+ }
+ ACE_ENDTRY;
+ }
+ }
+
+ if (!ok)
+ {
+ CosNotification::QoSProperties qosprops(7);
+ qosprops.length(7);
+ CORBA::ULong i = 0;
+#ifdef DISABLE_PROPERTIES_TODO
+ qosprops[i].name = CORBA::string_dup(CosNotification::EventReliability);
+ qosprops[i++].value <<= CosNotification::Persistent;
+ qosprops[i].name = CORBA::string_dup(CosNotification::ConnectionReliability);
+ qosprops[i++].value <<= CosNotification::Persistent; // Required, or we won't persist much
+ qosprops[i].name = CORBA::string_dup(CosNotification::Priority);
+ qosprops[i++].value <<= CosNotification::HighestPriority;
+ qosprops[i].name = CORBA::string_dup(CosNotification::Timeout);
+ qosprops[i++].value <<= (TimeBase::TimeT) 42 * 10000; // 42ms
+ qosprops[i].name = CORBA::string_dup(CosNotification::StopTimeSupported);
+ qosprops[i++].value <<= CORBA::Any::from_boolean(1);
+ qosprops[i].name = CORBA::string_dup(CosNotification::MaximumBatchSize);
+ qosprops[i++].value <<= (CORBA::Long)2;
+ qosprops[i].name = CORBA::string_dup(CosNotification::PacingInterval);
+ qosprops[i++].value <<= (TimeBase::TimeT) 50 * 10000; // 50ms
+#endif
+ qosprops.length (i);
+ CosNotification::AdminProperties adminprops(4);
+ adminprops.length(4);
+ i = 0;
+#ifdef DISABLE_PROPERTIES_TODO
+ adminprops[i].name = CORBA::string_dup(CosNotification::MaxQueueLength);
+ adminprops[i++].value <<= (CORBA::Long) 1234;
+ adminprops[i].name = CORBA::string_dup(CosNotification::MaxSuppliers);
+ adminprops[i++].value <<= (CORBA::Long) 1000;
+ adminprops[i].name = CORBA::string_dup(CosNotification::MaxConsumers);
+ adminprops[i++].value <<= (CORBA::Long) 1000;
+ adminprops[i].name = CORBA::string_dup(CosNotification::RejectNewEvents);
+ adminprops[i++].value <<= CORBA::Any::from_boolean(1);
+#endif
+ adminprops.length(i);
+
+ ec_ = this->ecf_->create_channel (
+ qosprops,
+ adminprops,
+ this->ec_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ ok = ! CORBA::is_nil (ec_.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer: Create event channel %d\n"),
+ ACE_static_cast (int, this->ec_id_)
+ ));
+ }
+ }
+
+ if (ok && this->channel_file_.length() > 0)
+ {
+ FILE * chf = ACE_OS::fopen (this->channel_file_.c_str (), "r");
+ if (chf != 0)
+ {
+ char buffer[100];
+ ACE_OS::fgets (buffer, sizeof(buffer), chf);
+ ACE_OS::fclose (chf);
+ this->ec_id_ = ACE_OS::atoi (buffer);
+ }
+ }
+}
+
+CosNotifyChannelAdmin::AdminID default_admin_id = ACE_static_cast (CosNotifyChannelAdmin::AdminID, -1);
+
+void
+Consumer_Main::init_consumer_admin (ACE_ENV_SINGLE_ARG_DECL)
+{
+ bool ok = false;
+ if (this->reconnecting_ && this->sa_id_ != default_admin_id)
+ {
+ ACE_TRY_EX(ONE)
+ {
+ this->sa_ = this->ec_->get_consumeradmin(
+ this->sa_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK_EX(ONE);
+ ok = ! CORBA::is_nil (this->sa_.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer: Reconnect to consumer admin %d\n"),
+ ACE_static_cast (int, this->sa_id_)
+ ));
+ }
+ }
+ ACE_CATCHALL
+ {
+ }
+ ACE_ENDTRY;
+ }
+
+ if (!ok)
+ {
+ ACE_TRY_EX(TWO)
+ {
+ this->sa_ = this->ec_->default_consumer_admin (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK_EX(TWO);
+ ok = ! CORBA::is_nil (this->sa_.in ());
+ this->sa_id_ = default_admin_id;
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer: Using default consumer admin\n")
+ ));
+ }
+ else if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer: No default consumer admin\n")
+ ));
+ }
+ }
+ ACE_CATCHALL
+ {
+ }
+ ACE_ENDTRY;
+ }
+
+ if (!ok)
+ {
+ this->sa_ = this->ec_->new_for_consumers(
+ CosNotifyChannelAdmin::OR_OP,
+ this->sa_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ ok = ! CORBA::is_nil (this->sa_.in ());
+
+#ifdef TEST_SET_QOS
+ // temporary: be sure we can set qos properties here
+ if (ok)
+ {
+ CosNotification::QoSProperties qosprops(2);
+ CORBA::ULong i = 0;
+ qosprops.length(2);
+
+ qosprops[i].name = CORBA::string_dup(CosNotification::EventReliability);
+ qosprops[i++].value <<= CosNotification::Persistent;
+ qosprops[i].name = CORBA::string_dup(CosNotification::ConnectionReliability);
+ qosprops[i++].value <<= CosNotification::Persistent; // Required, or we won't persist much
+ qosprops.length(i);
+ this->sa_->set_qos (qosprops ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+#endif
+
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer: Create new consumer admin %d\n"),
+ ACE_static_cast (int, this->sa_id_)
+ ));
+ }
+ }
+}
+
+void
+Consumer_Main::init_structured_proxy_supplier (ACE_ENV_SINGLE_ARG_DECL)
+{
+ bool ok = false;
+ CosNotifyChannelAdmin::ProxySupplier_var proxy;
+ if (this->reconnecting_)
+ {
+ ACE_TRY_NEW_ENV
+ {
+ proxy = this->sa_->get_proxy_supplier (
+ this->structured_proxy_id_
+ ACE_ENV_ARG_PARAMETER
+ );
+ ACE_TRY_CHECK;
+ ok = ! CORBA::is_nil (proxy.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer: Reconnect to proxy supplier %d\n"),
+ ACE_static_cast (int, this->structured_proxy_id_)
+ ));
+ }
+ }
+ ACE_CATCHALL
+ {
+ }
+ ACE_ENDTRY;
+ }
+
+ if (!ok)
+ {
+ proxy = this->sa_->obtain_notification_push_supplier(
+ CosNotifyChannelAdmin::STRUCTURED_EVENT,
+ this->structured_proxy_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ ok = ! CORBA::is_nil (proxy.in ());
+#ifdef TEST_SET_QOS
+ // temporary
+ if (ok)
+ {
+ set_proxy_qos (proxy.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+#endif // TEST_SET_QOS
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer: Create new proxy %d\n"),
+ ACE_static_cast (int, this->structured_proxy_id_)
+ ));
+ }
+ }
+ this->structured_proxy_push_supplier_ =
+ CosNotifyChannelAdmin::StructuredProxyPushSupplier::_narrow(proxy.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ if (CORBA::is_nil (this->structured_proxy_push_supplier_.in ()))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) init_structured_proxy_supplier received nil ProxySupplier\n")
+ ));
+ ACE_THROW (CORBA::OBJECT_NOT_EXIST ());
+ }
+
+ if (CORBA::is_nil (this->structured_push_consumer_ref_.in ()))
+ {
+ PortableServer::ObjectId_var push_consumer_id =
+ this->root_poa_->activate_object (
+ &(this->structured_push_consumer_) ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ CORBA::Object_var obj =
+ this->root_poa_->id_to_reference (push_consumer_id.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ this->structured_push_consumer_ref_ =
+ CosNotifyComm::StructuredPushConsumer::_narrow (obj.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+
+ if (CORBA::is_nil (this->structured_push_consumer_ref_.in ()))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Consumer: Error activating structured push consumer\n")
+ ));
+
+ ACE_THROW (CORBA::BAD_PARAM());
+ }
+
+ this->structured_proxy_push_supplier_->connect_structured_push_consumer (
+ this->structured_push_consumer_ref_.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ this->structured_push_consumer_.set_connected(true);
+}
+
+void
+Consumer_Main::init_sequence_proxy_supplier (ACE_ENV_SINGLE_ARG_DECL)
+{
+ bool ok = false;
+ CosNotifyChannelAdmin::ProxySupplier_var proxy;
+ if (this->reconnecting_)
+ {
+ ACE_TRY_NEW_ENV
+ {
+ proxy = this->sa_->get_proxy_supplier(
+ this->sequence_proxy_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ ok = ! CORBA::is_nil (proxy.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer: Reconnect to proxy %d\n"),
+ ACE_static_cast (int, this->sequence_proxy_id_)
+ ));
+ }
+ }
+ ACE_CATCHALL
+ {
+ }
+ ACE_ENDTRY;
+ }
+
+ if (!ok)
+ {
+ proxy = this->sa_->obtain_notification_push_supplier(
+ CosNotifyChannelAdmin::SEQUENCE_EVENT,
+ this->sequence_proxy_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ ok = ! CORBA::is_nil (proxy.in ());
+#ifdef TEST_SET_QOS
+ // temporary
+ if (ok)
+ {
+ set_proxy_qos (proxy.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+#endif // TEST_SET_QOS
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer: Create new proxy %d\n"),
+ ACE_static_cast (int, this->sequence_proxy_id_)
+ ));
+ }
+ }
+ this->sequence_proxy_push_supplier_ =
+ CosNotifyChannelAdmin::SequenceProxyPushSupplier::_narrow(proxy.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ if (CORBA::is_nil (this->sequence_proxy_push_supplier_.in ()))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Consumer: Received wrong type of push supplier proxy %d\n"),
+ ACE_static_cast (int, this->sequence_proxy_id_)
+ ));
+
+ ACE_THROW (CORBA::BAD_PARAM());
+ }
+
+ if (CORBA::is_nil (this->sequence_push_consumer_ref_.in ()))
+ {
+ PortableServer::ObjectId_var push_consumer_id =
+ this->root_poa_->activate_object (
+ &(this->sequence_push_consumer_) ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ CORBA::Object_var obj =
+ this->root_poa_->id_to_reference (push_consumer_id.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ this->sequence_push_consumer_ref_ =
+ CosNotifyComm::SequencePushConsumer::_narrow (obj.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+ if (CORBA::is_nil (this->sequence_push_consumer_ref_.in ()))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Consumer: Error activating sequence push consumer\n")
+ ));
+
+ ACE_THROW (CORBA::BAD_PARAM());
+ }
+
+ this->sequence_proxy_push_supplier_->connect_sequence_push_consumer (
+ this->sequence_push_consumer_ref_.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ this->sequence_push_consumer_.set_connected(true);
+
+}
+
+
+void
+Consumer_Main::set_proxy_qos (CosNotifyChannelAdmin::ProxySupplier_ptr proxy
+ ACE_ENV_ARG_DECL)
+{
+ // temporary: be sure we can set qos properties for proxyw
+ CosNotification::QoSProperties qosprops(2);
+ CORBA::ULong i = 0;
+ qosprops.length(2);
+
+ qosprops[i].name = CORBA::string_dup(CosNotification::EventReliability);
+ qosprops[i++].value <<= CosNotification::Persistent;
+ qosprops[i].name = CORBA::string_dup(CosNotification::ConnectionReliability);
+ qosprops[i++].value <<= CosNotification::Persistent; // Required, or we won't persist much
+ qosprops.length(i);
+ proxy->set_qos (qosprops ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+}
+
+void
+Consumer_Main::init_any_proxy_supplier (ACE_ENV_SINGLE_ARG_DECL)
+{
+ bool ok = false;
+ CosNotifyChannelAdmin::ProxySupplier_var proxy;
+ if (this->reconnecting_)
+ {
+ ACE_TRY_NEW_ENV
+ {
+ proxy = this->sa_->get_proxy_supplier(
+ this->any_proxy_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ ok = ! CORBA::is_nil (proxy.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer: Reconnect to proxy %d\n"),
+ ACE_static_cast (int, this->any_proxy_id_)
+ ));
+ }
+ }
+ ACE_CATCHALL
+ {
+ }
+ ACE_ENDTRY;
+ }
+
+ if (!ok)
+ {
+ proxy = this->sa_->obtain_notification_push_supplier(
+ CosNotifyChannelAdmin::ANY_EVENT,
+ this->any_proxy_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ ok = ! CORBA::is_nil (proxy.in ());
+
+#ifdef TEST_SET_QOS
+ // temporary
+ if (ok)
+ {
+ set_proxy_qos (proxy.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+#endif // TEST_SET_QOS
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer: Create new proxy\n"),
+ ACE_static_cast (int, this->any_proxy_id_)
+ ));
+ }
+ }
+ this->any_proxy_push_supplier_ =
+ CosNotifyChannelAdmin::ProxyPushSupplier::_narrow(proxy.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ if (CORBA::is_nil (this->any_proxy_push_supplier_.in ()))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Consumer: Received wrong type of push supplier proxy %d\n"),
+ ACE_static_cast (int, this->sequence_proxy_id_)
+ ));
+ ACE_THROW (CORBA::BAD_PARAM());
+ }
+ if (CORBA::is_nil (this->any_push_consumer_ref_.in ()))
+ {
+ PortableServer::ObjectId_var push_consumer_id =
+ this->root_poa_->activate_object (
+ &(this->any_push_consumer_) ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ CORBA::Object_var obj =
+ this->root_poa_->id_to_reference (push_consumer_id.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ this->any_push_consumer_ref_ =
+ CosNotifyComm::PushConsumer::_narrow (obj.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+
+ if (CORBA::is_nil (this->any_push_consumer_ref_.in ()))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Consumer:Error activating push consumer\n")
+ ));
+
+ ACE_THROW (CORBA::BAD_PARAM());
+ }
+ this->any_proxy_push_supplier_->connect_any_push_consumer (
+ this->any_push_consumer_ref_.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ this->any_push_consumer_.set_connected(true);
+}
+
+int Consumer_Main::fini (ACE_ENV_SINGLE_ARG_DECL)
+{
+
+ this->reconnection_callback_.fini (ACE_ENV_SINGLE_ARG_PARAMETER);
+ if (this->disconnect_on_exit_)
+ {
+ if (!CORBA::is_nil (this->structured_proxy_push_supplier_.in ()))
+ {
+ this->structured_proxy_push_supplier_->disconnect_structured_push_supplier (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-4);
+ }
+ if (!CORBA::is_nil (this->sequence_proxy_push_supplier_.in ()))
+ {
+ this->sequence_proxy_push_supplier_->disconnect_sequence_push_supplier (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-4);
+ }
+ if (!CORBA::is_nil (this->any_proxy_push_supplier_.in ()))
+ {
+ this->any_proxy_push_supplier_->disconnect_push_supplier (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-4);
+ }
+ if (!CORBA::is_nil (this->sa_.in ()) && this->sa_id_ != default_admin_id)
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) destroy admin %d\n"),
+ ACE_static_cast(int, this->sa_id_)
+ ));
+ }
+ this->sa_->destroy();
+ }
+ }
+ this->orb_->shutdown ();
+ return 0;
+}
+
+
+int Consumer_Main::run (ACE_ENV_SINGLE_ARG_DECL)
+{
+ int result = 0;
+
+ //////////////////////////////////
+ // Run the event loop for the ORB.
+ // Initial run to initialize the orb
+ ACE_Time_Value tv(1,0);
+ this->orb_->run (tv ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(-1);
+
+ while (this->structured_push_consumer_.received () < this->expect_
+ && this->sequence_push_consumer_.received () < this->expect_
+ && this->any_push_consumer_.received () < this->expect_
+ )
+ {
+ ACE_Time_Value work_tv(1,0);
+ // keep the orb alive -- listenting for reconnect
+ this->orb_->perform_work (work_tv ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(-1);
+ }
+
+ // see if consumers detected errors
+ if (this->structured_push_consumer_.has_problem ()
+ || this->sequence_push_consumer_.has_problem ()
+ || this->any_push_consumer_.has_problem ())
+ {
+ result = -3;
+ }
+ return result;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int result = -1;
+ Consumer_Main app;
+ ACE_TRY_NEW_ENV
+ {
+ result = app.init(argc, argv ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK
+
+ if (result == 0)
+ {
+ result = app.run (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+ if (result == 0)
+ {
+ app.fini (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+ }
+ ACE_CATCHANY
+ {
+ ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION,
+ "Consumer::main\t\n");
+ result = -1;
+ }
+ ACE_ENDTRY;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) Consumer exits: code %d\n"),
+ result
+ ));
+ return result;
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/Consumer.h b/TAO/orbsvcs/tests/Notify/Reconnecting/Consumer.h
new file mode 100644
index 00000000000..0f21447744e
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/Reconnecting/Consumer.h
@@ -0,0 +1,300 @@
+/* -*- C++ -*- */
+// $Id$
+// ==========================================================================
+//
+// = FILENAME
+// Consumer.h
+//
+// = DESCRIPTION
+// Test Consumer reconnect to existing channel/admin/proxy Notification Service
+//
+// = AUTHOR
+// Dale Wilson <wilson_d@ociweb.com>
+//
+// ==========================================================================
+
+#ifndef RECONNECTNG_CONSUMER_H
+#define RECONNECTNG_CONSUMER_H
+
+//#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+//#pragma warning(pop)
+//#endif /* _MSC_VER */
+
+
+#include "orbsvcs/CosNotifyChannelAdminC.h"
+#include "orbsvcs/CosNamingC.h"
+#include "orbsvcs/NotifyExtS.h"
+#include "ace/SString.h"
+
+class Consumer_Main;
+
+class StructuredPushConsumer_i : public virtual POA_CosNotifyComm::StructuredPushConsumer
+{
+public:
+ StructuredPushConsumer_i ();
+ virtual void offer_change (
+ const CosNotification::EventTypeSeq & added,
+ const CosNotification::EventTypeSeq & removed
+ ACE_ENV_ARG_DECL
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ CosNotifyComm::InvalidEventType));
+
+ virtual void push_structured_event (
+ const CosNotification::StructuredEvent & notification
+ ACE_ENV_ARG_DECL
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException,
+ CosEventComm::Disconnected));
+
+ virtual void disconnect_structured_push_consumer (
+ ACE_ENV_SINGLE_ARG_DECL
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException));
+
+ size_t received () const;
+ void set_expectations (size_t expecte, size_t fail, size_t serial_number, bool verbose);
+ bool has_problem () const;
+ void set_connected (bool flag);
+ bool is_connected () const;
+
+private:
+ void check_serial_number (CORBA::ULong seq);
+
+private:
+ bool verbose_;
+ size_t received_;
+ size_t expect_;
+ size_t fail_;
+ size_t may_discard_;
+ size_t serial_number_;
+ size_t exceptions_thrown_;
+ bool problem_;
+ bool connected_;
+};
+
+class SequencePushConsumer_i : public virtual POA_CosNotifyComm::SequencePushConsumer
+{
+public:
+ SequencePushConsumer_i ();
+ virtual void offer_change (
+ const CosNotification::EventTypeSeq & added,
+ const CosNotification::EventTypeSeq & removed
+ ACE_ENV_ARG_DECL
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ CosNotifyComm::InvalidEventType));
+
+ virtual void push_structured_events (
+ const CosNotification::EventBatch & notifications
+ ACE_ENV_ARG_DECL
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException,
+ CosEventComm::Disconnected));
+
+ virtual void disconnect_sequence_push_consumer (
+ ACE_ENV_SINGLE_ARG_DECL
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException));
+
+ size_t received () const;
+ void set_expectations (size_t expecte, size_t fail, size_t serial_number, bool verbose);
+ bool has_problem () const;
+ void set_connected (bool flag);
+ bool is_connected () const;
+
+private:
+ void check_serial_number (CORBA::ULong seq);
+
+private:
+ bool verbose_;
+ size_t received_;
+ size_t expect_;
+ size_t fail_;
+ size_t may_discard_;
+ size_t serial_number_;
+ size_t exceptions_thrown_;
+ bool problem_;
+ bool connected_;
+};
+
+class AnyPushConsumer_i : public virtual POA_CosNotifyComm::PushConsumer
+{
+public:
+ AnyPushConsumer_i ();
+
+ virtual void offer_change (
+ const CosNotification::EventTypeSeq & added,
+ const CosNotification::EventTypeSeq & removed
+ ACE_ENV_ARG_DECL
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ CosNotifyComm::InvalidEventType));
+
+ virtual void push (
+ const CORBA::Any & data
+ ACE_ENV_ARG_DECL
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException,
+ CosEventComm::Disconnected));
+
+ virtual void disconnect_push_consumer (
+ ACE_ENV_SINGLE_ARG_DECL
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException));
+
+ size_t received () const;
+ void set_expectations (size_t expecte, size_t fail, size_t serial_number, bool verbose);
+ bool has_problem () const;
+ void set_connected (bool flag);
+ bool is_connected () const;
+
+private:
+ void check_serial_number (CORBA::ULong seq);
+
+private:
+ bool verbose_;
+ size_t received_;
+ size_t expect_;
+ size_t fail_;
+ size_t may_discard_;
+ size_t serial_number_;
+ size_t exceptions_thrown_;
+ bool problem_;
+ bool connected_;
+};
+
+class ReconnectionCallback_i : public virtual POA_NotifyExt::ReconnectionCallback
+{
+public:
+ ReconnectionCallback_i (Consumer_Main & consumer_main);
+
+ virtual ~ReconnectionCallback_i ();
+
+ void init (
+ PortableServer::POA_ptr poa,
+ CosNotifyChannelAdmin::EventChannelFactory_ptr ecf_
+ ACE_ENV_ARG_DECL);
+
+ void fini (ACE_ENV_SINGLE_ARG_DECL);
+
+ size_t reconnect_count () const;
+
+ virtual void reconnect (
+ CORBA::Object_ptr reconnection
+ ACE_ENV_ARG_DECL
+ ) ACE_THROW_SPEC ((CORBA::SystemException));
+
+ virtual CORBA::Boolean is_alive (ACE_ENV_SINGLE_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException));
+
+private:
+ Consumer_Main & consumer_main_;
+ bool id_is_valid_;
+ NotifyExt::ReconnectionRegistry::ReconnectionID callback_id_;
+ CosNotifyChannelAdmin::EventChannelFactory_var ecf_;
+ size_t reconnect_count_;
+};
+
+class Consumer_Main
+{
+ public:
+ Consumer_Main ();
+ ~Consumer_Main ();
+
+ int parse_args (int argc, char *argv[]);
+ int parse_single_arg (int argc, char *argv[]);
+
+ int init (int argc, char *argv[] ACE_ENV_ARG_DECL);
+ int run (ACE_ENV_SINGLE_ARG_DECL);
+ int fini (ACE_ENV_SINGLE_ARG_DECL);
+ void usage (FILE * log) const;
+
+ void reconnect (
+ CosNotifyChannelAdmin::EventChannelFactory_ptr dest_factory
+ ACE_ENV_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException));
+
+ private:
+ /// Find naming service.
+ int resolve_naming_service (ACE_ENV_SINGLE_ARG_DECL);
+
+ /// Resolve the Notify factory from the Naming service.
+ int find_notify_factory (ACE_ENV_SINGLE_ARG_DECL);
+
+ /// Resolve the Notify factory using resolve_initial_reference ("NotifyEventChannelFactory")
+ int resolve_notify_factory (ACE_ENV_SINGLE_ARG_DECL);
+
+ void init_event_channel (ACE_ENV_SINGLE_ARG_DECL);
+ void init_consumer_admin (ACE_ENV_SINGLE_ARG_DECL);
+ void init_structured_proxy_supplier (ACE_ENV_SINGLE_ARG_DECL);
+ void init_sequence_proxy_supplier (ACE_ENV_SINGLE_ARG_DECL);
+ void init_any_proxy_supplier (ACE_ENV_SINGLE_ARG_DECL);
+
+ void set_proxy_qos (CosNotifyChannelAdmin::ProxySupplier_ptr proxy ACE_ENV_ARG_DECL);
+
+ void save_ids();
+ bool load_ids();
+
+ ////////////////////
+ // forbidden methods
+ private:
+ Consumer_Main (const Consumer_Main & rhs);
+ Consumer_Main & operator = (const Consumer_Main & rhs);
+
+ ////////////////
+ // Data members
+ private:
+
+ // set by command line parameters
+ bool verbose_; // -v make a glorious noise
+ enum Mode_T{
+ MODE_ANY,
+ MODE_STRUCTURED,
+ MODE_SEQUENCE} mode_; // -any, -structured, or -sequence
+ ACE_CString channel_file_; // -channel fileneame
+ size_t expect_; // -expect n
+ size_t fail_; // -fail n
+ bool use_naming_service_; // -nonamesvc
+ size_t serial_number_; // -serial_number
+ bool disconnect_on_exit_; // -disconnect
+ size_t structured_count_;
+ size_t sequence_count_;
+ size_t any_count_;
+
+ ACE_CString id_file_; // -ids
+ CORBA::ORB_var orb_;
+ PortableServer::POA_var root_poa_;
+ CosNaming::NamingContext_var naming_context_;
+ CosNotifyChannelAdmin::EventChannelFactory_var ecf_;
+
+ CosNotifyChannelAdmin::EventChannel_var ec_;
+ CosNotifyChannelAdmin::ChannelID ec_id_;
+
+ CosNotifyChannelAdmin::ConsumerAdmin_var sa_;
+ CosNotifyChannelAdmin::AdminID sa_id_;
+
+ CosNotifyChannelAdmin::StructuredProxyPushSupplier_var structured_proxy_push_supplier_;
+ CosNotifyChannelAdmin::ProxyID structured_proxy_id_;
+ StructuredPushConsumer_i structured_push_consumer_;
+ CosNotifyComm::StructuredPushConsumer_var structured_push_consumer_ref_;
+
+ CosNotifyChannelAdmin::SequenceProxyPushSupplier_var sequence_proxy_push_supplier_;
+ CosNotifyChannelAdmin::ProxyID sequence_proxy_id_;
+ SequencePushConsumer_i sequence_push_consumer_;
+ CosNotifyComm::SequencePushConsumer_var sequence_push_consumer_ref_;
+
+ CosNotifyChannelAdmin::ProxyPushSupplier_var any_proxy_push_supplier_;
+ CosNotifyChannelAdmin::ProxyID any_proxy_id_;
+ AnyPushConsumer_i any_push_consumer_;
+ CosNotifyComm::PushConsumer_var any_push_consumer_ref_;
+
+ ReconnectionCallback_i reconnection_callback_;
+
+ bool reconnecting_;
+};
+
+#endif /* RECONNECTNG_CONSUMER_H */
diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/README b/TAO/orbsvcs/tests/Notify/Reconnecting/README
new file mode 100644
index 00000000000..723c0a4f730
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/Reconnecting/README
@@ -0,0 +1,351 @@
+$Id$
+
+README for the Notification Service Reconnection Test
+-----------------------------------------------------
+
+Implementation notes
+--------------------
+
+Notification Service Supplier/Consumer reconnection test.
+
+This directory contains:
+
+ Supplier.cpp -- source for a configurable event supplier
+ Supplier.h
+ Consumer.cpp -- source for a configurable consumer for events produced
+ Consumer.h by a Supplier
+ run_ns.pl -- a script to start the Notification Service manually
+ run_supplier.pl -- a script to start Supplier manually
+ run_consumer.pl -- a script to start Consumer manually
+ run_test.pl -- a script to run several tests of the Reliable
+ Notification Service
+ ns_st.conf -- configures the Notification Service for single
+ thread operation with no persistence support.
+ ns_mt.conf -- configures the Notification Service for multi-
+ threaded operation with no persistence support.
+ ns_st_topo.conf -- configures the Notification Service for single
+ thread operation with support for topological,
+ but not event persistence.
+ ns_mt_topo.conf -- configures the Notification Service for multi-
+ threaded operation with support for topological,
+ but not event persistence.
+ ns_st_both.conf -- configures the Notification Service for single
+ thread operation with support for both topological,
+ and event persistence.
+ ns_mt_both.conf -- configures the Notification Service for multi-
+ threaded operation with support for both topological,
+ and event persistence.
+ event.conf -- configures the Notification Service for event
+ persistence without topology persistence. This is
+ an invalid configuration and should cause the
+ Notification Service to refuse to start.
+ Reconnecting.mpc -- a configuration/build file for MPC
+ README -- this file
+
+Supplier
+--------
+This program connects to the Notification Service and generates events based
+on command line parameters.
+
+ -nonamesvc Don't use the Naming Service to find
+ EventChannelFactory
+ -channel filename Where to find a channel number
+ -any or -str or -seq What type of event to send (pick one, default is -any)
+ -send n How many events to send
+ -pause n Pause after sending n events
+ Signal the pause by writing to file "Supplier.paused"
+ -serial_number n What serial number to start with
+ -v Verbose output
+
+Because the Supplier and Consumer share many command line options, the
+descriptions of these options will be combined below.
+
+Consumer
+--------
+This program connects to the Notification Service and consumes events from
+the Supplier.
+
+ -nonamesvc Don't use the Naming Service to find
+ EventChannelFactory
+ -channel filename Where to store a channel number so the Supplier can
+ find it
+ -any or -str or -seq What type of event supplier will send (pick one,
+ default: -any)
+ -expect n How many events are expected.
+ -fail n Simulate a recoverable failure every n events.
+ -serial_number n What serial number to expect first. If -1 is
+ used, then serial number checking is disabled.
+ This allows testing the consumer with multiple
+ Suppliers.
+ -disconnect Disconnect from notfication service cleanly
+ (no reconnect will be possible)
+ -v Verbose output.
+
+Command line option: -nonamesvc
+-------------------------------
+There are several techniques that Notification Service clients (Suppliers
+and Consumers) may use to find and connect to the Notification Service.
+One common technique is for the Notification Service to register an Event
+Channel Factory with the Naming Service using a well-known name (specified in
+the CORBA standard.)
+
+Although this technique is a good one for use in a system that already depends
+on the Naming Service, the test scripts in this directory do not depend on the
+Naming Service. When this option is specified, the Supplier and Consumer use
+"resolve_initial_references ()" to find the Notification Service.
+
+When this option is used, the ORB option -ORBInitRef must also be used to
+define an initial reference to the Notification Service.
+
+Command line option: -channel filename
+--------------------------------------
+The Notification Service has the ability to support several channels
+simultaneously. For these tests to work, the Supplier and Consumer must
+use the same channel. There are several techniques the Consumer(s) and
+Supplier(s) can use to select which channel to use. These programs use a
+shared file to communicate the channel number from the Consumer that creates
+the channel to the Supplier that uses it.
+
+When the Consumer starts up but is not reconnecting to an existing service,
+it creates a new channel and writes the channel ID to the file specified by
+this command (if no -channel option is given, the channel ID is not written.)
+
+When the Supplier starts up, but is not reconnecting to an existing service,
+it attempts to read the channel ID from the file specified by this option.
+If it is successful it uses that channel ID to send events.
+
+Command line options: -any or -str or -seq
+------------------------------------------
+The Notification Service supports three types of Events. Any events are
+like those used by the Event Service (an ancestor to the Notification
+Service). Structured events and Sequence events are events supported only
+by the Notification Service. See the TAO Developer's Guide or the CORBA
+specification for more details.
+
+Only one of these three options should be specified. If none of these
+is specified, the default is "-any".
+
+Command line option: -send n
+----------------------------
+This Supplier-only option tells the Supplier how many events to send.
+After it has sent that many events, the Supplier will shut down.
+
+Command line option: -expect n
+------------------------------
+This Consumer-only option tells the Consumer how many events to expect.
+After it has received that many events, the Consumer will shut down.
+
+Command line option: -fail n
+------------------------------
+This Consumer-only option tells the Consumer to throw an exception
+(CORBA::UNKNOWN) every n events. This simulates a recoverable error in
+the consumer. After throwing the exception, the consumer continues
+to listen for incoming events. It expects the event it was processing
+to be retransmitted.
+
+Because of the retransmission, the use of the -fail option may be
+counterintuitive. If the consumer options are "-expect 10 -fail 4" then
+it will receive events 0, 1, 2, and fail on event 3. It will then
+receive 3, 4, 5, and fail on event 6. Then it will receive 6, 7, 8,
+and fail on event 9. Finally it will receive the retransmission of event
+9 and exit.
+
+Command line option: -pause n
+-----------------------------
+This Supplier-only option is used during testing. The Supplier will send
+the specified number of events then wait for the Notification Service to
+stop and restart before sending the remaining events.
+
+To signal test scripts that a pause has happened, the Supplier will create
+a file named "Supplier.pause" This file can be used to synchronize a
+script with a running Supplier. It has no other purpose.
+
+Obviously the -pause option should specify a smaller number than the -send
+option. If this option is not used, no pause will occur.
+
+Command line option: -serial_number n
+-------------------------------------
+Each event sent by the the Supplier has a sequential serial number. As the
+Consumer receives events, it checks to see that the events arrived in serial
+number order. Missing or duplicated events will be detected by the Consumer.
+
+This option tells the Supplier what serial number to use for the first event
+it sends, and the Consumer what serial number to expect in the first event
+it receives.
+
+For the Consumer only, a value of -1 disables checking of incoming serial
+numbers. This should be used when the Consumer is receiving events from
+multiple suppliers.
+
+Command line option: -v
+-----------------------
+This option enables verbose messages. The Supplier and Consumer are
+relatively silent during normal operation -- displaying messages only when
+something goes wrong. If this verbose option is specified, more detailed
+progress messages will be displayed.
+
+Reconnection
+------------
+Reconnection to the Notification Service is based on ID numbers assigned to
+the objects within the Notification Service (objects like Channels, Admins,
+and Proxies). After initially starting up, the supplier writes the IDs it
+needs to preserve to a file named Supplier.ids. The Consumer writes its
+IDs to Consumer.ids.
+
+When a client (Supplier or Consumer) starts up, it looks for its corresponding
+".ids" file. If the file is found, the client attempts to reconnect to an
+existing Notification Service using these IDs. If the file is not found, or
+the reconnection fails, the client falls back on its normal startup procedure.
+
+In addition, a running client can receive a request for reconnection from
+the Notification Service. When it does so, it uses the saved ID numbers to
+complete the reconnection process.
+
+Programming Style
+-----------------
+The Supplier and Consumer source files were designed to be complete,
+stand-alone applications. Other than their basic dependency on ACE, TAO,
+and CORBA, they avoid using outside facilities. For example, there is a
+Notification Tests library used by many Notification Service tests that
+encapsulates connections to the Notification Service and typical CORBA
+application issues. Because these programs were intended to illustrate
+everything necessary for a client application to work with a reliable
+Notification Service, this library is not used.
+
+Obviously a real-world application should take advantage of such helper
+classes to allow the developer to concentrate on the domain problem for
+which the application is written.
+
+Also these programs use ACE-style platform independence techniques.
+Applications that do not need to support the wide variety of platforms
+supported by ACE and TAO can relax some of these coding techniques.
+
+run_test.pl
+-----------
+The run_test.pl script runs tests of different cases in which
+reliable topology is needed. The following command line options can
+be given to the test script:
+
+run_test.pl: command line options -any, -str, or -seq
+-----------------------------------------------------
+Specify one of these options to determine what type of event will be used
+during the test. The default if none of these options is present is "-any".
+
+run_test.pl: command line option -v
+--------------------------------------------
+This option controls the verbosity of the test script and the Supplier and
+Consumer applications. When it is present, a detailed step-by-step
+report is produced by the test.
+
+run_test.pl: Test #1: Supplier reconnection.
+--------------------------------------------
+All persistent information is discarded before the test starts. The test
+script starts the Notification Service, a Consumer and a Supplier.
+
+The Consumer is configured to receive 20 events. The Supplier is configured
+to send ten events.
+
+After sending ten events, the Supplier exits -- simulating a Supplier failure.
+The test script starts a new copy of the Supplier. The new Supplier is
+configured to send ten events starting with event number 10.
+It uses information saved by the previous supplier to reconnect to the same
+channel, admin, and proxy in the Notification Services.
+The Suppler sends the remaining ten events then exists. The Consumer having
+received the 20 events it expects, exits as well and the test is complete.
+
+This demonstrates that a Supplier can stop then restart and its events will e
+delivered to the correct Consumer.
+
+run_test.pl: Test #2: Consumer reconnection.
+--------------------------------------------
+The Notification Service from the previous test is still running and the
+saved reconnection information for both the Supplier and Consumer is still
+available.
+
+The test script starts a Consumer configured to receive 20 events and a
+Supplier configured to send twenty events. Both clients use the reconnection
+information from the previous test to reconnect to the Notification Service.
+
+Twenty events are sent successfully, then both clients exit and the test
+is complete.
+
+This demonstrates that a Consumer can stop then restart and reconnect. It
+will continue to receive the events on the channel to which it was originally
+connected.
+
+run_test.pl: Test #3: Saving and Restoring Topology
+---------------------------------------------------
+The test script stops the Notification Server from the previous two tests and
+starts a new Notification Server. It reloads the topology from the XML topology
+persistence files saved during the first two tests.
+
+The test script starts a Consumer and a Supplier. They are configured to
+receive and send respectively twenty events. The clients use the reconnection
+information from the previous tests to connect to the event channel, admins,
+and proxies that were reloaded from persistent topology information.
+The Supplier sends and the Consumer receives 20 events. Both clients exit.
+
+This demonstrates that the Notification Server can save its topology, then
+reload it, and the resulting topology behaves correctly when clients reconnect.
+
+run_test.pl: Test #4: The Reconnection Registry
+-----------------------------------------------
+This test starts with the Notification Service from the previous test.
+
+The script starts a new Consumer that expects to receive 20 events. The
+Consumer reconnects to the Notification Server.
+The script starts a Supplier. It is configured to send 10 events then
+pause waiting for a Notification Service initiated reconnection before
+sending the remaining 10 events.
+
+Both clients register with the Reconnection Registry to receive reconnection
+callbacks.
+
+The test script waits for the Supplier to pause. It then kills the
+Notification Service and starts a new copy. The new Notification Service
+is not configured to listen at the same endpoint as the previous one did,
+so the clients have no way to find the new copy directly. They must rely
+on the callback received from the Reconnection Registry.
+
+The new Notification Service reloads its topology, including the Reconnection
+Registry entries from the XML file. It sends reconnection callbacks to the
+registered clients.
+
+Using their saved reconnection information, the clients complete the
+reconnection to the new Notification Service.
+
+The Supplier sends the remaining 10 events then terminates. The Consumer,
+having received its expected 10 events also terminates.
+
+This demonstrates the reconnection registry and reconnection to live clients.
+
+run_test.pl: Test #5: Consumer Recoverable Exception
+----------------------------------------------------
+Using the Notification Service still running from the previous test,
+but discarding reconnection information, a new Consumer is started.
+It is configured to expect 10 events, but to throw an exception after
+receiving the sixth event. After throwing the exception it expects to see
+the sixth event retransmitted, then to receive the remaining four events.
+A Supplier is started that sends 10 events, and then exits.
+When the Consumer has received the events it expects, including the
+retransmission of the sixth event, it shuts down.
+
+This demonstrates the Notification Service can recover from transient
+communication or Consumer failures.
+
+Known Problems as of Feb 2004.
+------------------------------
+Sequence events are not working. It is unclear whether this is a problem in
+the test or in the Notification Service itself.
+
+Known Problems as of Mar 2004.
+------------------------------
+The problem with sequence events reported previously turned out to be problems
+in both the test and in the Notification Service itself. These problems
+have been resolved. It is now possible to mix and match consumers and
+suppliers.
+
+There are no new known problems.
+
+[----------------------------------------------------------------------------]
+
diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/Reconnecting.mpc b/TAO/orbsvcs/tests/Notify/Reconnecting/Reconnecting.mpc
new file mode 100644
index 00000000000..75de6986a9b
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/Reconnecting/Reconnecting.mpc
@@ -0,0 +1,12 @@
+project(*Supplier): notifytest {
+ Source_Files {
+ Supplier.cpp
+ }
+}
+
+project(*Consumer): notifytest {
+ Source_Files {
+ Consumer.cpp
+ }
+}
+
diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/Supplier.cpp b/TAO/orbsvcs/tests/Notify/Reconnecting/Supplier.cpp
new file mode 100644
index 00000000000..748ee176898
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/Reconnecting/Supplier.cpp
@@ -0,0 +1,1368 @@
+//$Id$
+
+#include "Supplier.h"
+#include "orbsvcs/CosNotifyChannelAdminC.h"
+#include "tao/debug.h"
+#include "tao/PortableServer/PortableServerC.h"
+#include <tao/TimeBaseC.h>
+#include <ace/OS_NS_stdio.h>
+#include <ace/OS_NS_strings.h>
+
+ACE_RCSID (Notify_Tests, Supplier_Main, "$Id$")
+
+static const char NOTIFY_FACTORY_NAME[] = "NotifyEventChannelFactory";
+static const char NAMING_SERVICE_NAME[] = "NameService";
+
+///////////////////////////
+// StructuredPushSupplier_i
+
+void
+StructuredPushSupplier_i::subscription_change (
+ const CosNotification::EventTypeSeq & added,
+ const CosNotification::EventTypeSeq & removed
+ ACE_ENV_ARG_DECL_NOT_USED
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ CosNotifyComm::InvalidEventType))
+{
+ ACE_UNUSED_ARG (added);
+ ACE_UNUSED_ARG (removed);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) Supplier StructuredPushSupplier received subscription change\n")
+ ));
+}
+
+
+void
+StructuredPushSupplier_i::disconnect_structured_push_supplier (
+ ACE_ENV_SINGLE_ARG_DECL_NOT_USED
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) Supplier StructuredPushSupplier received disconnect\n")
+ ));
+}
+
+///////////////////////////
+// SequencePushSupplier_i
+
+void
+SequencePushSupplier_i::subscription_change (
+ const CosNotification::EventTypeSeq & added,
+ const CosNotification::EventTypeSeq & removed
+ ACE_ENV_ARG_DECL_NOT_USED
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ CosNotifyComm::InvalidEventType))
+{
+ ACE_UNUSED_ARG (added);
+ ACE_UNUSED_ARG (removed);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) Supplier SequencePushSupplier received subscription change\n")
+ ));
+}
+
+
+void
+SequencePushSupplier_i::disconnect_sequence_push_supplier (
+ ACE_ENV_SINGLE_ARG_DECL_NOT_USED
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) Supplier SequencePushSupplier received disconnect\n")
+ ));
+}
+
+///////////////////////////
+// AnyPushSupplier_i
+
+void
+AnyPushSupplier_i::subscription_change (
+ const CosNotification::EventTypeSeq & added,
+ const CosNotification::EventTypeSeq & removed
+ ACE_ENV_ARG_DECL_NOT_USED
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ CosNotifyComm::InvalidEventType))
+{
+ ACE_UNUSED_ARG (added);
+ ACE_UNUSED_ARG (removed);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) Supplier AnyPushSupplier received subscription change\n")
+ ));
+}
+
+
+void
+AnyPushSupplier_i::disconnect_push_supplier (
+ ACE_ENV_SINGLE_ARG_DECL_NOT_USED
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) Suppleir AnyPushSupplier received disconnect\n")
+ ));
+}
+
+/////////////////////////
+// ReconnectionCallback_i
+
+ReconnectionCallback_i::ReconnectionCallback_i (Supplier_Main & supplier_main)
+ : supplier_main_ (supplier_main)
+ , id_is_valid_ (false)
+ , reconnect_count_ (0)
+{
+}
+
+size_t
+ReconnectionCallback_i::reconnect_count () const
+{
+ return this->reconnect_count_;
+}
+
+void
+ReconnectionCallback_i::reconnect (
+ CORBA::Object_ptr reconnection
+ ACE_ENV_ARG_DECL
+ ) ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Supplier received reconnection request\n")
+ ));
+ this->ecf_ = CosNotifyChannelAdmin::EventChannelFactory::_narrow (reconnection ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ if (!CORBA::is_nil (this->ecf_.in ()))
+ {
+ this->supplier_main_.reconnect (this->ecf_.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ this->reconnect_count_ += 1;
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Supplier reconnection request failed: wrong object type\n")
+ ));
+ }
+}
+
+CORBA::Boolean
+ReconnectionCallback_i::is_alive (ACE_ENV_SINGLE_ARG_DECL_NOT_USED)
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ return CORBA::Boolean (1);
+}
+
+ReconnectionCallback_i::~ReconnectionCallback_i ()
+{
+ // normally you would disconnect from registry here, but
+ // to simulate a failure, we exit without cleaning up
+ // if the fini method is not called.
+}
+
+
+void
+ReconnectionCallback_i::fini (ACE_ENV_SINGLE_ARG_DECL)
+{
+ if (this->id_is_valid_)
+ {
+ NotifyExt::ReconnectionRegistry_var registry =
+ NotifyExt::ReconnectionRegistry::_narrow (this->ecf_.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ registry->unregister_callback (this->callback_id_ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ this->id_is_valid_ = false;
+ }
+}
+
+void
+ReconnectionCallback_i::init (
+ PortableServer::POA_ptr poa,
+ CosNotifyChannelAdmin::EventChannelFactory_ptr ecf
+ ACE_ENV_ARG_DECL)
+{
+ this->ecf_ = CosNotifyChannelAdmin::EventChannelFactory::_duplicate (ecf);
+ PortableServer::ObjectId_var reconnection_callback_id =
+ poa->activate_object (this ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ CORBA::Object_var obj =
+ poa->id_to_reference (reconnection_callback_id.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ NotifyExt::ReconnectionCallback_var callback =
+ NotifyExt::ReconnectionCallback::_narrow (obj.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ NotifyExt::ReconnectionRegistry_var registry =
+ NotifyExt::ReconnectionRegistry::_narrow (ecf ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ this->callback_id_ = registry->register_callback (callback.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ this->id_is_valid_ = true;
+}
+
+
+
+/////////////////
+// Supplier_Main
+
+Supplier_Main::Supplier_Main ()
+ : verbose_ (false)
+ , mode_ (MODE_ANY)
+ , send_ (10)
+ , use_naming_service_ (true)
+ , serial_number_ (0)
+ , disconnect_on_exit_ (false)
+ , id_file_ (ACE_TEXT ("supplier.ids"))
+ , pause_ (0)
+ , reconnection_callback_ (*this)
+ , reconnecting_ (false)
+{
+}
+
+Supplier_Main::~Supplier_Main ()
+{
+}
+
+int
+Supplier_Main::parse_args (int argc, char *argv[])
+{
+ int result = 0;
+ int narg = 1;
+ bool corba_arg = false;
+ while (narg < argc && result == 0)
+ {
+ int consumed = parse_single_arg (argc - narg, &argv[narg]);
+ if ( consumed > 0)
+ {
+ narg += consumed;
+ corba_arg = false;
+ }
+ else if (ACE_OS::strncmp (argv[narg], "-ORB", 4) == 0)
+ {
+ corba_arg = true;
+ }
+ else if (corba_arg)
+ {
+ // previous argument was a ORB arg.
+ // current argument is unrecognized
+ // assume the ORB eats this arg
+ narg += 1;
+ corba_arg = false;
+ }
+ else
+ {
+ ACE_OS::fprintf(stderr, "Unrecognized argument: %s\n", argv[narg]);
+ usage (stderr);
+ result = -1;
+ }
+ }
+ return result;
+}
+
+int
+Supplier_Main::parse_single_arg (int argc, char *argv[])
+{
+ int consumed = 0;
+ if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-v")) == 0)
+ {
+ this->verbose_ = true;
+ consumed = 1;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-any")) == 0)
+ {
+ this->mode_ = MODE_ANY;
+ consumed = 1;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-structured")) == 0)
+ {
+ this->mode_ = MODE_STRUCTURED;
+ consumed = 1;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-sequence")) == 0)
+ {
+ this->mode_ = MODE_SEQUENCE;
+ consumed = 1;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-channel")) == 0)
+ {
+ this->channel_file_= argv[1];
+ consumed = 2;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-send")) == 0 && argc > 1)
+ {
+ this->send_ = ACE_OS::atoi (argv[1]);
+ consumed = 2;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-pause")) == 0 && argc > 1)
+ {
+ this->pause_ = ACE_OS::atoi (argv[1]);
+ consumed = 2;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-serial_number")) == 0)
+ {
+ this->serial_number_= ACE_OS::atoi (argv[1]);
+ consumed = 2;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-nonamesvc")) == 0)
+ {
+ this->use_naming_service_ = false;
+ consumed = 1;
+ }
+ else if (ACE_OS::strcasecmp (argv[0], "-disconnect") == 0)
+ {
+ this->disconnect_on_exit_ = true;
+ consumed = 1;
+ }
+
+ return consumed;
+}
+
+void Supplier_Main::usage(FILE * log)const
+{
+ ACE_OS::fputs (
+ ACE_TEXT ("usage\n")
+ ACE_TEXT (" -channel filename Where to find a channel number.\n")
+ ACE_TEXT (" -any or -structured or -sequence\n")
+ ACE_TEXT (" What type of event to send (pick one, default is -any)\n")
+ ACE_TEXT (" -send n How many events of each type to send.\n")
+ ACE_TEXT (" -pause n Pause after sending n events. Write to file \"Supplier.paused\"\n")
+ ACE_TEXT (" -serial_number n What serial number to start with.\n")
+ ACE_TEXT (" -v Verbose output.\n")
+ ACE_TEXT (" -disconnect Disconnect from channel on exit (prevents reconnect.) \n")
+ ACE_TEXT (" -nonamesvc Don't use the name service to find EventChannelFactory\n")
+ , log);
+}
+
+int Supplier_Main::init (int argc, char *argv[] ACE_ENV_ARG_DECL)
+{
+ this->orb_ = CORBA::ORB_init(argc, argv, "" ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+
+ if (0 != this->parse_args(argc, argv))
+ {
+ return -1;
+ }
+
+ CORBA::Object_ptr poa_object =
+ this->orb_->resolve_initial_references("RootPOA"
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+
+ if (CORBA::is_nil (poa_object))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT (" (%P|%t) Unable to initialize the POA.\n")));
+ return -1;
+ }
+
+ this->root_poa_ =
+ PortableServer::POA::_narrow (poa_object ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+
+ PortableServer::POAManager_var poa_manager =
+ root_poa_->the_POAManager (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+
+ poa_manager->activate (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+
+ if (this->use_naming_service_ )
+ {
+ this->find_notify_factory (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+ }
+ else
+ {
+ int ok = resolve_notify_factory (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+ if (!ok)
+ {
+ return -1;
+ }
+ }
+
+ this->reconnecting_ = load_ids ();
+
+ init_event_channel (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+
+ init_supplier_admin (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+
+ switch (this->mode_)
+ {
+ case MODE_STRUCTURED:
+ {
+ init_structured_proxy_consumer (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+ break;
+ }
+ case MODE_SEQUENCE:
+ {
+ init_sequence_proxy_consumer (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+ break;
+ }
+ case MODE_ANY:
+ {
+
+ init_any_proxy_consumer (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+ break;
+ }
+ default:
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Supplier: Unknown event push mode.\n")
+ ));
+ break;
+ }
+ }
+ this->reconnection_callback_.init (
+ this->root_poa_.in (),
+ this->ecf_.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+
+ save_ids ();
+ return 0;
+}
+void
+Supplier_Main::save_ids()
+{
+ FILE *idf =
+ ACE_OS::fopen (this->id_file_.c_str (), "w");
+
+ if (idf != 0)
+ {
+ int endflag = 12345;
+ int imode = ACE_static_cast (int, this->mode_);
+ ACE_OS::fprintf (idf,
+ "%d,%d,%d,%d,%d,%d,%d,\n",
+ imode,
+ ec_id_,
+ sa_id_,
+ structured_proxy_id_,
+ sequence_proxy_id_,
+ any_proxy_id_,
+ endflag);
+ ACE_OS::fclose (idf);
+ }
+}
+
+bool
+Supplier_Main::load_ids()
+{
+ bool ok = false;
+ FILE *idf =
+ ACE_OS::fopen (this->id_file_.c_str (), "w");
+
+ if (idf != 0)
+ {
+ int field = 0;
+
+ char buffer[100];
+ ACE_OS::fgets (buffer, sizeof(buffer), idf);
+ ACE_OS::fclose (idf);
+ char * pb = buffer;
+ while (*pb != 0)
+ {
+ char * eb = ACE_OS::strchr (pb, ',');
+ char * nb = eb + 1;
+ if (eb == 0)
+ {
+ eb = pb + ACE_OS::strlen (pb);
+ nb = eb;
+ }
+ else
+ {
+ *eb = 0;
+ }
+ if (pb < eb)
+ {
+ int value = ACE_OS::atoi(pb);
+ switch (field)
+ {
+ case 1:
+ this->mode_ = static_cast<Mode_T> (value);
+ break;
+ case 2:
+ this->ec_id_ = value;
+ break;
+ case 3:
+ this->sa_id_ = value;
+ break;
+ case 4:
+ this->structured_proxy_id_ = value;
+ break;
+ case 5:
+ this->sequence_proxy_id_ = value;
+ break;
+ case 6:
+ this->any_proxy_id_ = value;
+ break;
+ case 7:
+ ok = value == 12345;
+ break;
+ default:
+ ACE_OS::fprintf (stderr, ACE_TEXT ("Warning: too many fields in saved id file.\n"));
+ ok = false;
+ break;
+ }
+ }
+ pb = nb;
+ }
+ }
+ return ok;
+}
+
+void
+Supplier_Main::reconnect (
+ CosNotifyChannelAdmin::EventChannelFactory_ptr dest_factory
+ ACE_ENV_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ this->ecf_ = CosNotifyChannelAdmin::EventChannelFactory::_duplicate (dest_factory);
+ this->reconnecting_ = true;
+ init_event_channel (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+
+ init_supplier_admin (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+
+ switch (this->mode_)
+ {
+ case MODE_STRUCTURED:
+ {
+ init_structured_proxy_consumer (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+ break;
+ }
+ case MODE_SEQUENCE:
+ {
+ init_sequence_proxy_consumer (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+ break;
+ }
+ case MODE_ANY:
+ {
+ init_any_proxy_consumer (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK;
+ break;
+ }
+ }
+}
+
+
+int
+Supplier_Main::resolve_naming_service (ACE_ENV_SINGLE_ARG_DECL)
+{
+ // ignore redundant calls
+ if (CORBA::is_nil (this->naming_context_.in ()))
+ {
+ CORBA::Object_var naming_obj =
+ this->orb_->resolve_initial_references (NAMING_SERVICE_NAME
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+
+ this->naming_context_ =
+ CosNaming::NamingContext::_narrow (naming_obj.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ }
+
+ return !CORBA::is_nil (this->naming_context_.in ());
+}
+
+int
+Supplier_Main::find_notify_factory (ACE_ENV_SINGLE_ARG_DECL)
+{
+ int status = this->resolve_naming_service (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+ if (status)
+ {
+ CosNaming::Name name (1);
+ name.length (1);
+ name[0].id = CORBA::string_dup (NOTIFY_FACTORY_NAME);
+
+ CORBA::Object_var obj =
+ this->naming_context_->resolve (name
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+
+ this->ecf_ =
+ CosNotifyChannelAdmin::EventChannelFactory::_narrow (
+ obj.in ()
+ ACE_ENV_ARG_PARAMETER
+ );
+ ACE_CHECK_RETURN(0);
+ }
+ return ! CORBA::is_nil (this->ecf_.in ());
+}
+
+int
+Supplier_Main::resolve_notify_factory (ACE_ENV_SINGLE_ARG_DECL)
+{
+ CORBA::Object_var factory_obj =
+ this->orb_->resolve_initial_references (NOTIFY_FACTORY_NAME
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+
+ this->ecf_ =
+ CosNotifyChannelAdmin::EventChannelFactory::_narrow (
+ factory_obj.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN(0);
+ return ! CORBA::is_nil (this->ecf_.in ());
+}
+
+void
+Supplier_Main::init_event_channel (ACE_ENV_SINGLE_ARG_DECL)
+{
+ bool ok = false;
+ if (this->reconnecting_)
+ {
+ ACE_TRY_NEW_ENV
+ {
+ this->ec_ = this->ecf_->get_event_channel (
+ this->ec_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ ok = ! CORBA::is_nil (this->ec_.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Supplier: Reconnect to event channel %d\n"),
+ ACE_static_cast (int, this->ec_id_)
+ ));
+ }
+ }
+ ACE_CATCHALL
+ {
+ }
+ ACE_ENDTRY;
+ }
+
+ if (!ok && this->channel_file_.length () > 0)
+ {
+ FILE * chf = ACE_OS::fopen (this->channel_file_.c_str (), "r");
+ if (chf != 0)
+ {
+ char buffer[100];
+ ACE_OS::fgets (buffer, sizeof(buffer), chf);
+ ACE_OS::fclose (chf);
+ this->ec_id_ = ACE_OS::atoi (buffer);
+
+ ACE_DECLARE_NEW_ENV;
+ ACE_TRY_EX (unique_label_1)
+ {
+ this->ec_ = this->ecf_->get_event_channel (
+ this->ec_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK_EX (unique_label_1)
+ ok = ! CORBA::is_nil (this->ec_.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) supplier: Connect to Consumer's event channel %d\n"),
+ ACE_static_cast (int, this->ec_id_)
+ ));
+ }
+ }
+ ACE_CATCHALL
+ {
+ }
+ ACE_ENDTRY;
+ }
+ }
+
+ if (!ok)
+ {
+ CosNotification::QoSProperties qosprops(7);
+ qosprops.length(7);
+
+ CORBA::ULong i = 0;
+#ifdef DISABLE_PROPERITIES_TODO
+ qosprops[i].name = CORBA::string_dup(CosNotification::EventReliability);
+ qosprops[i++].value <<= CosNotification::Persistent;
+ qosprops[i].name = CORBA::string_dup(CosNotification::ConnectionReliability);
+ qosprops[i++].value <<= CosNotification::Persistent; // Required, or we won't persist much
+ qosprops[i].name = CORBA::string_dup(CosNotification::Priority);
+ qosprops[i++].value <<= CosNotification::HighestPriority;
+ qosprops[i].name = CORBA::string_dup(CosNotification::Timeout);
+ qosprops[i++].value <<= (TimeBase::TimeT) 42 * 1000000; // 4.2s
+ qosprops[i].name = CORBA::string_dup(CosNotification::StopTimeSupported);
+ qosprops[i++].value <<= CORBA::Any::from_boolean(1);
+ qosprops[i].name = CORBA::string_dup(CosNotification::MaximumBatchSize);
+ qosprops[i++].value <<= (CORBA::Long) 2;
+ qosprops[i].name = CORBA::string_dup(CosNotification::PacingInterval);
+ qosprops[i++].value <<= (TimeBase::TimeT) 50 * 10000; // 50ms
+#endif
+ qosprops.length(i);
+
+ CosNotification::AdminProperties adminprops(4);
+ adminprops.length(4);
+ i = 0;
+#ifdef DISABLE_PROPERTIES_TODO
+ adminprops[i].name = CORBA::string_dup(CosNotification::MaxQueueLength);
+ adminprops[i++].value <<= (CORBA::Long) 1234;
+ adminprops[i].name = CORBA::string_dup(CosNotification::MaxConsumers);
+ adminprops[i++].value <<= (CORBA::Long) 1000;
+ adminprops[i].name = CORBA::string_dup(CosNotification::MaxSuppliers);
+ adminprops[i++].value <<= (CORBA::Long) 1000;
+ adminprops[i].name = CORBA::string_dup(CosNotification::RejectNewEvents);
+ adminprops[i++].value <<= CORBA::Any::from_boolean(1);
+#endif
+ adminprops.length(i);
+
+ ec_ = this->ecf_->create_channel (
+ qosprops,
+ adminprops,
+ this->ec_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ ok = ! CORBA::is_nil (ec_.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Supplier: Create event channel %d\n"),
+ ACE_static_cast (int, this->ec_id_)
+ ));
+ }
+ }
+}
+
+CosNotifyChannelAdmin::AdminID default_admin_id = ACE_static_cast (CosNotifyChannelAdmin::AdminID, -1);
+
+void
+Supplier_Main::init_supplier_admin (ACE_ENV_SINGLE_ARG_DECL)
+{
+ bool ok = false;
+ if (this->reconnecting_ && this->sa_id_ != default_admin_id)
+ {
+ ACE_TRY_EX(ONE)
+ {
+ this->sa_ = this->ec_->get_supplieradmin(
+ this->sa_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK_EX(ONE);
+ ok = ! CORBA::is_nil (this->sa_.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Supplier: Reconnect to supplier admin %d\n"),
+ ACE_static_cast (int, this->sa_id_)
+ ));
+ }
+ }
+ ACE_CATCHALL
+ {
+ }
+ ACE_ENDTRY;
+ }
+
+ if (!ok)
+ {
+ ACE_TRY_EX(TWO)
+ {
+ this->sa_ = this->ec_->default_supplier_admin (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK_EX(TWO);
+ ok = ! CORBA::is_nil (this->sa_.in ());
+ this->sa_id_ = default_admin_id;
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Supplier: Using default supplier admin\n")
+ ));
+ }
+ else if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Supplier: No default supplier admin\n")
+ ));
+ }
+ }
+ ACE_CATCHALL
+ {
+ }
+ ACE_ENDTRY;
+ }
+
+ if (!ok)
+ {
+ this->sa_ = this->ec_->new_for_suppliers(
+ CosNotifyChannelAdmin::OR_OP,
+ this->sa_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ ok = ! CORBA::is_nil (this->sa_.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Supplier: Create new supplier admin %d\n"),
+ ACE_static_cast (int, this->sa_id_)
+ ));
+ }
+ }
+}
+
+void
+Supplier_Main::init_structured_proxy_consumer (ACE_ENV_SINGLE_ARG_DECL)
+{
+ bool ok = false;
+ CosNotifyChannelAdmin::ProxyConsumer_var proxy;
+ if (this->reconnecting_)
+ {
+ ACE_TRY_NEW_ENV
+ {
+ proxy = this->sa_->get_proxy_consumer (
+ this->structured_proxy_id_
+ ACE_ENV_ARG_PARAMETER
+ );
+ ACE_TRY_CHECK;
+ ok = ! CORBA::is_nil (proxy.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Supplier: Reconnect to proxy supplier %d\n"),
+ ACE_static_cast (int, this->structured_proxy_id_)
+ ));
+ }
+ }
+ ACE_CATCHALL
+ {
+ }
+ ACE_ENDTRY;
+ }
+
+ if (!ok)
+ {
+ proxy = this->sa_->obtain_notification_push_consumer(
+ CosNotifyChannelAdmin::STRUCTURED_EVENT,
+ this->structured_proxy_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ ok = ! CORBA::is_nil (proxy.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Supplier: Create new proxy %d\n"),
+ ACE_static_cast (int, this->structured_proxy_id_)
+ ));
+ }
+ }
+ this->structured_proxy_push_consumer_ =
+ CosNotifyChannelAdmin::StructuredProxyPushConsumer::_narrow(proxy.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ if (CORBA::is_nil (this->structured_proxy_push_consumer_.in ()))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) init_structured_proxy_consumer received nil ProxyConsumer\n")
+ ));
+ ACE_THROW (CORBA::OBJECT_NOT_EXIST ());
+ }
+ if (CORBA::is_nil (this->structured_push_supplier_ref_.in ()))
+ {
+ PortableServer::ObjectId_var push_supplier_id =
+ this->root_poa_->activate_object (
+ &(this->structured_push_supplier_) ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ CORBA::Object_var obj =
+ this->root_poa_->id_to_reference (push_supplier_id.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ this->structured_push_supplier_ref_ =
+ CosNotifyComm::StructuredPushSupplier::_narrow (obj.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+ if (CORBA::is_nil (structured_push_supplier_ref_.in ()))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Supplier: Received wrong type of push consumer proxy %d\n"),
+ ACE_static_cast (int, this->structured_proxy_id_)
+ ));
+
+ ACE_THROW (CORBA::UNKNOWN());
+ }
+
+ this->structured_proxy_push_consumer_->connect_structured_push_supplier (
+ structured_push_supplier_ref_.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+}
+
+void
+Supplier_Main::init_sequence_proxy_consumer (ACE_ENV_SINGLE_ARG_DECL)
+{
+ bool ok = false;
+ CosNotifyChannelAdmin::ProxyConsumer_var proxy;
+ if (this->reconnecting_)
+ {
+ ACE_TRY_NEW_ENV
+ {
+ proxy = this->sa_->get_proxy_consumer(
+ this->sequence_proxy_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ ok = ! CORBA::is_nil (proxy.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Supplier: Reconnect to proxy %d\n"),
+ ACE_static_cast (int, this->sequence_proxy_id_)
+ ));
+ }
+ }
+ ACE_CATCHALL
+ {
+ }
+ ACE_ENDTRY;
+ }
+
+ if (!ok)
+ {
+ proxy = this->sa_->obtain_notification_push_consumer(
+ CosNotifyChannelAdmin::SEQUENCE_EVENT,
+ this->sequence_proxy_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ ok = ! CORBA::is_nil (proxy.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Supplier: Create new proxy %d\n"),
+ ACE_static_cast (int, this->sequence_proxy_id_)
+ ));
+ }
+ }
+ this->sequence_proxy_push_consumer_ =
+ CosNotifyChannelAdmin::SequenceProxyPushConsumer::_narrow(proxy.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ if (CORBA::is_nil (this->sequence_proxy_push_consumer_.in ()))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Supplier: Received wrong type of push consumer proxy %d\n"),
+ ACE_static_cast (int, this->sequence_proxy_id_)
+ ));
+ ACE_THROW (CORBA::UNKNOWN());
+ }
+
+ if (CORBA::is_nil (this->sequence_push_supplier_ref_.in ()))
+ {
+ PortableServer::ObjectId_var push_supplier_id =
+ this->root_poa_->activate_object (
+ &(this->sequence_push_supplier_) ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ CORBA::Object_var obj =
+ this->root_poa_->id_to_reference (push_supplier_id.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ this->sequence_push_supplier_ref_ =
+ CosNotifyComm::SequencePushSupplier::_narrow (obj.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+ if (CORBA::is_nil (sequence_push_supplier_ref_.in ()))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Supplier: Received wrong type of push consumer proxy %d\n"),
+ ACE_static_cast (int, this->sequence_proxy_id_)
+ ));
+ ACE_THROW (CORBA::UNKNOWN());
+ }
+
+ this->sequence_proxy_push_consumer_->connect_sequence_push_supplier (
+ sequence_push_supplier_ref_.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+}
+
+void
+Supplier_Main::init_any_proxy_consumer (ACE_ENV_SINGLE_ARG_DECL)
+{
+ bool ok = false;
+ CosNotifyChannelAdmin::ProxyConsumer_var proxy;
+ if (this->reconnecting_)
+ {
+ ACE_TRY_NEW_ENV
+ {
+ proxy = this->sa_->get_proxy_consumer(
+ this->any_proxy_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ ok = ! CORBA::is_nil (proxy.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Supplier: Reconnect to proxy %d\n"),
+ ACE_static_cast (int, this->any_proxy_id_)
+ ));
+ }
+ }
+ ACE_CATCHALL
+ {
+ }
+ ACE_ENDTRY;
+ }
+
+ if (!ok)
+ {
+ proxy = this->sa_->obtain_notification_push_consumer(
+ CosNotifyChannelAdmin::ANY_EVENT,
+ this->any_proxy_id_
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ ok = ! CORBA::is_nil (proxy.in ());
+ if (ok && this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Supplier: Create new proxy\n"),
+ ACE_static_cast (int, this->any_proxy_id_)
+ ));
+ }
+ }
+ this->any_proxy_push_consumer_ =
+ CosNotifyChannelAdmin::ProxyPushConsumer::_narrow(proxy.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ if (CORBA::is_nil (this->any_proxy_push_consumer_.in ()))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Supplier: Received wrong type of push consumer proxy %d\n"),
+ ACE_static_cast (int, this->any_proxy_id_)
+ ));
+ ACE_THROW (CORBA::UNKNOWN());
+ }
+
+ if (CORBA::is_nil (this->any_push_supplier_ref_.in ()))
+ {
+ PortableServer::ObjectId_var push_supplier_id =
+ this->root_poa_->activate_object (
+ &(this->any_push_supplier_) ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ CORBA::Object_var obj =
+ this->root_poa_->id_to_reference (push_supplier_id.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ this->any_push_supplier_ref_ =
+ CosNotifyComm::PushSupplier::_narrow (obj.in () ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+ if (CORBA::is_nil (any_push_supplier_ref_.in ()))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Supplier: Received wrong type of push consumer proxy %d\n"),
+ ACE_static_cast (int, this->sequence_proxy_id_)
+ ));
+ ACE_THROW (CORBA::UNKNOWN());
+ }
+
+ this->any_proxy_push_consumer_->connect_any_push_supplier (
+ any_push_supplier_ref_.in ()
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+}
+
+int Supplier_Main::fini (ACE_ENV_SINGLE_ARG_DECL)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) supplier::fini\n")
+ ));
+ if (this->disconnect_on_exit_)
+ {
+ this->reconnection_callback_.fini (ACE_ENV_SINGLE_ARG_PARAMETER);
+ if (!CORBA::is_nil (this->structured_proxy_push_consumer_.in ()))
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Disconnecting structured\n")
+ ));
+ }
+ this->structured_proxy_push_consumer_->disconnect_structured_push_consumer (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-4);
+ }
+ if (!CORBA::is_nil (this->sequence_proxy_push_consumer_.in ()))
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Disconnecting sequence\n")
+ ));
+ }
+ this->sequence_proxy_push_consumer_->disconnect_sequence_push_consumer (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-4);
+ }
+ if (!CORBA::is_nil (this->any_proxy_push_consumer_.in ()))
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Disconnecting any\n")
+ ));
+ }
+ this->any_proxy_push_consumer_->disconnect_push_consumer (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-4);
+ }
+ if (!CORBA::is_nil (this->sa_.in ()) && this->sa_id_ != default_admin_id)
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) destroy admin %d\n"),
+ ACE_static_cast(int, this->sa_id_)
+ ));
+ }
+ this->sa_->destroy();
+ }
+ }
+ this->orb_->shutdown ();
+ return 0;
+}
+
+void Supplier_Main::send_structured_event (ACE_ENV_SINGLE_ARG_DECL)
+{
+ CosNotification::StructuredEvent event;
+
+ // EventHeader.
+
+ // FixedEventHeader.
+ // EventType.
+ // string.
+ event.header.fixed_header.event_type.domain_name = CORBA::string_dup("*");
+ // string
+ event.header.fixed_header.event_type.type_name = CORBA::string_dup("*");
+ // string
+ event.header.fixed_header.event_name = CORBA::string_dup("reconnect_test");
+
+ // OptionalHeaderFields.
+ // PropertySeq.
+ // sequence<Property>: string name, any value
+ CosNotification::PropertySeq& qos = event.header.variable_header;
+ qos.length (2);
+ qos[0].name = CORBA::string_dup (CosNotification::Priority);
+ qos[0].value <<= CosNotification::LowestPriority;
+ qos[1].name = CORBA::string_dup (CosNotification::EventReliability);
+ qos[1].value <<= CosNotification::Persistent;
+
+ // FilterableEventBody
+ // PropertySeq
+ // sequence<Property>: string name, any value
+ event.filterable_data.length (1);
+ event.filterable_data[0].name = CORBA::string_dup("serial_number");
+ event.filterable_data[0].value <<= CORBA::ULong ( this->serial_number_);
+
+ // any
+ event.remainder_of_body <<= CORBA::ULong ( this->serial_number_);
+
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) Supplier push structured event %d\n"),
+ ACE_static_cast (int, serial_number_)
+ ));
+ }
+
+ this->structured_proxy_push_consumer_->push_structured_event (event
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+}
+
+void Supplier_Main::send_sequence_event (ACE_ENV_SINGLE_ARG_DECL)
+{
+ CosNotification::EventBatch event_batch(1);
+ event_batch.length (1);
+ CosNotification::StructuredEvent & event = event_batch[0];
+
+ // EventHeader.
+
+ // FixedEventHeader.
+ // EventType.
+ // string.
+ event.header.fixed_header.event_type.domain_name = CORBA::string_dup("*");
+ // string
+ event.header.fixed_header.event_type.type_name = CORBA::string_dup("*");
+ // string
+ event.header.fixed_header.event_name = CORBA::string_dup("reconnect_test");
+
+ // OptionalHeaderFields.
+ // PropertySeq.
+ // sequence<Property>: string name, any value
+ CosNotification::PropertySeq& qos = event.header.variable_header;
+ qos.length (2);
+ qos[0].name = CORBA::string_dup (CosNotification::Priority);
+ qos[0].value <<= CosNotification::LowestPriority;
+ qos[1].name = CORBA::string_dup (CosNotification::EventReliability);
+ qos[1].value <<= CosNotification::Persistent;
+
+ // FilterableEventBody
+ // PropertySeq
+ // sequence<Property>: string name, any value
+ event.filterable_data.length (1);
+ event.filterable_data[0].name = CORBA::string_dup("serial_number");
+ event.filterable_data[0].value <<= CORBA::ULong ( this->serial_number_);
+
+ // any
+ event.remainder_of_body <<= CORBA::ULong ( this->serial_number_);
+
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) Supplier push sequence events %d\n"),
+ ACE_static_cast (int, this->serial_number_)
+ ));
+ }
+
+ this->sequence_proxy_push_consumer_->push_structured_events (event_batch
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+}
+
+void Supplier_Main::send_any_event (ACE_ENV_SINGLE_ARG_DECL)
+{
+ CORBA::Any event;
+ event <<= CORBA::ULong (this->serial_number_);
+
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) Supplier push any event %d\n"),
+ ACE_static_cast (int, this->serial_number_)
+ ));
+ }
+
+ this->any_proxy_push_consumer_->push (event
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+}
+
+int Supplier_Main::run (ACE_ENV_SINGLE_ARG_DECL)
+{
+ int result = 0;
+ bool paused = false;
+ size_t reconnections = 0;
+
+ size_t send = 0;
+ while ( send < this->send_)
+ {
+ // keep the orb alive -- listenting for reconnect
+ if (this->orb_->work_pending ())
+ {
+ this->orb_->perform_work ();
+ }
+
+ if (this->pause_ != 0 && send == this->pause_)
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Supplier paused after %d events\n"),
+ ACE_static_cast (int, this->pause_)
+ ));
+ }
+ reconnections = this->reconnection_callback_.reconnect_count ();
+ FILE * pause_file = ACE_OS::fopen ("Supplier.paused", "w");
+ if (pause_file != 0)
+ {
+ ACE_OS::fputs (ACE_TEXT ("paused\n"), pause_file);
+ ACE_OS::fclose (pause_file);
+ }
+ paused = true;
+ this->pause_ = 0;
+ }
+ if (paused)
+ {
+ if (this->reconnection_callback_.reconnect_count () != reconnections)
+ {
+ if (this->verbose_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Supplier no longer paused. Next s# %d\n"),
+ ACE_static_cast (int, this->serial_number_)
+ ));
+ }
+ paused = false;
+ }
+ }
+
+ if (!paused)
+ {
+ switch (this->mode_)
+ {
+ case MODE_STRUCTURED:
+ {
+ send_structured_event (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+ break;
+ }
+ case MODE_SEQUENCE:
+ {
+ send_sequence_event (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+ break;
+ }
+ case MODE_ANY:
+ {
+ send_any_event (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (-1);
+ break;
+ }
+ }
+ this->serial_number_ += 1;
+ send += 1;
+ }
+ }
+ return result;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ int result = -1;
+ Supplier_Main app;
+ ACE_TRY_NEW_ENV
+ {
+ result = app.init(argc, argv ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK
+
+ if (result == 0)
+ {
+ result = app.run (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+ if (result == 0)
+ {
+ app.fini (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+ }
+ ACE_CATCHANY
+ {
+ ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION,
+ "Supplier::main\t\n");
+ result = -1;
+ }
+ ACE_ENDTRY;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P,%t) Supplier exits: code %d\n"),
+ result
+ ));
+ return result;
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/Supplier.h b/TAO/orbsvcs/tests/Notify/Reconnecting/Supplier.h
new file mode 100644
index 00000000000..f429cf7892c
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/Reconnecting/Supplier.h
@@ -0,0 +1,209 @@
+/* -*- C++ -*- */
+// $Id$
+// ==========================================================================
+//
+// = FILENAME
+// Supplier.h
+//
+// = DESCRIPTION
+// Test Supplier reconnect to existing channel/admin/proxy Notification Service
+//
+// = AUTHOR
+// Dale Wilson <wilson_d@ociweb.com>
+//
+// ==========================================================================
+
+#ifndef RECONNECTNG_SUPPLIER_H
+#define RECONNECTNG_SUPPLIER_H
+
+#include "orbsvcs/CosNotifyChannelAdminC.h"
+#include "orbsvcs/CosNamingC.h"
+#include "orbsvcs/NotifyExtS.h"
+#include <ace/SString.h>
+
+class Supplier_Main;
+
+class StructuredPushSupplier_i : public virtual POA_CosNotifyComm::StructuredPushSupplier
+{
+ virtual void subscription_change (
+ const CosNotification::EventTypeSeq & added,
+ const CosNotification::EventTypeSeq & removed
+ ACE_ENV_ARG_DECL
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ CosNotifyComm::InvalidEventType));
+
+ virtual void disconnect_structured_push_supplier (
+ ACE_ENV_SINGLE_ARG_DECL
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException));
+};
+
+class SequencePushSupplier_i : public virtual POA_CosNotifyComm::SequencePushSupplier
+{
+ virtual void subscription_change (
+ const CosNotification::EventTypeSeq & added,
+ const CosNotification::EventTypeSeq & removed
+ ACE_ENV_ARG_DECL
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ CosNotifyComm::InvalidEventType));
+
+ virtual void disconnect_sequence_push_supplier (
+ ACE_ENV_SINGLE_ARG_DECL
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException));
+};
+
+class AnyPushSupplier_i : public virtual POA_CosNotifyComm::PushSupplier
+{
+ virtual void subscription_change (
+ const CosNotification::EventTypeSeq & added,
+ const CosNotification::EventTypeSeq & removed
+ ACE_ENV_ARG_DECL
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ CosNotifyComm::InvalidEventType));
+
+ virtual void disconnect_push_supplier (
+ ACE_ENV_SINGLE_ARG_DECL
+ )
+ ACE_THROW_SPEC ((CORBA::SystemException));
+};
+
+class ReconnectionCallback_i : public virtual POA_NotifyExt::ReconnectionCallback
+{
+public:
+ ReconnectionCallback_i (Supplier_Main & supplier_main);
+
+ virtual ~ReconnectionCallback_i ();
+
+ void init (
+ PortableServer::POA_ptr poa,
+ CosNotifyChannelAdmin::EventChannelFactory_ptr ecf_
+ ACE_ENV_ARG_DECL);
+
+ void fini (ACE_ENV_SINGLE_ARG_DECL);
+
+ size_t reconnect_count () const;
+
+ virtual void reconnect (
+ CORBA::Object_ptr reconnection
+ ACE_ENV_ARG_DECL
+ ) ACE_THROW_SPEC ((CORBA::SystemException));
+
+ virtual CORBA::Boolean is_alive (ACE_ENV_SINGLE_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException));
+
+private:
+ Supplier_Main & supplier_main_;
+ bool id_is_valid_;
+ NotifyExt::ReconnectionRegistry::ReconnectionID callback_id_;
+ CosNotifyChannelAdmin::EventChannelFactory_var ecf_;
+ size_t reconnect_count_;
+};
+
+class Supplier_Main
+{
+ public:
+ Supplier_Main ();
+ ~Supplier_Main ();
+
+ int parse_args (int argc, char *argv[]);
+ int parse_single_arg (int argc, char *argv[]);
+
+ int init (int argc, char *argv[] ACE_ENV_ARG_DECL);
+ int run (ACE_ENV_SINGLE_ARG_DECL);
+ int fini (ACE_ENV_SINGLE_ARG_DECL);
+ void usage (FILE * log) const;
+
+ void reconnect (
+ CosNotifyChannelAdmin::EventChannelFactory_ptr dest_factory
+ ACE_ENV_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException));
+
+ private:
+ /// Find naming service.
+ int resolve_naming_service (ACE_ENV_SINGLE_ARG_DECL);
+
+ /// Resolve the Notify factory from the Naming service.
+ int find_notify_factory (ACE_ENV_SINGLE_ARG_DECL);
+
+ /// Resolve the Notify factory using resolve_initial_reference ("NotifyEventChannelFactory")
+ int resolve_notify_factory (ACE_ENV_SINGLE_ARG_DECL);
+
+ void init_event_channel (ACE_ENV_SINGLE_ARG_DECL);
+ void init_supplier_admin (ACE_ENV_SINGLE_ARG_DECL);
+ void init_structured_proxy_consumer (ACE_ENV_SINGLE_ARG_DECL);
+ void init_sequence_proxy_consumer (ACE_ENV_SINGLE_ARG_DECL);
+ void init_any_proxy_consumer (ACE_ENV_SINGLE_ARG_DECL);
+
+ /// send events.
+ void send_structured_event (ACE_ENV_SINGLE_ARG_DECL);
+ void send_sequence_event (ACE_ENV_SINGLE_ARG_DECL);
+ void send_any_event (ACE_ENV_SINGLE_ARG_DECL);
+
+ void save_ids();
+ bool load_ids();
+
+ ////////////////////
+ // forbidden methods
+ private:
+ Supplier_Main (const Supplier_Main & rhs);
+ Supplier_Main & operator = (const Supplier_Main & rhs);
+
+ ////////////////
+ // Data members
+ private:
+
+ // set by command line parameters
+ bool verbose_; // -v make a glorious noise
+ enum Mode_T {
+ MODE_ANY,
+ MODE_STRUCTURED,
+ MODE_SEQUENCE} mode_; // -any, -structured, or -sequence
+ ACE_CString channel_file_; // -channel filename
+ size_t send_; // -send n
+ bool use_naming_service_; // -nonamesvc
+ size_t serial_number_; // -serial_number
+ bool disconnect_on_exit_; // -disconnect
+ ACE_CString id_file_; // -ids
+ size_t pause_; // -pause n (pause after sending n messages)
+ CORBA::ORB_var orb_;
+ PortableServer::POA_var root_poa_;
+ CosNaming::NamingContext_var naming_context_;
+ CosNotifyChannelAdmin::EventChannelFactory_var ecf_;
+
+ CosNotifyChannelAdmin::EventChannel_var ec_;
+ CosNotifyChannelAdmin::ChannelID ec_id_;
+
+ CosNotifyChannelAdmin::SupplierAdmin_var sa_;
+ CosNotifyChannelAdmin::AdminID sa_id_;
+
+ CosNotifyChannelAdmin::StructuredProxyPushConsumer_var structured_proxy_push_consumer_;
+ CosNotifyChannelAdmin::ProxyID structured_proxy_id_;
+ StructuredPushSupplier_i structured_push_supplier_;
+ CosNotifyComm::StructuredPushSupplier_var structured_push_supplier_ref_;
+
+
+ CosNotifyChannelAdmin::SequenceProxyPushConsumer_var sequence_proxy_push_consumer_;
+ CosNotifyChannelAdmin::ProxyID sequence_proxy_id_;
+ SequencePushSupplier_i sequence_push_supplier_;
+ CosNotifyComm::SequencePushSupplier_var sequence_push_supplier_ref_;
+
+ CosNotifyChannelAdmin::ProxyPushConsumer_var any_proxy_push_consumer_;
+ CosNotifyChannelAdmin::ProxyID any_proxy_id_;
+ AnyPushSupplier_i any_push_supplier_;
+ CosNotifyComm::PushSupplier_var any_push_supplier_ref_;
+
+ ReconnectionCallback_i reconnection_callback_;
+
+ bool reconnecting_;
+};
+
+
+
+#endif /* RECONNECTNG_SUPPLIER_H */
diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/event.conf b/TAO/orbsvcs/tests/Notify/Reconnecting/event.conf
new file mode 100644
index 00000000000..04992b13665
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/Reconnecting/event.conf
@@ -0,0 +1,6 @@
+
+static CosNotify_Service "-AllowReconnect"
+
+# This should fail because event perstence requires topology persistence
+
+dynamic Event_Persistence Service_Object* TAO_CosNotification:_make_Standard_Event_Persistence() "-v -file_path ./event_persist.db" \ No newline at end of file
diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt.conf b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt.conf
new file mode 100644
index 00000000000..bb4c2d1f954
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt.conf
@@ -0,0 +1,10 @@
+
+## -DispatchingThreads N - creates a thread pool for dispatching and consumer side filter eval
+## -SourceThreads M - creates a thread pool for lookup and supplier side filter eval
+
+## This prevents worker threads from joining the tp reactor
+##static Client_Strategy_Factory "-ORBClientConnectionHandler rw"
+
+static CosNotify_Service "-DispatchingThreads 2 -SourceThreads 2 -AllowReconnect"
+
+
diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt_both.conf b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt_both.conf
new file mode 100644
index 00000000000..00559411451
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt_both.conf
@@ -0,0 +1,5 @@
+static CosNotify_Service "-DispatchingThreads 2 -SourceThreads 2 -AllowReconnect"
+
+dynamic Topology_Factory Service_Object* TAO_CosNotification_persist:_make_XML_Topology_Factory() "-base_path ./reconnect_test"
+dynamic Event_Persistence Service_Object* TAO_CosNotification_persist:_make_Standard_Event_Persistence() "-file_path ./event_persist.db"
+
diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt_topo.conf b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt_topo.conf
new file mode 100644
index 00000000000..0ab2672941d
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt_topo.conf
@@ -0,0 +1,3 @@
+static CosNotify_Service "-DispatchingThreads 2 -SourceThreads 2 -AllowReconnect"
+dynamic Topology_Factory Service_Object* TAO_CosNotification_persist:_make_XML_Topology_Factory() "-base_path ./reconnect_test"
+
diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st.conf b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st.conf
new file mode 100644
index 00000000000..902cc095284
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st.conf
@@ -0,0 +1,4 @@
+
+static CosNotify_Service "-AllowReconnect"
+
+
diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st_both.conf b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st_both.conf
new file mode 100644
index 00000000000..5496d663e82
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st_both.conf
@@ -0,0 +1,4 @@
+static CosNotify_Service "-AllowReconnect"
+
+dynamic Topology_Factory Service_Object* TAO_CosNotification_persist:_make_XML_Topology_Factory() "-v -base_path ./reconnect_test"
+dynamic Event_Persistence Service_Object* TAO_CosNotification_persist:_make_Standard_Event_Persistence() "-v -file_path ./event_persist.db"
diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st_topo.conf b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st_topo.conf
new file mode 100644
index 00000000000..d6f099b3d24
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st_topo.conf
@@ -0,0 +1,2 @@
+static CosNotify_Service "-AllowReconnect"
+dynamic Topology_Factory Service_Object* TAO_CosNotification_persist:_make_XML_Topology_Factory() "-v -base_path ./reconnect_test"
diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/run_test.pl b/TAO/orbsvcs/tests/Notify/Reconnecting/run_test.pl
new file mode 100755
index 00000000000..c878e97f8c4
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/Reconnecting/run_test.pl
@@ -0,0 +1,386 @@
+eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
+ & eval 'exec perl -S $0 $argv:q'
+ if 0;
+
+# $Id$
+# -*- perl -*-
+
+use lib "../../../../../bin";
+use PerlACE::Run_Test;
+
+my($eventType) = "-any"; # your choice of -any -structured or -sequence
+
+my($ACE_ROOT) = $ENV{ACE_ROOT};
+my($TAO_ROOT) = "$ACE_ROOT/TAO";
+
+my($notify_port) = "9889";
+
+#file used to detect notification service startup
+my($notify_ior) = PerlACE::LocalFile("notify.ior");
+#hard coded file name in Consumer.cpp (for now)
+my($consumer_ids) = PerlACE::LocalFile("consumer.ids");
+#hard coded file name in Supplier.cpp (for now)
+my($supplier_ids) = PerlACE::LocalFile("supplier.ids");
+#file used to communicate channel # from consumer to supplier
+my($channel_id) = PerlACE::LocalFile("channel_id");
+#file names comes from svc.conf (+.xml & .000)
+my($save_xml) = PerlACE::LocalFile("./reconnect_test.xml");
+my($save_000) = PerlACE::LocalFile("./reconnect_test.000");
+my($eventpersist) = PerlACE::LocalFile("./event_persist.db");
+# hardcode filename written by the Supplier when it pauses.
+my($supplier_pause) = PerlACE::LocalFile("Supplier.paused");
+
+my($verbose) = "";
+
+my $svcconf = "ns_st_topo.conf";
+
+# Process command line arguments
+foreach $i (@ARGV) {
+ if ($i eq "-any") {
+ $eventType = "-any";
+ }
+ elsif ($i eq "-str" or $i eq "-structured") {
+ $eventType = "-structured";
+ }
+ elsif ($i eq "-seq" or $i eq "-sequence") {
+ $eventType = "-sequence";
+ }
+ elsif ($i eq "-mt") {
+ $svcconf = "ns_mt_topo.conf";
+ }
+ elsif ($i eq "-v" or $i eq "-verbose") {
+ $verbose = "-v";
+ }
+ else {
+ print "TEST SCRIPT: unknown: $i\n";
+ print "TEST SCRIPT: usage: [-any|-str|-seq] -mt -v\n";
+ exit -4;
+ }
+}
+
+my($client_args) = " $eventType $verbose -NoNameSvc -ORBInitRef NotifyEventChannelFactory=corbaloc::localhost:$notify_port/NotifyEventChannelFactory ";
+my($ns_args) = " -NoNameSvc -Boot -ORBSvcConf $svcconf -IORoutput $notify_ior -ORBEndpoint iiop://:$notify_port ";
+#my($ns_args_hidden) = " -NoNameSvc -Boot -ORBSvcConf $svcconf -IORoutput $notify_ior";
+# nuke the topology save files so we start clean
+unlink $save_xml;
+unlink $save_000;
+unlink $eventpersist;
+unlink $notify_ior;
+
+
+##define the processes first
+my($NS) = new PerlACE::Process("$TAO_ROOT/orbsvcs/Notify_Service/Notify_Service");
+my($CON) = new PerlACE::Process("./Consumer");
+my($SUP) = new PerlACE::Process("./Supplier");
+
+if ($verbose eq "-v") {print "TEST SCRIPT: Starting Notify Service on port $notify_port\n";}
+$NS->Arguments($ns_args);
+if ($verbose eq "-v") {print "TEST SCRIPT: " . $NS->CommandLine . "\n";}
+$NS->Spawn();
+
+# the ior file is only used to wait for the service to start
+if (PerlACE::waitforfile_timed ($notify_ior, 10) == -1) {
+ print STDERR "ERROR: Timed out waiting for $notify_ior\n";
+ $NS->Kill ();
+ exit 1;
+}
+# be sure consumer doesn't try to reconnect the first time
+unlink $consumer_ids;
+# don't use previous channel id
+unlink $channel_id;
+
+# start the consumer,
+# write the channel number to channel.id for use by Supplier
+# expect to receive 20 events of type any
+#
+$CON->Arguments("-channel $channel_id -expect 20 $client_args");
+if ($verbose eq "-v") {print "TEST SCRIPT: " . $CON->CommandLine . "\n";}
+$CON->Spawn();
+
+# wait for the channel number file
+if (PerlACE::waitforfile_timed ($channel_id, 10) == -1) {
+ print STDERR "ERROR: Timed out waiting for Consumer to write $channel_id\n";
+ $NS->Kill ();
+ $CON->Kill ();
+ exit 1;
+}
+
+# discard old reconnect information
+unlink $supplier_ids;
+
+# send 10 Any's, picking up the channel# from channel.id
+$SUP->Arguments("-channel $channel_id -send 10 $client_args");
+if ($verbose eq "-v") {print "TEST SCRIPT: " . $SUP->CommandLine . "\n";}
+$SUP->SpawnWaitKill(60);
+
+# forget the channel id, depend on the reconnect information
+unlink $channel_id;
+
+$SUP->Arguments("-send 10 -serial_number 10 $client_args");
+if ($verbose eq "-v") {print "TEST SCRIPT: " . $SUP->CommandLine . "\n";}
+$SUP->SpawnWaitKill(60);
+
+$status = $CON->WaitKill (60);
+
+if ($status) {
+ print STDERR "ERROR: Consumer reported error\n";
+ $NS->Kill();
+ exit $status;
+ }
+
+print "TEST SCRIPT: ****Passed: Supplier reconnect test.\n";
+
+################
+#end of test 1
+################
+
+# Now start the consumer again. Depending on reconnect this time
+# Let it write the channel.id file so we know when it's up.
+
+if ($verbose eq "-v") {print "TEST SCRIPT: " . $CON->CommandLine . "\n";}
+$CON->Spawn();
+# wait for the channel number file
+if (PerlACE::waitforfile_timed ($channel_id, 10) == -1) {
+ print STDERR "ERROR: Timed out waiting for Consumer to write $channel_id\n";
+ $NS->Kill ();
+ $CON->Kill ();
+ exit 1;
+}
+
+# forget the channel id, depend on the supplier reconnect information
+unlink $channel_id;
+
+$SUP->Arguments("-send 20 -serial_number 0 $client_args");
+if ($verbose eq "-v") {print "TEST SCRIPT: " . $SUP->CommandLine . "\n";}
+$status= $SUP->SpawnWaitKill(60);
+if ($status) {
+ print STDERR "ERROR: Supplier reported error\n";
+ $CON->Kill();
+ $NS->Kill();
+ exit $status;
+ }
+
+$status = $CON->WaitKill (60);
+if ($status) {
+ print STDERR "ERROR: Consumer reported error\n";
+ $NS->Kill();
+ exit $status;
+ }
+
+print "TEST SCRIPT: ****Passed: Consumer reconnect test.\n";
+
+################
+#end of test 2
+################
+
+if ($verbose eq "-v") {print "TEST SCRIPT: Stop the Notification Service\n";}
+$NS->Kill();
+unlink $notify_ior;
+
+if ($verbose eq "-v") {print "TEST SCRIPT: Restarting Notify Service on port $notify_port\n";}
+if ($verbose eq "-v") {print "TEST SCRIPT: It should load topology from $save_xml\n";}
+
+# sleep to avoid socket-related problems
+sleep (10 * $PerlACE::Process::WAIT_DELAY_FACTOR);
+$NS->Arguments($ns_args);
+if ($verbose eq "-v") {print "TEST SCRIPT: " . $NS->CommandLine . "\n";}
+$NS->Spawn();
+
+# the ior file is only used to wait for the service to start
+if (PerlACE::waitforfile_timed ($notify_ior, 10) == -1) {
+ print STDERR "ERROR: Timed out waiting for $notify_ior\n";
+ $NS->Kill ();
+ exit 1;
+}
+
+# Now start the consumer again. It will use the reconnect info.
+# Let it write the channel.id file so we know when it's up.
+unlink $channel_id;
+
+if ($verbose eq "-v") {print "TEST SCRIPT: " . $CON->CommandLine . "\n";}
+$CON->Spawn();
+# wait for the channel number file
+if (PerlACE::waitforfile_timed ($channel_id, 10) == -1) {
+ print STDERR "ERROR: Timed out waiting for Consumer to write $channel_id\n";
+ $NS->Kill ();
+ $CON->Kill ();
+ exit 1;
+}
+
+# forget the channel id, depend on the supplier reconnect information
+unlink $channel_id;
+
+$SUP->Arguments("-send 20 -serial_number 0 $client_args");
+if ($verbose eq "-v") {print "TEST SCRIPT: " . $SUP->CommandLine . "\n";}
+$status = $SUP->SpawnWaitKill(60);
+if ($status) {
+ print STDERR "ERROR: Supplier reported error\n";
+ $NS->Kill();
+ $CON->Kill();
+ exit $status;
+ }
+
+$status = $CON->WaitKill (60);
+if ($status) {
+ print STDERR "ERROR: Consumer reported error\n";
+ $NS->Kill();
+ exit $status;
+ }
+
+print "TEST SCRIPT: ****Passed: Topology Persistence Test.\n";
+
+################
+#end of test 3
+################
+
+# Now start the consumer one more time
+# Let it write the channel.id file so we know when it's up.
+unlink $channel_id;
+
+if ($verbose eq "-v") {print "TEST SCRIPT: " . $CON->CommandLine . "\n";}
+$CON->Spawn();
+# wait for the channel number file
+if (PerlACE::waitforfile_timed ($channel_id, 10) == -1) {
+ print STDERR "ERROR: Timed out waiting for Consumer to write $channel_id\n";
+ $NS->Kill ();
+ $CON->Kill ();
+ exit 1;
+}
+
+# forget the channel id, depend on the supplier reconnect information
+unlink $channel_id;
+
+# Start the Supplier, tell it to send 10 messages, pause until it is reconnected
+# then send another 10.
+
+unlink ($supplier_pause);
+
+$SUP->Arguments("-send 20 -pause 10 -serial_number 0 $client_args");
+if ($verbose eq "-v") {print "TEST SCRIPT: " . $SUP->CommandLine . "\n";}
+$SUP->Spawn();
+
+# wait for the supplier's "paused" file
+if (PerlACE::waitforfile_timed ($supplier_pause, 30) == -1) {
+ print STDERR "ERROR: Timed out waiting for Supplier to write $supplier_pause\n";
+ $NS->Kill ();
+ $SUP->Kill ();
+ $CON->Kill ();
+ exit 1;
+}
+unlink ($supplier_pause);
+
+if ($verbose eq "-v") {print "TEST SCRIPT: Stop the Notification Service\n";}
+$NS->Kill();
+unlink $notify_ior;
+
+if ($verbose eq "-v") {print "TEST SCRIPT: Restarting Notify Service\n";}
+if ($verbose eq "-v") {print "TEST SCRIPT: Use unspecified port to make it \"invisible\" to clients\n";}
+if ($verbose eq "-v") {print "TEST SCRIPT: It should load topology from $save_xml\n";}
+if ($verbose eq "-v") {print "TEST SCRIPT: and reconnect to registered clients.\n";}
+
+#$NS->Arguments($ns_args_hidden);
+# sleep to avoid socket-related problems
+sleep (10 * $PerlACE::Process::WAIT_DELAY_FACTOR);
+
+if ($verbose eq "-v") {print "TEST SCRIPT: " . $NS->CommandLine . "\n";}
+$NS->Spawn();
+
+# at this point, both the consumer and the supplier should reconnect
+# and the remaining events should be delivered
+# eventually the consumer will finish
+
+$status = $CON->WaitKill (20);
+if ($status) {
+ print STDERR "ERROR: Consumer reported error\n";
+ $SUP->Kill();
+ $NS->Kill();
+ exit $status;
+ }
+
+$status = $SUP->Kill ();
+if ($status) {
+ print STDERR "ERROR: Supplier reported error\n";
+ $NS->Kill();
+ exit $status;
+ }
+
+print "TEST SCRIPT: ****Passed: Reconnection Factory test.\n";
+
+################
+#end of test 4
+################
+
+if ($verbose eq "-v") {print "TEST SCRIPT: Stop the Notification Service\n";}
+$NS->Kill();
+
+unlink $notify_ior;
+unlink $save_xml;
+unlink $save_000;
+unlink $eventpersist;
+unlink $consumer_ids;
+unlink $channel_id;
+unlink $supplier_ids;
+
+sleep (10 * $PerlACE::Process::WAIT_DELAY_FACTOR); ## avoid lingering sockets
+# go back to normal ns args
+$NS->Arguments($ns_args);
+if ($verbose eq "-v") {print "TEST SCRIPT: " . $NS->CommandLine . "\n";}
+$NS->Spawn();
+
+# the ior file is only used to wait for the service to start
+if (PerlACE::waitforfile_timed ($notify_ior, 20) == -1) {
+ print STDERR "ERROR: Timed out waiting for $notify_ior\n";
+ $NS->Kill ();
+ exit 1;
+}
+
+#configure the consumer to expect 20 events, fail (throw an exception
+# after 8 events) then continue to listen for remaining events.
+#The Notification service should automatically retry (but may discard)
+# the failed events.
+$CON->Arguments("-channel $channel_id -expect 20 -fail 8 $client_args");
+if ($verbose eq "-v") {print "TEST SCRIPT: " . $CON->CommandLine . "\n";}
+$CON->Spawn();
+
+# wait for the channel number file
+if (PerlACE::waitforfile_timed ($channel_id, 10) == -1) {
+ print STDERR "ERROR: Timed out waiting for Consumer to write $channel_id\n";
+ $NS->Kill ();
+ $CON->Kill ();
+ exit 1;
+}
+
+$SUP->Arguments("-channel $channel_id -send 20 $client_args");
+if ($verbose eq "-v") {print "TEST SCRIPT: " . $SUP->CommandLine . "\n";}
+$status = $SUP->SpawnWaitKill(20);
+if ($status) {
+ print STDERR "ERROR: Supplier reported error\n";
+ $NS->Kill();
+ $CON->Kill ();
+ exit $status;
+ }
+
+## this is a slow test due to the reconnection
+## time, so give it enough time...
+$status = $CON->WaitKill (240);
+
+if ($status) {
+ print STDERR "ERROR: Consumer reported error\n";
+ $NS->Kill();
+ exit $status;
+ }
+
+print "TEST SCRIPT: ****Passed: Consumer recoverable exception test.\n";
+
+################
+#end of test 5
+################
+
+if ($verbose eq "-v") {print "TEST SCRIPT: Stop the Notification Service\n";}
+$NS->Kill();
+unlink $notify_ior;
+unlink $save_xml;
+unlink $save_000;
+unlink $eventpersist;
+
+exit $status;
diff --git a/TAO/orbsvcs/tests/Notify/XML_Persistence/XML_Persistence.mpc b/TAO/orbsvcs/tests/Notify/XML_Persistence/XML_Persistence.mpc
new file mode 100644
index 00000000000..040b6dab9f0
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/XML_Persistence/XML_Persistence.mpc
@@ -0,0 +1,2 @@
+project : orbsvcsexe, portableserver, notify_serv {
+}
diff --git a/TAO/orbsvcs/tests/Notify/XML_Persistence/main.cpp b/TAO/orbsvcs/tests/Notify/XML_Persistence/main.cpp
new file mode 100644
index 00000000000..d5fc70bfc38
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/XML_Persistence/main.cpp
@@ -0,0 +1,360 @@
+/**
+ * $Id$
+ */
+
+#include <orbsvcs/orbsvcs/CosNotificationC.h>
+#include <orbsvcs/orbsvcs/NotifyExtC.h>
+#include <orbsvcs/orbsvcs/Notify/Notify_EventChannelFactory_i.h>
+
+#include <tao/TimeBaseC.h>
+#include <tao/corba.h>
+#include <tao/PortableServer/PortableServer.h>
+
+#include "ace/OS_NS_string.h"
+#include <ace/OS_NS_stdio.h>
+#include <ace/Dynamic_Service.h>
+#include <ace/ARGV.h>
+
+class TestSupplier
+: public POA_CosNotifyComm::StructuredPushSupplier
+{
+ virtual void disconnect_structured_push_supplier(ACE_ENV_SINGLE_ARG_DECL_NOT_USED) throw (CORBA::SystemException) {
+ }
+
+ virtual void subscription_change( const CosNotification::EventTypeSeq&,
+ const CosNotification::EventTypeSeq& ACE_ENV_ARG_DECL_NOT_USED)
+ throw (CORBA::SystemException, CosNotifyComm::InvalidEventType)
+ {
+ }
+};
+
+class TestConsumer
+: public POA_CosNotifyComm::StructuredPushConsumer
+{
+ virtual void disconnect_structured_push_consumer(ACE_ENV_SINGLE_ARG_DECL_NOT_USED) throw (CORBA::SystemException) {
+ }
+
+ virtual void offer_change( const CosNotification::EventTypeSeq&, const CosNotification::EventTypeSeq& ACE_ENV_ARG_DECL_NOT_USED)
+ throw (CORBA::SystemException, CosNotifyComm::InvalidEventType)
+ {
+ }
+
+ virtual void push_structured_event(const CosNotification::StructuredEvent& ACE_ENV_ARG_DECL_NOT_USED)
+ throw (CORBA::SystemException, CosEventComm::Disconnected)
+ {
+ }
+};
+
+int main(int ac, char **av)
+{
+ int retval = 1;
+
+ bool pass1 = false;
+ bool pass2 = false;
+ ACE_DECLARE_NEW_CORBA_ENV;
+ ACE_TRY
+ {
+ CORBA::ORB_var orb;
+ PortableServer::POA_var poa;
+
+ orb = CORBA::ORB_init(ac, av, "" ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ ACE_ASSERT(! CORBA::is_nil (orb.in ()));
+
+ if (ac > 2
+ && ACE_OS::strcmp (av[1], "-pass"))
+ {
+ int pn = av[2][0] - '0';
+ switch (pn)
+ {
+ case 1:
+ pass1 = true;
+ pass2 = false;
+ break;
+ case 2:
+ pass1 = false;
+ pass2 = true;
+ break;
+ case 3:
+ pass1 = true;
+ pass2 = true;
+ break;
+ default:
+ fprintf (stderr, "Illegal -pass command line option. Expecting 1, 2, or 3\n");
+ return -1;
+ }
+ }
+ if (! pass1 && !pass2)
+ {
+ FILE *f;
+ f = fopen ("loadtest.xml", "r");
+ if (f != 0)
+ {
+ fclose (f);
+ pass1 = false;
+ pass2 = true;
+ }
+ else
+ {
+ pass1 = true;
+ pass2 = false;
+ }
+ }
+ CORBA::Object_var obj =
+ orb->resolve_initial_references("RootPOA" ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ ACE_ASSERT(! CORBA::is_nil (obj.in ()));
+ poa = PortableServer::POA::_narrow(obj.in () ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ ACE_ASSERT(! CORBA::is_nil (poa.in ()));
+ PortableServer::POAManager_var mgr = poa->the_POAManager();
+ mgr->activate();
+
+ if (pass1)
+ {
+ CosNotifyChannelAdmin::EventChannelFactory_var cosecf =
+ TAO_Notify_EventChannelFactory_i::create(poa.in () ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ NotifyExt::EventChannelFactory_var ecf =
+ NotifyExt::EventChannelFactory::_narrow (cosecf.in () ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ if (CORBA::is_nil (ecf.in ()))
+ {
+ return -1;
+ }
+
+ CosNotification::QoSProperties qosprops(7);
+ CORBA::ULong i = 0;
+
+ qosprops.length(7);
+ qosprops[i].name = CORBA::string_dup(CosNotification::EventReliability);
+ qosprops[i++].value <<= CosNotification::Persistent;
+ qosprops[i].name = CORBA::string_dup(CosNotification::ConnectionReliability);
+ qosprops[i++].value <<= CosNotification::Persistent; // Required, or we won't persist much
+ qosprops[i].name = CORBA::string_dup(CosNotification::Priority);
+ qosprops[i++].value <<= CosNotification::HighestPriority;
+ qosprops[i].name = CORBA::string_dup(CosNotification::Timeout);
+ qosprops[i++].value <<= (TimeBase::TimeT) 42000;
+ qosprops[i].name = CORBA::string_dup(CosNotification::StopTimeSupported);
+ qosprops[i++].value <<= CORBA::Any::from_boolean(1);
+ qosprops[i].name = CORBA::string_dup(CosNotification::MaximumBatchSize);
+ qosprops[i++].value <<= (CORBA::Long) 555;
+ qosprops[i].name = CORBA::string_dup(CosNotification::PacingInterval);
+ qosprops[i++].value <<= (TimeBase::TimeT) 34300;
+ qosprops.length(i);
+
+ CosNotification::AdminProperties adminprops(4);
+ adminprops.length(4);
+ i = 0;
+ adminprops[i].name = CORBA::string_dup(CosNotification::MaxQueueLength);
+ adminprops[i++].value <<= (CORBA::Long) 1234;
+ adminprops[i].name = CORBA::string_dup(CosNotification::MaxConsumers);
+ adminprops[i++].value <<= (CORBA::Long) 3;
+ adminprops[i].name = CORBA::string_dup(CosNotification::MaxSuppliers);
+ adminprops[i++].value <<= (CORBA::Long) 3;
+ adminprops[i].name = CORBA::string_dup(CosNotification::RejectNewEvents);
+ adminprops[i++].value <<= CORBA::Any::from_boolean(1);
+ adminprops.length (i);
+
+ CosNotifyChannelAdmin::ChannelID ecid;
+ ::CosNotifyChannelAdmin::EventChannel_var ec =
+ ecf->create_channel(qosprops, adminprops, ecid ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CosNotifyChannelAdmin::AdminID consumer_admin_id;
+ CosNotifyChannelAdmin::ConsumerAdmin_var ca =
+ ec->new_for_consumers(CosNotifyChannelAdmin::OR_OP,
+ consumer_admin_id
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CosNotifyChannelAdmin::AdminID supplier_admin_id;
+ CosNotifyChannelAdmin::SupplierAdmin_var sa =
+ ec->new_for_suppliers(CosNotifyChannelAdmin::OR_OP,
+ supplier_admin_id
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CosNotifyChannelAdmin::ProxyID proxy_id;
+ CosNotifyChannelAdmin::ProxySupplier_var ps =
+ ca->obtain_notification_push_supplier(
+ CosNotifyChannelAdmin::STRUCTURED_EVENT,
+ proxy_id
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CosNotifyChannelAdmin::StructuredProxyPushSupplier_var strps =
+ CosNotifyChannelAdmin::StructuredProxyPushSupplier::_narrow(ps.in());
+
+ ps = ca->obtain_notification_push_supplier(
+ CosNotifyChannelAdmin::SEQUENCE_EVENT,
+ proxy_id
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CosNotifyChannelAdmin::SequenceProxyPushSupplier_var seqps =
+ CosNotifyChannelAdmin::SequenceProxyPushSupplier::_narrow(ps.in());
+
+ ps = ca->obtain_notification_push_supplier(
+ CosNotifyChannelAdmin::ANY_EVENT,
+ proxy_id
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CosNotifyChannelAdmin::ProxyPushSupplier_var anyps =
+ CosNotifyChannelAdmin::ProxyPushSupplier::_narrow(ps.in());
+
+ CosNotifyChannelAdmin::ProxyConsumer_var pc =
+ sa->obtain_notification_push_consumer(
+ CosNotifyChannelAdmin::STRUCTURED_EVENT,
+ proxy_id
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CosNotifyChannelAdmin::StructuredProxyPushConsumer_var strpc = CosNotifyChannelAdmin::StructuredProxyPushConsumer::_narrow(pc.in());
+
+ pc = sa->obtain_notification_push_consumer(
+ CosNotifyChannelAdmin::SEQUENCE_EVENT,
+ proxy_id
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CosNotifyChannelAdmin::SequenceProxyPushConsumer_var seqpc = CosNotifyChannelAdmin::SequenceProxyPushConsumer::_narrow(pc.in());
+
+ pc =
+ sa->obtain_notification_push_consumer(
+ CosNotifyChannelAdmin::ANY_EVENT,
+ proxy_id
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CosNotifyChannelAdmin::ProxyPushConsumer_var anypc = CosNotifyChannelAdmin::ProxyPushConsumer::_narrow(pc.in());
+
+ CosNotifyFilter::FilterFactory_var ff =
+ ec->default_filter_factory (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CosNotifyFilter::Filter_var filter1 =
+ ff->create_filter("EXTENDED_TCL" ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ ACE_ASSERT(! CORBA::is_nil (filter1.in ()));
+
+ CosNotifyFilter::Filter_var filter2 =
+ ff->create_filter("EXTENDED_TCL" ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ ACE_ASSERT(! CORBA::is_nil (filter2.in ()));
+
+ CosNotifyFilter::ConstraintExpSeq constraint_list(1);
+ constraint_list.length(1);
+ constraint_list[0].event_types.length(0);
+ constraint_list[0].constraint_expr = CORBA::string_dup("Number == 100");
+
+ filter1->add_constraints(constraint_list ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ filter2->add_constraints(constraint_list ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ ca->add_filter (filter1.in() ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ sa->add_filter (filter2.in() ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ strps->add_filter (filter1.in() ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ seqps->add_filter (filter2.in() ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ anyps->add_filter (filter1.in() ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ strpc->add_filter (filter2.in() ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ seqpc->add_filter (filter1.in() ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ anypc->add_filter (filter1.in() ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ anypc->add_filter (filter2.in() ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ CosNotification::EventTypeSeq added1(1), removed1(0);
+ added1.length(1);
+ added1[0].domain_name = CORBA::string_dup("nightly_builds");
+ added1[0].type_name = CORBA::string_dup("*");
+ ca->subscription_change(added1, removed1 ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ // Connect a PushConsumer and PushSupplier
+ TestSupplier test_supplier_svt;
+ CosNotifyComm::StructuredPushSupplier_var push_sup = test_supplier_svt._this();
+ TestConsumer test_consumer_svt;
+ CosNotifyComm::StructuredPushConsumer_var push_cons = test_consumer_svt._this();
+ strpc->connect_structured_push_supplier(push_sup.in());
+ strps->connect_structured_push_consumer(push_cons.in());
+
+ strps->suspend_connection();
+
+ ecf->destroy(ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ ////////////////////////////////
+ // TODO make this not hardcoded
+ ACE_OS::rename ("abc.xml", "loadtest.xml");
+
+ } // end of pass 1
+
+ if (pass2)
+ {
+
+ // Create a new ecf, which should load itself from loadtest.xml
+ CosNotifyChannelAdmin::EventChannelFactory_var
+ cosecf = TAO_Notify_EventChannelFactory_i::create(poa.in () ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ ACE_TRY_CHECK;
+ NotifyExt::EventChannelFactory_var
+ ecf = NotifyExt::EventChannelFactory::_narrow (cosecf.in () ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ if (CORBA::is_nil (ecf.in ()))
+ {
+ return -1;
+ }
+
+ // Force a change, which should write out a new abc.xml.
+ ecf->save_topology (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ ecf->destroy(ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+
+ poa->destroy (1, 1 ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (1);
+ orb->destroy (ACE_ENV_SINGLE_ARG_PARAMETER);
+ ACE_CHECK_RETURN (1);
+ poa = PortableServer::POA::_nil ();
+ orb = CORBA::ORB::_nil ();
+ retval = 0;
+ }
+ ACE_CATCHANY
+ {
+ ACE_PRINT_EXCEPTION(ex, "Unexpected exception caught in main. ");
+ retval = -1;
+ }
+ ACE_CATCHALL
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Error : Unknown exception caught in main.") ));
+ retval = -2;
+ }
+ ACE_ENDTRY;
+ return retval;
+}
diff --git a/TAO/orbsvcs/tests/Notify/XML_Persistence/run_test.pl b/TAO/orbsvcs/tests/Notify/XML_Persistence/run_test.pl
new file mode 100755
index 00000000000..6b73d986e0f
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/XML_Persistence/run_test.pl
@@ -0,0 +1,62 @@
+eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
+ & eval 'exec perl -S $0 $argv:q'
+ if 0;
+
+# $Id$
+# -*- perl -*-
+
+# ex
+
+use lib "$ENV{ACE_ROOT}/bin";
+use PerlACE::Run_Test;
+use File::Compare;
+
+$ACE_ROOT = $ENV{ACE_ROOT};
+$TAO_ROOT = "$ACE_ROOT/TAO";
+
+sub cleanup() {
+ unlink "loadtest.xml";
+ unlink "abc.xml";
+ for ($i = 0; $i < 10; ++$i) {
+ unlink "abc.00" . $i;
+ }
+ for ($i = 10; $i < 20; ++$i) {
+ unlink "abc.0" . $i;
+ }
+}
+
+cleanup();
+
+$ret = 0;
+
+$UTEST = new PerlACE::Process("main");
+$ret = $UTEST->SpawnWaitKill(10);
+if ($ret != 0) {
+ print "ERROR : main returned $ret\n";
+ exit $ret;
+}
+
+# NOTE: In TAO 1.3a main ran the notification service twice
+# producing both abc.xml and loadtest.xml. Unfortunately
+# in TAO 1.4 the notification service will does not run
+# successfully the second time in the same EXE.
+# -- todo figure out why and fix it.
+# Thus main was modified to run in two passes. If loadtest.xml
+# exists, it runs pass 2.
+$ret = $UTEST->SpawnWaitKill(10);
+if ($ret != 0) {
+ print "ERROR : main returned $ret\n";
+ exit $ret;
+}
+
+$different = compare("loadtest.xml", "abc.xml");
+if ($different) {
+ print "ERROR : loadtest.xml != abc.xml\n";
+ exit 1;
+} else {
+ print "Success : loadtest.xml == abc.xml\n";
+ cleanup();
+}
+
+
+exit $ret;
diff --git a/TAO/orbsvcs/tests/Notify/XML_Persistence/svc.conf b/TAO/orbsvcs/tests/Notify/XML_Persistence/svc.conf
new file mode 100644
index 00000000000..10b21998a5b
--- /dev/null
+++ b/TAO/orbsvcs/tests/Notify/XML_Persistence/svc.conf
@@ -0,0 +1,2 @@
+static Notify_Default_Event_Manager_Objects_Factory "-MTDispatching -DispatchingThreads 1"
+dynamic Topology_Factory Service_Object* TAO_CosNotification_persist:_make_XML_Topology_Factory() "-save_base_path ./abc -load_base_path ./loadtest -backup_count 2 -no_timestamp"
diff --git a/TAO/orbsvcs/tests/Notify/lib/Periodic_Consumer.cpp b/TAO/orbsvcs/tests/Notify/lib/Periodic_Consumer.cpp
index 66d655dd9b6..efa4eb67f71 100644
--- a/TAO/orbsvcs/tests/Notify/lib/Periodic_Consumer.cpp
+++ b/TAO/orbsvcs/tests/Notify/lib/Periodic_Consumer.cpp
@@ -12,8 +12,8 @@
#include "LookupManager.h"
#include "Priority_Mapping.h"
-ACE_RCSID (RT_Notify,
- TAO_Notify_Tests_Periodic_Consumer,
+ACE_RCSID (RT_Notify,
+ TAO_Notify_Tests_Periodic_Consumer,
"$Id$")
int WARMUP_COUNT = 10;
@@ -234,6 +234,8 @@ TAO_Notify_Tests_Periodic_Consumer::push_structured_event (const CosNotification
// Eat CPU
static CORBA::ULong prime_number = 9619;
+ (void)ACE::gcd (prime_number, prime_number/2 -1);
+
for (CORBA::ULong load = this->load_; load != 0; --load)
ACE::is_prime (prime_number,
2,